diff --git a/.gitignore b/.gitignore index 69393dc33db6..182f1b0039b2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ # Documentation generated by doxygen or from classes.xml doc/_build/ +# Clangd for vim +.clangd/ + # Javascript specific *.bc @@ -15,7 +18,6 @@ cmake-build-debug .gradle local.properties *.iml -.idea .gradletasknamecache project.properties platform/android/java/app/libs/* diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 0a15aabe80b0..ddf00ffd8dc5 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -183,8 +183,9 @@ void EditorSettings::_get_property_list(List *p_list) const { const VariantContainer *v = props.getptr(*k); - if (v->hide_from_editor) + if (v->hide_from_editor) { continue; + } _EVCSort vc; vc.name = *k; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 40e0c3571406..4a760b5aab52 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -88,7 +88,6 @@ Ref EditorSceneImporter::import_animation(const String &p_path, uint3 //and you want to load the resulting file Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); } @@ -185,7 +184,6 @@ String ResourceImporterScene::get_resource_type() const { } bool ResourceImporterScene::get_option_visibility(const String &p_option, const Map &p_options) const { - if (p_option.begins_with("animation/")) { if (p_option != "animation/import" && !bool(p_options["animation/import"])) return false; diff --git a/main/tests/test_basis.cpp b/main/tests/test_basis.cpp index 5904fc386a12..ade146765b82 100644 --- a/main/tests/test_basis.cpp +++ b/main/tests/test_basis.cpp @@ -89,6 +89,7 @@ Basis EulerToBasis(RotOrder mode, const Vector3 &p_rotation) { } Vector3 BasisToEuler(RotOrder mode, const Basis &p_rotation) { + switch (mode) { case EulerXYZ: return p_rotation.get_euler_xyz(); @@ -135,6 +136,7 @@ String get_rot_order_name(RotOrder ro) { } bool test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { + // This test: // 1. Converts the rotation vector from deg to rad. // 2. Converts euler to basis. @@ -316,7 +318,7 @@ void test_euler_conversion() { } MainLoop *test() { - OS::get_singleton()->print("Start euler conversion checks.\n"); + OS::get_singleton()->print("Start euler conversion check.\n"); test_euler_conversion(); return NULL; diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp index a219330c2bdc..de89b1c2906b 100644 --- a/main/tests/test_main.cpp +++ b/main/tests/test_main.cpp @@ -65,6 +65,7 @@ const char **tests_get_names() { "gd_bytecode", "ordered_hash_map", "astar", + "basis", NULL }; @@ -150,6 +151,10 @@ MainLoop *test_main(String p_test, const List &p_args) { return TestAStar::test(); } + if (p_test == "basis") { + return TestBasis::test(); + } + print_line("Unknown test: " + p_test); return NULL; } diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub deleted file mode 100644 index a61bb418bf93..000000000000 --- a/modules/assimp/SCsub +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_assimp = env_modules.Clone() - -# Force bundled version for now, there's no released version of Assimp with -# support for ArmaturePopulate which we use from their master branch. -if True: # env['builtin_assimp']: - thirdparty_dir = "#thirdparty/assimp" - - env_assimp.Prepend(CPPPATH=["#thirdparty/assimp"]) - env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/code"]) - env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/include"]) - - # env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_SINGLETHREADED"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_BOOST_WORKAROUND"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OWN_ZLIB"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_EXPORT"]) - - # Importers we don't need - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3DS_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3MF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AC_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AMF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASE_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASSBIN_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_B3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BLEND_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BVH_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_C4D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COB_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COLLADA_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_CSM_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_DXF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF2_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_HMP_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IFC_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRR_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRRMESH_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWO_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWS_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_M3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD2_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD3_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDC_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDL_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MMD_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MS3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NDO_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NFF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OBJ_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OFF_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OGRE_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OPENGEX_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_PLY_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3BSP_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_RAW_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SIB_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SMD_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STEP_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STL_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_TERRAGEN_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X3D_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_XGL_IMPORTER"]) - env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X_IMPORTER"]) - - if env["platform"] == "windows": - env_assimp.Append(CPPDEFINES=["PLATFORM_WINDOWS"]) - env_assimp.Append(CPPDEFINES=[("PLATFORM", "WINDOWS")]) - elif env["platform"] == "x11": - env_assimp.Append(CPPDEFINES=["PLATFORM_LINUX"]) - env_assimp.Append(CPPDEFINES=[("PLATFORM", "LINUX")]) - elif env["platform"] == "osx": - env_assimp.Append(CPPDEFINES=["PLATFORM_DARWIN"]) - env_assimp.Append(CPPDEFINES=[("PLATFORM", "DARWIN")]) - - env_thirdparty = env_assimp.Clone() - env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp")) - env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp")) - env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp")) - env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp")) - env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp")) - -# Godot's own source files -env_assimp.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp deleted file mode 100644 index 44df268602eb..000000000000 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ /dev/null @@ -1,1517 +0,0 @@ -/*************************************************************************/ -/* editor_scene_importer_assimp.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "editor_scene_importer_assimp.h" -#include "core/io/image_loader.h" -#include "editor/import/resource_importer_scene.h" -#include "import_utils.h" -#include "scene/3d/camera.h" -#include "scene/3d/light.h" -#include "scene/3d/mesh_instance.h" -#include "scene/main/node.h" -#include "scene/resources/material.h" -#include "scene/resources/surface_tool.h" - -#include -#include -#include -#include -#include - -// move into assimp -aiBone *get_bone_by_name(const aiScene *scene, aiString bone_name) { - for (unsigned int mesh_id = 0; mesh_id < scene->mNumMeshes; ++mesh_id) { - aiMesh *mesh = scene->mMeshes[mesh_id]; - - // iterate over all the bones on the mesh for this node only! - for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) { - - aiBone *bone = mesh->mBones[boneIndex]; - if (bone->mName == bone_name) { - printf("matched bone by name: %s\n", bone->mName.C_Str()); - return bone; - } - } - } - - return NULL; -} - -void EditorSceneImporterAssimp::get_extensions(List *r_extensions) const { - - const String import_setting_string = "filesystem/import/open_asset_import/"; - - Map import_format; - { - Vector exts; - exts.push_back("fbx"); - ImportFormat import = { exts, true }; - import_format.insert("fbx", import); - } - for (Map::Element *E = import_format.front(); E; E = E->next()) { - _register_project_setting_import(E->key(), import_setting_string, E->get().extensions, r_extensions, - E->get().is_default); - } -} - -void EditorSceneImporterAssimp::_register_project_setting_import(const String generic, const String import_setting_string, - const Vector &exts, List *r_extensions, - const bool p_enabled) const { - const String use_generic = "use_" + generic; - _GLOBAL_DEF(import_setting_string + use_generic, p_enabled, true); - if (ProjectSettings::get_singleton()->get(import_setting_string + use_generic)) { - for (int32_t i = 0; i < exts.size(); i++) { - r_extensions->push_back(exts[i]); - } - } -} - -uint32_t EditorSceneImporterAssimp::get_import_flags() const { - return IMPORT_SCENE; -} - -void EditorSceneImporterAssimp::_bind_methods() { -} - -Node *EditorSceneImporterAssimp::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, - List *r_missing_deps, Error *r_err) { - Assimp::Importer importer; - importer.SetPropertyBool(AI_CONFIG_PP_FD_REMOVE, true); - // Cannot remove pivot points because the static mesh will be in the wrong place - importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false); - int32_t max_bone_weights = 4; - //if (p_flags & IMPORT_ANIMATION_EIGHT_WEIGHTS) { - // const int eight_bones = 8; - // importer.SetPropertyBool(AI_CONFIG_PP_LBW_MAX_WEIGHTS, eight_bones); - // max_bone_weights = eight_bones; - //} - - importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT); - - //importer.SetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD, 1.0f); - int32_t post_process_Steps = aiProcess_CalcTangentSpace | - aiProcess_GlobalScale | - // imports models and listens to their file scale for CM to M conversions - //aiProcess_FlipUVs | - aiProcess_FlipWindingOrder | - // very important for culling so that it is done in the correct order. - //aiProcess_DropNormals | - //aiProcess_GenSmoothNormals | - //aiProcess_JoinIdenticalVertices | - aiProcess_ImproveCacheLocality | - //aiProcess_RemoveRedundantMaterials | // Causes a crash - //aiProcess_SplitLargeMeshes | - aiProcess_Triangulate | - aiProcess_GenUVCoords | - //aiProcess_FindDegenerates | - //aiProcess_SortByPType | - // aiProcess_FindInvalidData | - aiProcess_TransformUVCoords | - aiProcess_FindInstances | - //aiProcess_FixInfacingNormals | - //aiProcess_ValidateDataStructure | - aiProcess_OptimizeMeshes | - aiProcess_PopulateArmatureData | - //aiProcess_OptimizeGraph | - //aiProcess_Debone | - // aiProcess_EmbedTextures | - //aiProcess_SplitByBoneCount | - 0; - String g_path = ProjectSettings::get_singleton()->globalize_path(p_path); - aiScene *scene = (aiScene *)importer.ReadFile(g_path.utf8().ptr(), post_process_Steps); - - ERR_FAIL_COND_V_MSG(scene == NULL, NULL, String("Open Asset Import failed to open: ") + String(importer.GetErrorString())); - - return _generate_scene(p_path, scene, p_flags, p_bake_fps, max_bone_weights); -} - -template -struct EditorSceneImporterAssetImportInterpolate { - - T lerp(const T &a, const T &b, float c) const { - - return a + (b - a) * c; - } - - T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { - - float t2 = t * t; - float t3 = t2 * t; - - return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); - } - - T bezier(T start, T control_1, T control_2, T end, float t) { - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; - } -}; - -//thank you for existing, partial specialization -template <> -struct EditorSceneImporterAssetImportInterpolate { - - Quat lerp(const Quat &a, const Quat &b, float c) const { - ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized."); - ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized."); - - return a.slerp(b, c).normalized(); - } - - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) { - ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized."); - ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized."); - - return p1.slerp(p2, c).normalized(); - } - - Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) { - ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized."); - - return start.slerp(end, t).normalized(); - } -}; - -template -T EditorSceneImporterAssimp::_interpolate_track(const Vector &p_times, const Vector &p_values, float p_time, - AssetImportAnimation::Interpolation p_interp) { - //could use binary search, worth it? - int idx = -1; - for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) - break; - idx++; - } - - EditorSceneImporterAssetImportInterpolate interp; - - switch (p_interp) { - case AssetImportAnimation::INTERP_LINEAR: { - - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.lerp(p_values[idx], p_values[idx + 1], c); - - } break; - case AssetImportAnimation::INTERP_STEP: { - - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - return p_values[idx]; - - } break; - case AssetImportAnimation::INTERP_CATMULLROMSPLINE: { - - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[1 + p_times.size() - 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); - - } break; - case AssetImportAnimation::INTERP_CUBIC_SPLINE: { - - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[(p_times.size() - 1) * 3 + 1]; - } - - float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - T from = p_values[idx * 3 + 1]; - T c1 = from + p_values[idx * 3 + 2]; - T to = p_values[idx * 3 + 4]; - T c2 = to + p_values[idx * 3 + 3]; - - return interp.bezier(from, c1, c2, to, c); - - } break; - } - - ERR_FAIL_V(p_values[0]); -} - -aiBone *EditorSceneImporterAssimp::get_bone_from_stack(ImportState &state, aiString name) { - List::Element *iter; - aiBone *bone = NULL; - for (iter = state.bone_stack.front(); iter; iter = iter->next()) { - bone = (aiBone *)iter->get(); - - if (bone && bone->mName == name) { - state.bone_stack.erase(bone); - return bone; - } - } - - return NULL; -} - -Spatial * -EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, - const int32_t p_max_bone_weights) { - ERR_FAIL_COND_V(scene == NULL, NULL); - - ImportState state; - state.path = p_path; - state.assimp_scene = scene; - state.max_bone_weights = p_max_bone_weights; - state.animation_player = NULL; - state.import_flags = p_flags; - - // populate light map - for (unsigned int l = 0; l < scene->mNumLights; l++) { - - aiLight *ai_light = scene->mLights[l]; - ERR_CONTINUE(ai_light == NULL); - state.light_cache[AssimpUtils::get_assimp_string(ai_light->mName)] = l; - } - - // fill camera cache - for (unsigned int c = 0; c < scene->mNumCameras; c++) { - aiCamera *ai_camera = scene->mCameras[c]; - ERR_CONTINUE(ai_camera == NULL); - state.camera_cache[AssimpUtils::get_assimp_string(ai_camera->mName)] = c; - } - - if (scene->mRootNode) { - state.nodes.push_back(scene->mRootNode); - - // make flat node tree - in order to make processing deterministic - for (unsigned int i = 0; i < scene->mRootNode->mNumChildren; i++) { - _generate_node(state, scene->mRootNode->mChildren[i]); - } - - RegenerateBoneStack(state); - - Node *last_valid_parent = NULL; - - List::Element *iter; - for (iter = state.nodes.front(); iter; iter = iter->next()) { - const aiNode *element_assimp_node = iter->get(); - const aiNode *parent_assimp_node = element_assimp_node->mParent; - - String node_name = AssimpUtils::get_assimp_string(element_assimp_node->mName); - //print_verbose("node: " + node_name); - - Spatial *spatial = NULL; - Transform transform = AssimpUtils::assimp_matrix_transform(element_assimp_node->mTransformation); - - // retrieve this node bone - aiBone *bone = get_bone_from_stack(state, element_assimp_node->mName); - - if (state.light_cache.has(node_name)) { - spatial = create_light(state, node_name, transform); - } else if (state.camera_cache.has(node_name)) { - spatial = create_camera(state, node_name, transform); - } else if (state.armature_nodes.find(element_assimp_node)) { - // create skeleton - print_verbose("Making skeleton: " + node_name); - Skeleton *skeleton = memnew(Skeleton); - spatial = skeleton; - if (!state.armature_skeletons.has(element_assimp_node)) { - state.armature_skeletons.insert(element_assimp_node, skeleton); - } - } else if (bone != NULL) { - continue; - } else { - spatial = memnew(Spatial); - } - - ERR_CONTINUE_MSG(spatial == NULL, "FBX Import - are we out of ram?"); - // we on purpose set the transform and name after creating the node. - - spatial->set_name(node_name); - spatial->set_global_transform(transform); - - // first element is root - if (iter == state.nodes.front()) { - state.root = spatial; - } - - // flat node map parent lookup tool - state.flat_node_map.insert(element_assimp_node, spatial); - - Map::Element *parent_lookup = state.flat_node_map.find(parent_assimp_node); - - // note: this always fails on the root node :) keep that in mind this is by design - if (parent_lookup) { - Spatial *parent_node = parent_lookup->value(); - - ERR_FAIL_COND_V_MSG(parent_node == NULL, state.root, - "Parent node invalid even though lookup successful, out of ram?") - - if (spatial != state.root) { - parent_node->add_child(spatial); - spatial->set_owner(state.root); - } else { - // required - think about it root never has a parent yet is valid, anything else without a parent is not valid. - } - } else if (spatial != state.root) { - // if the ainode is not in the tree - // parent it to the last good parent found - if (last_valid_parent) { - last_valid_parent->add_child(spatial); - spatial->set_owner(state.root); - } else { - // this is a serious error? - memdelete(spatial); - } - } - - // update last valid parent - last_valid_parent = spatial; - } - print_verbose("node counts: " + itos(state.nodes.size())); - - // make clean bone stack - RegenerateBoneStack(state); - - print_verbose("generating godot bone data"); - - print_verbose("Godot bone stack count: " + itos(state.bone_stack.size())); - - // This is a list of bones, duplicates are from other meshes and must be dealt with properly - for (List::Element *element = state.bone_stack.front(); element; element = element->next()) { - aiBone *bone = element->get(); - - ERR_CONTINUE_MSG(!bone, "invalid bone read from assimp?"); - - // Utilities for armature lookup - for now only FBX makes these - aiNode *armature_for_bone = bone->mArmature; - - // Utilities for bone node lookup - for now only FBX makes these - aiNode *bone_node = bone->mNode; - aiNode *parent_node = bone_node->mParent; - - String bone_name = AssimpUtils::get_anim_string_from_assimp(bone->mName); - ERR_CONTINUE_MSG(armature_for_bone == NULL, "Armature for bone invalid: " + bone_name); - Skeleton *skeleton = state.armature_skeletons[armature_for_bone]; - - state.skeleton_bone_map[bone] = skeleton; - - if (bone_name.empty()) { - bone_name = "untitled_bone_name"; - WARN_PRINT("Untitled bone name detected... report with file please"); - } - - // todo: this is where skin support goes - if (skeleton && skeleton->find_bone(bone_name) == -1) { - print_verbose("[Godot Glue] Imported bone" + bone_name); - int boneIdx = skeleton->get_bone_count(); - - Transform pform = AssimpUtils::assimp_matrix_transform(bone->mNode->mTransformation); - skeleton->add_bone(bone_name); - skeleton->set_bone_rest(boneIdx, pform); - skeleton->set_bone_pose(boneIdx, pform); - - if (parent_node != NULL) { - int parent_bone_id = skeleton->find_bone(AssimpUtils::get_anim_string_from_assimp(parent_node->mName)); - int current_bone_id = boneIdx; - skeleton->set_bone_parent(current_bone_id, parent_bone_id); - } - } - } - - print_verbose("generating mesh phase from skeletal mesh"); - - List cleanup_template_nodes; - - for (Map::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) { - const aiNode *assimp_node = key_value_pair->key(); - Spatial *mesh_template = key_value_pair->value(); - - ERR_CONTINUE(assimp_node == NULL); - ERR_CONTINUE(mesh_template == NULL); - - Node *parent_node = mesh_template->get_parent(); - - if (mesh_template == state.root) { - continue; - } - - if (parent_node == NULL) { - print_error("Found invalid parent node!"); - continue; // root node - } - - String node_name = AssimpUtils::get_assimp_string(assimp_node->mName); - Transform node_transform = AssimpUtils::assimp_matrix_transform(assimp_node->mTransformation); - - if (assimp_node->mNumMeshes > 0) { - MeshInstance *mesh = create_mesh(state, assimp_node, node_name, parent_node, node_transform); - if (mesh) { - - parent_node->remove_child(mesh_template); - - // re-parent children - List children; - // re-parent all children to new node - // note: since get_child_count will change during execution we must build a list first to be safe. - for (int childId = 0; childId < mesh_template->get_child_count(); childId++) { - // get child - Node *child = mesh_template->get_child(childId); - children.push_back(child); - } - - for (List::Element *element = children.front(); element; element = element->next()) { - // reparent the children to the real mesh node. - mesh_template->remove_child(element->get()); - mesh->add_child(element->get()); - element->get()->set_owner(state.root); - } - - // update mesh in list so that each mesh node is available - // this makes the template unavailable which is the desired behaviour - state.flat_node_map[assimp_node] = mesh; - - cleanup_template_nodes.push_back(mesh_template); - - // clean up this list we don't need it - children.clear(); - } - } - } - - for (List::Element *element = cleanup_template_nodes.front(); element; element = element->next()) { - if (element->get()) { - memdelete(element->get()); - } - } - } - - if (p_flags & IMPORT_ANIMATION && scene->mNumAnimations) { - - state.animation_player = memnew(AnimationPlayer); - state.root->add_child(state.animation_player); - state.animation_player->set_owner(state.root); - - for (uint32_t i = 0; i < scene->mNumAnimations; i++) { - _import_animation(state, i, p_bake_fps); - } - } - - // - // Cleanup operations - // - - state.mesh_cache.clear(); - state.material_cache.clear(); - state.light_cache.clear(); - state.camera_cache.clear(); - state.assimp_node_map.clear(); - state.path_to_image_cache.clear(); - state.nodes.clear(); - state.flat_node_map.clear(); - state.armature_skeletons.clear(); - state.bone_stack.clear(); - return state.root; -} - -void EditorSceneImporterAssimp::_insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id, - int anim_fps, Ref animation, float ticks_per_second, - Skeleton *skeleton, const NodePath &node_path, - const String &node_name, aiBone *track_bone) { - const aiNodeAnim *assimp_track = assimp_anim->mChannels[track_id]; - //make transform track - int track_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_TRANSFORM); - animation->track_set_path(track_idx, node_path); - //first determine animation length - - float increment = 1.0 / float(anim_fps); - float time = 0.0; - - bool last = false; - - Vector pos_values; - Vector pos_times; - Vector scale_values; - Vector scale_times; - Vector rot_values; - Vector rot_times; - - for (size_t p = 0; p < assimp_track->mNumPositionKeys; p++) { - aiVector3D pos = assimp_track->mPositionKeys[p].mValue; - pos_values.push_back(Vector3(pos.x, pos.y, pos.z)); - pos_times.push_back(assimp_track->mPositionKeys[p].mTime / ticks_per_second); - } - - for (size_t r = 0; r < assimp_track->mNumRotationKeys; r++) { - aiQuaternion quat = assimp_track->mRotationKeys[r].mValue; - rot_values.push_back(Quat(quat.x, quat.y, quat.z, quat.w).normalized()); - rot_times.push_back(assimp_track->mRotationKeys[r].mTime / ticks_per_second); - } - - for (size_t sc = 0; sc < assimp_track->mNumScalingKeys; sc++) { - aiVector3D scale = assimp_track->mScalingKeys[sc].mValue; - scale_values.push_back(Vector3(scale.x, scale.y, scale.z)); - scale_times.push_back(assimp_track->mScalingKeys[sc].mTime / ticks_per_second); - } - - while (true) { - Vector3 pos; - Quat rot; - Vector3 scale(1, 1, 1); - - if (pos_values.size()) { - pos = _interpolate_track(pos_times, pos_values, time, AssetImportAnimation::INTERP_LINEAR); - } - - if (rot_values.size()) { - rot = _interpolate_track(rot_times, rot_values, time, - AssetImportAnimation::INTERP_LINEAR) - .normalized(); - } - - if (scale_values.size()) { - scale = _interpolate_track(scale_times, scale_values, time, AssetImportAnimation::INTERP_LINEAR); - } - - if (skeleton) { - int skeleton_bone = skeleton->find_bone(node_name); - - if (skeleton_bone >= 0 && track_bone) { - - Transform xform; - xform.basis.set_quat_scale(rot, scale); - xform.origin = pos; - - xform = skeleton->get_bone_pose(skeleton_bone).inverse() * xform; - - rot = xform.basis.get_rotation_quat(); - rot.normalize(); - scale = xform.basis.get_scale(); - pos = xform.origin; - } else { - ERR_FAIL_MSG("Skeleton bone lookup failed for skeleton: " + skeleton->get_name()); - } - } - - animation->track_set_interpolation_type(track_idx, Animation::INTERPOLATION_LINEAR); - animation->transform_track_insert_key(track_idx, time, pos, rot, scale); - - if (last) { //done this way so a key is always inserted past the end (for proper interpolation) - break; - } - time += increment; - if (time >= animation->get_length()) { - last = true; - } - } -} - -// I really do not like this but need to figure out a better way of removing it later. -Node *EditorSceneImporterAssimp::get_node_by_name(ImportState &state, String name) { - for (Map::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) { - const aiNode *assimp_node = key_value_pair->key(); - Spatial *node = key_value_pair->value(); - - String node_name = AssimpUtils::get_assimp_string(assimp_node->mName); - if (name == node_name && node) { - return node; - } - } - return NULL; -} - -/* Bone stack is a fifo handler for multiple armatures since armatures aren't a thing in assimp (yet) */ -void EditorSceneImporterAssimp::RegenerateBoneStack(ImportState &state) { - - state.bone_stack.clear(); - // build bone stack list - for (unsigned int mesh_id = 0; mesh_id < state.assimp_scene->mNumMeshes; ++mesh_id) { - aiMesh *mesh = state.assimp_scene->mMeshes[mesh_id]; - - // iterate over all the bones on the mesh for this node only! - for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) { - aiBone *bone = mesh->mBones[boneIndex]; - - // doubtful this is required right now but best to check - if (!state.bone_stack.find(bone)) { - //print_verbose("[assimp] bone stack added: " + String(bone->mName.C_Str()) ); - state.bone_stack.push_back(bone); - } - } - } -} - -/* Bone stack is a fifo handler for multiple armatures since armatures aren't a thing in assimp (yet) */ -void EditorSceneImporterAssimp::RegenerateBoneStack(ImportState &state, aiMesh *mesh) { - state.bone_stack.clear(); - // iterate over all the bones on the mesh for this node only! - for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) { - aiBone *bone = mesh->mBones[boneIndex]; - if (state.bone_stack.find(bone) == NULL) { - state.bone_stack.push_back(bone); - } - } -} - -// animation tracks are per bone - -void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_animation_index, int p_bake_fps) { - - ERR_FAIL_INDEX(p_animation_index, (int)state.assimp_scene->mNumAnimations); - - const aiAnimation *anim = state.assimp_scene->mAnimations[p_animation_index]; - String name = AssimpUtils::get_anim_string_from_assimp(anim->mName); - if (name == String()) { - name = "Animation " + itos(p_animation_index + 1); - } - print_verbose("import animation: " + name); - float ticks_per_second = anim->mTicksPerSecond; - - if (state.assimp_scene->mMetaData != NULL && Math::is_equal_approx(ticks_per_second, 0.0f)) { - int32_t time_mode = 0; - state.assimp_scene->mMetaData->Get("TimeMode", time_mode); - ticks_per_second = AssimpUtils::get_fbx_fps(time_mode, state.assimp_scene); - } - - //? - //if ((p_path.get_file().get_extension().to_lower() == "glb" || p_path.get_file().get_extension().to_lower() == "gltf") && Math::is_equal_approx(ticks_per_second, 0.0f)) { - // ticks_per_second = 1000.0f; - //} - - if (Math::is_equal_approx(ticks_per_second, 0.0f)) { - ticks_per_second = 25.0f; - } - - Ref animation; - animation.instance(); - animation->set_name(name); - animation->set_length(anim->mDuration / ticks_per_second); - - if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { - animation->set_loop(true); - } - - // generate bone stack for animation import - RegenerateBoneStack(state); - - //regular tracks - for (size_t i = 0; i < anim->mNumChannels; i++) { - const aiNodeAnim *track = anim->mChannels[i]; - String node_name = AssimpUtils::get_assimp_string(track->mNodeName); - print_verbose("track name import: " + node_name); - if (track->mNumRotationKeys == 0 && track->mNumPositionKeys == 0 && track->mNumScalingKeys == 0) { - continue; //do not bother - } - - Skeleton *skeleton = NULL; - NodePath node_path; - aiBone *bone = NULL; - - // Import skeleton bone animation for this track - // Any bone will do, no point in processing more than just what is in the skeleton - { - bone = get_bone_from_stack(state, track->mNodeName); - - if (bone) { - // get skeleton by bone - skeleton = state.armature_skeletons[bone->mArmature]; - - if (skeleton) { - String path = state.root->get_path_to(skeleton); - path += ":" + node_name; - node_path = path; - - if (node_path != NodePath()) { - _insert_animation_track(state, anim, i, p_bake_fps, animation, ticks_per_second, skeleton, - node_path, node_name, bone); - } else { - print_error("Failed to find valid node path for animation"); - } - } - } - } - - // not a bone - // note this is flaky it uses node names which is unreliable - Node *allocated_node = get_node_by_name(state, node_name); - // todo: implement skeleton grabbing for node based animations too :) - // check if node exists, if it does then also apply animation track for node and bones above are all handled. - // this is now inclusive animation handling so that - // we import all the data and do not miss anything. - if (allocated_node) { - node_path = state.root->get_path_to(allocated_node); - - if (node_path != NodePath()) { - _insert_animation_track(state, anim, i, p_bake_fps, animation, ticks_per_second, skeleton, - node_path, node_name, nullptr); - } - } - } - - //blend shape tracks - - for (size_t i = 0; i < anim->mNumMorphMeshChannels; i++) { - - const aiMeshMorphAnim *anim_mesh = anim->mMorphMeshChannels[i]; - - const String prop_name = AssimpUtils::get_assimp_string(anim_mesh->mName); - const String mesh_name = prop_name.split("*")[0]; - - ERR_CONTINUE(prop_name.split("*").size() != 2); - - Node *item = get_node_by_name(state, mesh_name); - ERR_CONTINUE_MSG(!item, "failed to look up node by name"); - const MeshInstance *mesh_instance = Object::cast_to(item); - ERR_CONTINUE(mesh_instance == NULL); - - String base_path = state.root->get_path_to(mesh_instance); - - Ref mesh = mesh_instance->get_mesh(); - ERR_CONTINUE(mesh.is_null()); - - //add the tracks for this mesh - int base_track = animation->get_track_count(); - for (int j = 0; j < mesh->get_blend_shape_count(); j++) { - - animation->add_track(Animation::TYPE_VALUE); - animation->track_set_path(base_track + j, base_path + ":blend_shapes/" + mesh->get_blend_shape_name(j)); - } - - for (size_t k = 0; k < anim_mesh->mNumKeys; k++) { - for (size_t j = 0; j < anim_mesh->mKeys[k].mNumValuesAndWeights; j++) { - - float t = anim_mesh->mKeys[k].mTime / ticks_per_second; - float w = anim_mesh->mKeys[k].mWeights[j]; - - animation->track_insert_key(base_track + j, t, w); - } - } - } - - if (animation->get_track_count()) { - state.animation_player->add_animation(name, animation); - } -} -// -// Mesh Generation from indices ? why do we need so much mesh code -// [debt needs looked into] -Ref -EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &state, const Vector &p_surface_indices, - const aiNode *assimp_node, Ref &skin, - Skeleton *&skeleton_assigned) { - - Ref mesh; - mesh.instance(); - bool has_uvs = false; - bool compress_vert_data = state.import_flags & IMPORT_USE_COMPRESSION; - uint32_t mesh_flags = compress_vert_data ? Mesh::ARRAY_COMPRESS_DEFAULT : 0; - - Map morph_mesh_string_lookup; - - for (int i = 0; i < p_surface_indices.size(); i++) { - const unsigned int mesh_idx = p_surface_indices[0]; - const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_idx]; - for (size_t j = 0; j < ai_mesh->mNumAnimMeshes; j++) { - String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName); - if (!morph_mesh_string_lookup.has(ai_anim_mesh_name)) { - morph_mesh_string_lookup.insert(ai_anim_mesh_name, j); - mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); - if (ai_anim_mesh_name.empty()) { - ai_anim_mesh_name = String("morph_") + itos(j); - } - mesh->add_blend_shape(ai_anim_mesh_name); - } - } - } - // - // Process Vertex Weights - // - for (int i = 0; i < p_surface_indices.size(); i++) { - const unsigned int mesh_idx = p_surface_indices[i]; - const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_idx]; - - Map > vertex_weights; - - if (ai_mesh->mNumBones > 0) { - for (size_t b = 0; b < ai_mesh->mNumBones; b++) { - aiBone *bone = ai_mesh->mBones[b]; - - if (!skeleton_assigned) { - print_verbose("Assigned mesh skeleton during mesh creation"); - skeleton_assigned = state.skeleton_bone_map[bone]; - - if (!skin.is_valid()) { - print_verbose("Configured new skin"); - skin.instance(); - } else { - print_verbose("Reusing existing skin!"); - } - } - // skeleton_assigned = - String bone_name = AssimpUtils::get_assimp_string(bone->mName); - int bone_index = skeleton_assigned->find_bone(bone_name); - ERR_CONTINUE(bone_index == -1); - for (size_t w = 0; w < bone->mNumWeights; w++) { - - aiVertexWeight ai_weights = bone->mWeights[w]; - - BoneInfo bi; - uint32_t vertex_index = ai_weights.mVertexId; - bi.bone = bone_index; - bi.weight = ai_weights.mWeight; - - if (!vertex_weights.has(vertex_index)) { - vertex_weights[vertex_index] = Vector(); - } - - vertex_weights[vertex_index].push_back(bi); - } - } - } - - // - // Create mesh from data from assimp - // - - Ref st; - st.instance(); - st->begin(Mesh::PRIMITIVE_TRIANGLES); - - for (size_t j = 0; j < ai_mesh->mNumVertices; j++) { - - // Get the texture coordinates if they exist - if (ai_mesh->HasTextureCoords(0)) { - has_uvs = true; - st->add_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y)); - } - - if (ai_mesh->HasTextureCoords(1)) { - has_uvs = true; - st->add_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y)); - } - - // Assign vertex colors - if (ai_mesh->HasVertexColors(0)) { - Color color = Color(ai_mesh->mColors[0]->r, ai_mesh->mColors[0]->g, ai_mesh->mColors[0]->b, - ai_mesh->mColors[0]->a); - st->add_color(color); - } - - // Work out normal calculations? - this needs work it doesn't work properly on huestos - if (ai_mesh->mNormals != NULL) { - const aiVector3D normals = ai_mesh->mNormals[j]; - const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z); - st->add_normal(godot_normal); - if (ai_mesh->HasTangentsAndBitangents()) { - const aiVector3D tangents = ai_mesh->mTangents[j]; - const Vector3 godot_tangent = Vector3(tangents.x, tangents.y, tangents.z); - const aiVector3D bitangent = ai_mesh->mBitangents[j]; - const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z); - float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f; - st->add_tangent(Plane(tangents.x, tangents.y, tangents.z, d)); - } - } - - // We have vertex weights right? - if (vertex_weights.has(j)) { - - Vector bone_info = vertex_weights[j]; - Vector bones; - bones.resize(bone_info.size()); - Vector weights; - weights.resize(bone_info.size()); - - // todo? do we really need to loop over all bones? - assimp may have helper to find all influences on this vertex. - for (int k = 0; k < bone_info.size(); k++) { - bones.write[k] = bone_info[k].bone; - weights.write[k] = bone_info[k].weight; - } - - st->add_bones(bones); - st->add_weights(weights); - } - - // Assign vertex - const aiVector3D pos = ai_mesh->mVertices[j]; - - // note we must include node offset transform as this is relative to world space not local space. - Vector3 godot_pos = Vector3(pos.x, pos.y, pos.z); - st->add_vertex(godot_pos); - } - - // fire replacement for face handling - for (size_t j = 0; j < ai_mesh->mNumFaces; j++) { - const aiFace face = ai_mesh->mFaces[j]; - for (unsigned int k = 0; k < face.mNumIndices; k++) { - st->add_index(face.mIndices[k]); - } - } - - if (ai_mesh->HasTangentsAndBitangents() == false && has_uvs) { - st->generate_tangents(); - } - - aiMaterial *ai_material = state.assimp_scene->mMaterials[ai_mesh->mMaterialIndex]; - Ref mat; - mat.instance(); - - int32_t mat_two_sided = 0; - if (AI_SUCCESS == ai_material->Get(AI_MATKEY_TWOSIDED, mat_two_sided)) { - if (mat_two_sided > 0) { - mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); - } else { - mat->set_cull_mode(SpatialMaterial::CULL_BACK); - } - } - - aiString mat_name; - if (AI_SUCCESS == ai_material->Get(AI_MATKEY_NAME, mat_name)) { - mat->set_name(AssimpUtils::get_assimp_string(mat_name)); - } - - // Culling handling for meshes - - // cull all back faces - mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); - - // Now process materials - aiTextureType base_color = aiTextureType_BASE_COLOR; - { - String filename, path; - AssimpImageData image_data; - - if (AssimpUtils::GetAssimpTexture(state, ai_material, base_color, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - - // anything transparent must be culled - if (image_data.raw_image->detect_alpha() != Image::ALPHA_NONE) { - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS); - mat->set_cull_mode( - SpatialMaterial::CULL_DISABLED); // since you can see both sides in transparent mode - } - - mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, image_data.texture); - } - } - - aiTextureType tex_diffuse = aiTextureType_DIFFUSE; - { - String filename, path; - AssimpImageData image_data; - - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_diffuse, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - - // anything transparent must be culled - if (image_data.raw_image->detect_alpha() != Image::ALPHA_NONE) { - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS); - mat->set_cull_mode( - SpatialMaterial::CULL_DISABLED); // since you can see both sides in transparent mode - } - - mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, image_data.texture); - } - - aiColor4D clr_diffuse; - if (AI_SUCCESS == ai_material->Get(AI_MATKEY_COLOR_DIFFUSE, clr_diffuse)) { - if (Math::is_equal_approx(clr_diffuse.a, 1.0f) == false) { - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS); - mat->set_cull_mode( - SpatialMaterial::CULL_DISABLED); // since you can see both sides in transparent mode - } - mat->set_albedo(Color(clr_diffuse.r, clr_diffuse.g, clr_diffuse.b, clr_diffuse.a)); - } - } - - aiTextureType tex_normal = aiTextureType_NORMALS; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_normal, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true); - mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, image_data.texture); - } else { - aiString texture_path; - if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_NORMAL_TEXTURE, AI_PROPERTIES, texture_path)) { - if (AssimpUtils::CreateAssimpTexture(state, texture_path, filename, path, image_data)) { - mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true); - mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, image_data.texture); - } - } - } - } - - aiTextureType tex_normal_camera = aiTextureType_NORMAL_CAMERA; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_normal_camera, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true); - mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, image_data.texture); - } - } - - aiTextureType tex_emission_color = aiTextureType_EMISSION_COLOR; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_emission_color, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true); - mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, image_data.texture); - } - } - - aiTextureType tex_metalness = aiTextureType_METALNESS; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_metalness, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_texture(SpatialMaterial::TEXTURE_METALLIC, image_data.texture); - } - } - - aiTextureType tex_roughness = aiTextureType_DIFFUSE_ROUGHNESS; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_roughness, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, image_data.texture); - } - } - - aiTextureType tex_emissive = aiTextureType_EMISSIVE; - { - String filename = ""; - String path = ""; - Ref texture; - AssimpImageData image_data; - - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_emissive, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_feature(SpatialMaterial::FEATURE_EMISSION, true); - mat->set_texture(SpatialMaterial::TEXTURE_EMISSION, image_data.texture); - } else { - // Process emission textures - aiString texture_emissive_path; - if (AI_SUCCESS == - ai_material->Get(AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE, AI_PROPERTIES, texture_emissive_path)) { - if (AssimpUtils::CreateAssimpTexture(state, texture_emissive_path, filename, path, image_data)) { - mat->set_feature(SpatialMaterial::FEATURE_EMISSION, true); - mat->set_texture(SpatialMaterial::TEXTURE_EMISSION, image_data.texture); - } - } else { - float pbr_emission = 0.0f; - if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR, AI_NULL, pbr_emission)) { - mat->set_emission(Color(pbr_emission, pbr_emission, pbr_emission, 1.0f)); - } - } - } - } - - aiTextureType tex_specular = aiTextureType_SPECULAR; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_specular, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_texture(SpatialMaterial::TEXTURE_METALLIC, image_data.texture); - } - } - - aiTextureType tex_ao_map = aiTextureType_AMBIENT_OCCLUSION; - { - String filename, path; - Ref texture; - AssimpImageData image_data; - - // Process texture normal map - if (AssimpUtils::GetAssimpTexture(state, ai_material, tex_ao_map, filename, path, image_data)) { - AssimpUtils::set_texture_mapping_mode(image_data.map_mode, image_data.texture); - mat->set_feature(SpatialMaterial::FEATURE_AMBIENT_OCCLUSION, true); - mat->set_texture(SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION, image_data.texture); - } - } - - Array array_mesh = st->commit_to_arrays(); - Array morphs; - morphs.resize(ai_mesh->mNumAnimMeshes); - Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES; - - for (size_t j = 0; j < ai_mesh->mNumAnimMeshes; j++) { - - String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName); - - if (ai_anim_mesh_name.empty()) { - ai_anim_mesh_name = String("morph_") + itos(j); - } - - Array array_copy; - array_copy.resize(VisualServer::ARRAY_MAX); - - for (int l = 0; l < VisualServer::ARRAY_MAX; l++) { - array_copy[l] = array_mesh[l].duplicate(true); - } - - const size_t num_vertices = ai_mesh->mAnimMeshes[j]->mNumVertices; - array_copy[Mesh::ARRAY_INDEX] = Variant(); - if (ai_mesh->mAnimMeshes[j]->HasPositions()) { - PoolVector3Array vertices; - vertices.resize(num_vertices); - for (size_t l = 0; l < num_vertices; l++) { - const aiVector3D ai_pos = ai_mesh->mAnimMeshes[j]->mVertices[l]; - Vector3 position = Vector3(ai_pos.x, ai_pos.y, ai_pos.z); - vertices.write()[l] = position; - } - PoolVector3Array new_vertices = array_copy[VisualServer::ARRAY_VERTEX].duplicate(true); - ERR_CONTINUE(vertices.size() != new_vertices.size()); - for (int32_t l = 0; l < new_vertices.size(); l++) { - PoolVector3Array::Write w = new_vertices.write(); - w[l] = vertices[l]; - } - array_copy[VisualServer::ARRAY_VERTEX] = new_vertices; - } - - int32_t color_set = 0; - if (ai_mesh->mAnimMeshes[j]->HasVertexColors(color_set)) { - PoolColorArray colors; - colors.resize(num_vertices); - for (size_t l = 0; l < num_vertices; l++) { - const aiColor4D ai_color = ai_mesh->mAnimMeshes[j]->mColors[color_set][l]; - Color color = Color(ai_color.r, ai_color.g, ai_color.b, ai_color.a); - colors.write()[l] = color; - } - PoolColorArray new_colors = array_copy[VisualServer::ARRAY_COLOR].duplicate(true); - ERR_CONTINUE(colors.size() != new_colors.size()); - for (int32_t l = 0; l < colors.size(); l++) { - PoolColorArray::Write w = new_colors.write(); - w[l] = colors[l]; - } - array_copy[VisualServer::ARRAY_COLOR] = new_colors; - } - - if (ai_mesh->mAnimMeshes[j]->HasNormals()) { - PoolVector3Array normals; - normals.resize(num_vertices); - for (size_t l = 0; l < num_vertices; l++) { - const aiVector3D ai_normal = ai_mesh->mAnimMeshes[j]->mNormals[l]; - Vector3 normal = Vector3(ai_normal.x, ai_normal.y, ai_normal.z); - normals.write()[l] = normal; - } - PoolVector3Array new_normals = array_copy[VisualServer::ARRAY_NORMAL].duplicate(true); - ERR_CONTINUE(normals.size() != new_normals.size()); - for (int l = 0; l < normals.size(); l++) { - PoolVector3Array::Write w = new_normals.write(); - w[l] = normals[l]; - } - array_copy[VisualServer::ARRAY_NORMAL] = new_normals; - } - - if (ai_mesh->mAnimMeshes[j]->HasTangentsAndBitangents()) { - PoolColorArray tangents; - tangents.resize(num_vertices); - PoolColorArray::Write w = tangents.write(); - for (size_t l = 0; l < num_vertices; l++) { - AssimpUtils::calc_tangent_from_mesh(ai_mesh, j, l, l, w); - } - PoolRealArray new_tangents = array_copy[VisualServer::ARRAY_TANGENT].duplicate(true); - ERR_CONTINUE(new_tangents.size() != tangents.size() * 4); - for (int32_t l = 0; l < tangents.size(); l++) { - new_tangents.write()[l + 0] = tangents[l].r; - new_tangents.write()[l + 1] = tangents[l].g; - new_tangents.write()[l + 2] = tangents[l].b; - new_tangents.write()[l + 3] = tangents[l].a; - } - array_copy[VisualServer::ARRAY_TANGENT] = new_tangents; - } - - morphs[j] = array_copy; - } - mesh->add_surface_from_arrays(primitive, array_mesh, morphs, mesh_flags); - mesh->surface_set_material(i, mat); - mesh->surface_set_name(i, AssimpUtils::get_assimp_string(ai_mesh->mName)); - } - - return mesh; -} - -/** - * Create a new mesh for the node supplied - */ -MeshInstance * -EditorSceneImporterAssimp::create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform) { - /* MESH NODE */ - Ref mesh; - Ref skin; - // see if we have mesh cache for this. - Vector surface_indices; - - RegenerateBoneStack(state); - - // Configure indices - for (uint32_t i = 0; i < assimp_node->mNumMeshes; i++) { - int mesh_index = assimp_node->mMeshes[i]; - // create list of mesh indexes - surface_indices.push_back(mesh_index); - } - - //surface_indices.sort(); - String mesh_key; - for (int i = 0; i < surface_indices.size(); i++) { - if (i > 0) { - mesh_key += ":"; - } - mesh_key += itos(surface_indices[i]); - } - - Skeleton *skeleton = NULL; - aiNode *armature = NULL; - - if (!state.mesh_cache.has(mesh_key)) { - mesh = _generate_mesh_from_surface_indices(state, surface_indices, assimp_node, skin, skeleton); - state.mesh_cache[mesh_key] = mesh; - } - - MeshInstance *mesh_node = memnew(MeshInstance); - mesh = state.mesh_cache[mesh_key]; - mesh_node->set_mesh(mesh); - - // if we have a valid skeleton set it up - if (skin.is_valid()) { - for (uint32_t i = 0; i < assimp_node->mNumMeshes; i++) { - unsigned int mesh_index = assimp_node->mMeshes[i]; - const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_index]; - - // please remember bone id relative to the skin is NOT the mesh relative index. - // it is the index relative to the skeleton that is why - // we have state.bone_id_map, it allows for duplicate bone id's too :) - // hope this makes sense - - int bind_count = 0; - for (unsigned int boneId = 0; boneId < ai_mesh->mNumBones; ++boneId) { - aiBone *iterBone = ai_mesh->mBones[boneId]; - - // used to reparent mesh to the correct armature later on if assigned. - if (!armature) { - print_verbose("Configured mesh armature, will reparent later to armature"); - armature = iterBone->mArmature; - } - - if (skeleton) { - int id = skeleton->find_bone(AssimpUtils::get_assimp_string(iterBone->mName)); - if (id != -1) { - print_verbose("Set bind bone: mesh: " + itos(mesh_index) + " bone index: " + itos(id)); - Transform t = AssimpUtils::assimp_matrix_transform(iterBone->mOffsetMatrix); - - skin->add_bind(bind_count, t); - skin->set_bind_bone(bind_count, id); - bind_count++; - } - } - } - } - - print_verbose("Finished configuring bind pose for skin mesh"); - } - - // this code parents all meshes with bones to the armature they are for - // GLTF2 specification relies on this and we are enforcing it for FBX. - if (armature && state.flat_node_map[armature]) { - Node *armature_parent = state.flat_node_map[armature]; - print_verbose("Parented mesh " + node_name + " to armature " + armature_parent->get_name()); - // static mesh handling - armature_parent->add_child(mesh_node); - // transform must be identity - mesh_node->set_global_transform(Transform()); - mesh_node->set_name(node_name); - mesh_node->set_owner(state.root); - } else { - // static mesh handling - active_node->add_child(mesh_node); - mesh_node->set_global_transform(node_transform); - mesh_node->set_name(node_name); - mesh_node->set_owner(state.root); - } - - if (skeleton) { - print_verbose("Attempted to set skeleton path!"); - mesh_node->set_skeleton_path(mesh_node->get_path_to(skeleton)); - mesh_node->set_skin(skin); - } - - return mesh_node; -} - -/** - * Create a light for the scene - * Automatically caches lights for lookup later - */ -Spatial *EditorSceneImporterAssimp::create_light( - ImportState &state, - const String &node_name, - Transform &look_at_transform) { - Light *light = NULL; - aiLight *assimp_light = state.assimp_scene->mLights[state.light_cache[node_name]]; - ERR_FAIL_COND_V(!assimp_light, NULL); - - if (assimp_light->mType == aiLightSource_DIRECTIONAL) { - light = memnew(DirectionalLight); - } else if (assimp_light->mType == aiLightSource_POINT) { - light = memnew(OmniLight); - } else if (assimp_light->mType == aiLightSource_SPOT) { - light = memnew(SpotLight); - } - ERR_FAIL_COND_V(light == NULL, NULL); - - if (assimp_light->mType != aiLightSource_POINT) { - Vector3 pos = Vector3( - assimp_light->mPosition.x, - assimp_light->mPosition.y, - assimp_light->mPosition.z); - Vector3 look_at = Vector3( - assimp_light->mDirection.y, - assimp_light->mDirection.x, - assimp_light->mDirection.z) - .normalized(); - Vector3 up = Vector3( - assimp_light->mUp.x, - assimp_light->mUp.y, - assimp_light->mUp.z); - - look_at_transform.set_look_at(pos, look_at, up); - } - // properties for light variables should be put here. - // not really hugely important yet but we will need them in the future - - light->set_color( - Color(assimp_light->mColorDiffuse.r, assimp_light->mColorDiffuse.g, assimp_light->mColorDiffuse.b)); - - return light; -} - -/** - * Create camera for the scene - */ -Spatial *EditorSceneImporterAssimp::create_camera( - ImportState &state, - const String &node_name, - Transform &look_at_transform) { - aiCamera *camera = state.assimp_scene->mCameras[state.camera_cache[node_name]]; - ERR_FAIL_COND_V(!camera, NULL); - - Camera *camera_node = memnew(Camera); - ERR_FAIL_COND_V(!camera_node, NULL); - float near = camera->mClipPlaneNear; - if (Math::is_equal_approx(near, 0.0f)) { - near = 0.1f; - } - camera_node->set_perspective(Math::rad2deg(camera->mHorizontalFOV) * 2.0f, near, camera->mClipPlaneFar); - Vector3 pos = Vector3(camera->mPosition.x, camera->mPosition.y, camera->mPosition.z); - Vector3 look_at = Vector3(camera->mLookAt.y, camera->mLookAt.x, camera->mLookAt.z).normalized(); - Vector3 up = Vector3(camera->mUp.x, camera->mUp.y, camera->mUp.z); - - look_at_transform.set_look_at(pos + look_at_transform.origin, look_at, up); - return camera_node; -} - -/** - * Generate node - * Recursive call to iterate over all nodes - */ -void EditorSceneImporterAssimp::_generate_node( - ImportState &state, - const aiNode *assimp_node) { - - ERR_FAIL_COND(assimp_node == NULL); - state.nodes.push_back(assimp_node); - String parent_name = AssimpUtils::get_assimp_string(assimp_node->mParent->mName); - - // please note - // duplicate bone names exist - // this is why we only check if the bone exists - // so everything else is useless but the name - // please do not copy any other values from get_bone_by_name. - aiBone *parent_bone = get_bone_by_name(state.assimp_scene, assimp_node->mParent->mName); - aiBone *current_bone = get_bone_by_name(state.assimp_scene, assimp_node->mName); - - // is this an armature - // parent null - // and this is the first bone :) - if (parent_bone == NULL && current_bone) { - state.armature_nodes.push_back(assimp_node->mParent); - print_verbose("found valid armature: " + parent_name); - } - - for (size_t i = 0; i < assimp_node->mNumChildren; i++) { - _generate_node(state, assimp_node->mChildren[i]); - } -} diff --git a/modules/assimp/godot_update_assimp.sh b/modules/assimp/godot_update_assimp.sh deleted file mode 100755 index ff8ff59e9754..000000000000 --- a/modules/assimp/godot_update_assimp.sh +++ /dev/null @@ -1,262 +0,0 @@ -rm -rf ../../thirdparty/assimp -cd ../../thirdparty/ -git clone https://github.com/assimp/assimp.git -cd assimp -rm -rf code/3DSExporter.h -rm -rf code/3DSLoader.h -rm -rf code/3MFXmlTags.h -rm -rf code/ABCImporter.h -rm -rf code/ACLoader.h -rm -rf code/AMFImporter_Macro.hpp -rm -rf code/ASELoader.h -rm -rf code/assbin_chunks.h -rm -rf code/AssbinExporter.h -rm -rf code/AssbinLoader.h -rm -rf code/AssimpCExport.cpp -rm -rf code/AssxmlExporter.h -rm -rf code/B3DImporter.h -# rm -rf code/BaseProcess.cpp -# rm -rf code/BaseProcess.h -# rm -rf code/Bitmap.cpp -rm -rf code/BlenderBMesh.cpp -rm -rf code/BlenderBMesh.h -rm -rf code/BlenderCustomData.cpp -rm -rf code/BlenderCustomData.h -rm -rf code/BlenderIntermediate.h -rm -rf code/BlenderLoader.h -rm -rf code/BlenderModifier.h -rm -rf code/BlenderSceneGen.h -rm -rf code/BlenderTessellator.h -rm -rf code/BVHLoader.h -rm -rf code/C4DImporter.h -# rm -rf code/CalcTangentsProcess.h -# rm -rf code/CInterfaceIOWrapper.cpp -# rm -rf code/CInterfaceIOWrapper.h -rm -rf code/COBLoader.h -rm -rf code/COBScene.h -rm -rf code/ColladaExporter.h -rm -rf code/ColladaLoader.h -# rm -rf code/ComputeUVMappingProcess.h -# rm -rf code/ConvertToLHProcess.h -# rm -rf code/CreateAnimMesh.cpp -rm -rf code/CSMLoader.h -rm -rf code/D3MFExporter.h -rm -rf code/D3MFImporter.h -rm -rf code/D3MFOpcPackage.h -# rm -rf code/DeboneProcess.h -# rm -rf code/DefaultIOStream.cpp -# rm -rf code/DefaultIOSystem.cpp -# rm -rf code/DefaultProgressHandler.h -# rm -rf code/DropFaceNormalsProcess.cpp -# rm -rf code/DropFaceNormalsProcess.h -rm -rf code/DXFHelper.h -rm -rf code/DXFLoader.h -# rm -rf code/EmbedTexturesProcess.cpp -# rm -rf code/EmbedTexturesProcess.h -# rm -rf code/FBXCommon.h -# rm -rf code/FBXCompileConfig.h -# rm -rf code/FBXDeformer.cpp -# rm -rf code/FBXDocumentUtil.cpp -# rm -rf code/FBXDocumentUtil.h -# rm -rf code/FBXExporter.h -# rm -rf code/FBXExportNode.h -# rm -rf code/FBXExportProperty.h -# rm -rf code/FBXImporter.cpp -# rm -rf code/FBXImporter.h -# rm -rf code/FBXImportSettings.h -# rm -rf code/FBXMeshGeometry.h -# rm -rf code/FBXModel.cpp -# rm -rf code/FBXNodeAttribute.cpp -# rm -rf code/FBXParser.h -# rm -rf code/FBXProperties.cpp -# rm -rf code/FBXProperties.h -# rm -rf code/FBXTokenizer.cpp -# rm -rf code/FBXTokenizer.h -# rm -rf code/FBXUtil.cpp -# rm -rf code/FBXUtil.h -# rm -rf code/FileLogStream.h -# rm -rf code/FindDegenerates.h -# rm -rf code/FindInstancesProcess.h -# rm -rf code/FindInvalidDataProcess.h -rm -rf code/FIReader.hpp -# rm -rf code/FixNormalsStep.cpp -# rm -rf code/FixNormalsStep.h -# rm -rf code/GenFaceNormalsProcess.cpp -# rm -rf code/GenFaceNormalsProcess.h -# rm -rf code/GenVertexNormalsProcess.cpp -# rm -rf code/GenVertexNormalsProcess.h -rm -rf code/glTF2Asset.h -rm -rf code/glTF2Asset.inl -rm -rf code/glTF2AssetWriter.inl -rm -rf code/glTF2Exporter.cpp -rm -rf code/glTF2Importer.cpp -rm -rf code/glTF2AssetWriter.h -rm -rf code/glTFAsset.h -rm -rf code/glTFAsset.inl -rm -rf code/glTFAssetWriter.inl -rm -rf code/glTFExporter.cpp -rm -rf code/glTFImporter.cpp -rm -rf code/glTF2Exporter.h -rm -rf code/glTF2Importer.h -rm -rf code/glTFAssetWriter.h -rm -rf code/glTFExporter.h -rm -rf code/glTFImporter.h -rm -rf code/HalfLifeFileData.h -rm -rf code/HMPFileData.h -rm -rf code/HMPLoader.h -rm -rf code/HMPLoader.cpp -rm -rf code/IFF.h -# rm -rf code/Importer.h -# rm -rf code/ImproveCacheLocality.h -rm -rf code/IRRLoader.h -rm -rf code/IRRMeshLoader.h -rm -rf code/IRRShared.h -# rm -rf code/JoinVerticesProcess.h -# rm -rf code/LimitBoneWeightsProcess.cpp -# rm -rf code/LimitBoneWeightsProcess.h -rm -rf code/LWSLoader.h -rm -rf code/makefile.mingw -# rm -rf code/MakeVerboseFormat.cpp -# rm -rf code/MakeVerboseFormat.h -# rm -rf code/MaterialSystem.h -rm -rf code/MD2FileData.h -rm -rf code/MD2Loader.h -rm -rf code/MD2NormalTable.h -rm -rf code/MD3FileData.h -rm -rf code/MD3Loader.h -rm -rf code/MD4FileData.h -rm -rf code/MD5Loader.h -rm -rf code/MD5Parser.cpp -rm -rf code/MDCFileData.h -rm -rf code/MDCLoader.h -rm -rf code/MDLDefaultColorMap.h -# rm -rf code/MMDCpp14.h -# rm -rf code/MMDImporter.h -rm -rf code/MS3DLoader.h -rm -rf code/NDOLoader.h -rm -rf code/NFFLoader.h -rm -rf code/ObjExporter.h -rm -rf code/ObjFileImporter.h -rm -rf code/ObjFileMtlImporter.h -rm -rf code/ObjFileParser.h -rm -rf code/ObjTools.h -rm -rf code/ObjExporter.cpp -rm -rf code/ObjFileImporter.cpp -rm -rf code/ObjFileMtlImporter.cpp -rm -rf code/ObjFileParser.cpp -rm -rf code/OFFLoader.h -rm -rf code/OFFLoader.cpp -rm -rf code/OgreImporter.cpp -rm -rf code/OgreImporter.h -rm -rf code/OgreParsingUtils.h -rm -rf code/OgreXmlSerializer.h -rm -rf code/OgreXmlSerializer.cpp -rm -rf code/OgreBinarySerializer.cpp -rm -rf code/OpenGEXExporter.cpp -rm -rf code/OpenGEXExporter.h -rm -rf code/OpenGEXImporter.h -rm -rf code/OpenGEXStructs.h -rm -rf code/OpenGEXImporter.cpp -# rm -rf code/OptimizeGraph.h -# rm -rf code/OptimizeMeshes.cpp -# rm -rf code/OptimizeMeshes.h -rm -rf code/PlyExporter.h -rm -rf code/PlyLoader.h -# rm -rf code/PolyTools.h -# rm -rf code/PostStepRegistry.cpp -# rm -rf code/PretransformVertices.h -rm -rf code/Q3BSPFileData.h -rm -rf code/Q3BSPFileImporter.h -rm -rf code/Q3BSPFileParser.cpp -rm -rf code/Q3BSPFileParser.h -rm -rf code/Q3BSPZipArchive.cpp -rm -rf code/Q3BSPZipArchive.h -rm -rf code/Q3DLoader.h -rm -rf code/Q3DLoader.cpp -rm -rf code/Q3BSPFileImporter.cpp -rm -rf code/RawLoader.h -# rm -rf code/RemoveComments.cpp -# rm -rf code/RemoveRedundantMaterials.cpp -# rm -rf code/RemoveRedundantMaterials.h -# rm -rf code/RemoveVCProcess.h -# rm -rf code/ScaleProcess.cpp -# rm -rf code/ScaleProcess.h -# rm -rf code/scene.cpp -# rm -rf code/ScenePreprocessor.cpp -# rm -rf code/ScenePreprocessor.h -# rm -rf code/ScenePrivate.h -# rm -rf code/SGSpatialSort.cpp -rm -rf code/SIBImporter.h -rm -rf code/SMDLoader.cpp -# rm -rf code/simd.cpp -# rm -rf code/simd.h -# rm -rf code/SortByPTypeProcess.h -# rm -rf code/SplitByBoneCountProcess.h -# rm -rf code/SplitLargeMeshes.h -# rm -rf code/StdOStreamLogStream.h -rm -rf code/StepExporter.h -rm -rf code/StepExporter.cpp -rm -rf code/STLExporter.cpp -rm -rf code/STLExporter.h -rm -rf code/STLLoader.h -rm -rf code/STLLoader.cpp -# rm -rf code/TargetAnimation.cpp -# rm -rf code/TargetAnimation.h -rm -rf code/TerragenLoader.h -rm -rf code/TerragenLoader.cpp -# rm -rf code/TextureTransform.h -# rm -rf code/TriangulateProcess.h -rm -rf code/UnrealLoader.h -# rm -rf code/ValidateDataStructure.h -# rm -rf code/Version.cpp -# rm -rf code/VertexTriangleAdjacency.cpp -# rm -rf code/VertexTriangleAdjacency.h -# rm -rf code/Win32DebugLogStream.h -rm -rf code/X3DImporter_Macro.hpp -rm -rf code/X3DImporter_Metadata.cpp -rm -rf code/X3DImporter_Networking.cpp -rm -rf code/X3DImporter_Texturing.cpp -rm -rf code/X3DImporter_Shape.cpp -rm -rf code/X3DImporter_Rendering.cpp -rm -rf code/X3DImporter_Postprocess.cpp -rm -rf code/X3DImporter_Light.cpp -rm -rf code/X3DImporter_Group.cpp -rm -rf code/X3DImporter_Geometry3D.cpp -rm -rf code/X3DImporter_Geometry2D.cpp -rm -rf code/X3DImporter.cpp -rm -rf code/X3DExporter.cpp -rm -rf code/X3DVocabulary.cpp -rm -rf code/XFileExporter.h -rm -rf code/XFileExporter.cpp -rm -rf code/XFileHelper.h -rm -rf code/XFileHelper.cpp -rm -rf code/XFileImporter.h -rm -rf code/XFileImporter.cpp -rm -rf code/XFileParser.h -rm -rf code/XFileParser.cpp -rm -rf code/XGLLoader.h -rm -rf code/XGLLoader.cpp -rm -rf code/Importer -rm -rf .git -rm -rf cmake-modules -rm -rf doc -rm -rf packaging -rm -rf port -rm -rf samples -rm -rf scripts -rm -rf test -rm -rf tools -rm -rf contrib/zlib -rm -rf contrib/android-cmake -rm -rf contrib/gtest -rm -rf contrib/clipper -rm -rf contrib/irrXML -rm -rf contrib/Open3DGC -rm -rf contrib/openddlparser -rm -rf contrib/poly2tri -#rm -rf contrib/rapidjson -rm -rf contrib/unzip -rm -rf contrib/zip -rm -rf contrib/stb_image -rm .travis* - diff --git a/modules/assimp/import_utils.h b/modules/assimp/import_utils.h deleted file mode 100644 index fd6f4dc176c0..000000000000 --- a/modules/assimp/import_utils.h +++ /dev/null @@ -1,447 +0,0 @@ -/*************************************************************************/ -/* import_utils.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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_IMPORTER_ASSIMP_H -#define IMPORT_UTILS_IMPORTER_ASSIMP_H - -#include "core/io/image_loader.h" -#include "import_state.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace AssimpImporter; - -#define AI_PROPERTIES aiTextureType_UNKNOWN, 0 -#define AI_NULL 0, 0 -#define AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR "$raw.Maya|baseColor" -#define AI_MATKEY_FBX_MAYA_METALNESS_FACTOR "$raw.Maya|metalness" -#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR "$raw.Maya|diffuseRoughness" - -#define AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE "$raw.Maya|emissionColor|file" -#define AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR "$raw.Maya|emission" -#define AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE "$raw.Maya|metalness|file" -#define AI_MATKEY_FBX_MAYA_METALNESS_UV_XFORM "$raw.Maya|metalness|uvtrafo" -#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE "$raw.Maya|diffuseRoughness|file" -#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_UV_XFORM "$raw.Maya|diffuseRoughness|uvtrafo" -#define AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE "$raw.Maya|baseColor|file" -#define AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM "$raw.Maya|baseColor|uvtrafo" -#define AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE "$raw.Maya|normalCamera|file" -#define AI_MATKEY_FBX_MAYA_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo" - -#define AI_MATKEY_FBX_NORMAL_TEXTURE "$raw.Maya|normalCamera|file" -#define AI_MATKEY_FBX_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo" - -#define AI_MATKEY_FBX_MAYA_STINGRAY_DISPLACEMENT_SCALING_FACTOR "$raw.Maya|displacementscaling" -#define AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR "$raw.Maya|base_color" -#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR "$raw.Maya|emissive" -#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR "$raw.Maya|metallic" -#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR "$raw.Maya|roughness" -#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR "$raw.Maya|emissive_intensity" - -#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE "$raw.Maya|TEX_normal_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_UV_XFORM "$raw.Maya|TEX_normal_map|uvtrafo" -#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE "$raw.Maya|TEX_color_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM "$raw.Maya|TEX_color_map|uvtrafo" -#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE "$raw.Maya|TEX_metallic_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_UV_XFORM "$raw.Maya|TEX_metallic_map|uvtrafo" -#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE "$raw.Maya|TEX_roughness_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_UV_XFORM "$raw.Maya|TEX_roughness_map|uvtrafo" -#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE "$raw.Maya|TEX_emissive_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_UV_XFORM "$raw.Maya|TEX_emissive_map|uvtrafo" -#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_TEXTURE "$raw.Maya|TEX_ao_map|file" -#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_UV_XFORM "$raw.Maya|TEX_ao_map|uvtrafo" - -/** - * Assimp Utils - * Conversion tools / glue code to convert from assimp to godot -*/ -class AssimpUtils { -public: - /** - * calculate tangents for mesh data from assimp data - */ - static void calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, PoolColorArray::Write &w) { - const aiVector3D normals = ai_mesh->mAnimMeshes[i]->mNormals[tri_index]; - const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z); - const aiVector3D tangent = ai_mesh->mAnimMeshes[i]->mTangents[tri_index]; - const Vector3 godot_tangent = Vector3(tangent.x, tangent.y, tangent.z); - const aiVector3D bitangent = ai_mesh->mAnimMeshes[i]->mBitangents[tri_index]; - const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z); - float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f; - Color plane_tangent = Color(tangent.x, tangent.y, tangent.z, d); - w[index] = plane_tangent; - } - - 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 assimp string - * automatically filters the string data - */ - static String get_assimp_string(const aiString &p_string) { - //convert an assimp String to a Godot String - String name; - name.parse_utf8(p_string.C_Str() /*,p_string.length*/); - if (name.find(":") != -1) { - String replaced_name = name.split(":")[1]; - print_verbose("Replacing " + name + " containing : with " + replaced_name); - name = replaced_name; - } - - return name; - } - - static String get_anim_string_from_assimp(const aiString &p_string) { - - String name; - name.parse_utf8(p_string.C_Str() /*,p_string.length*/); - if (name.find(":") != -1) { - String replaced_name = name.split(":")[1]; - print_verbose("Replacing " + name + " containing : with " + replaced_name); - name = replaced_name; - } - return name; - } - - /** - * No filter logic get_raw_string_from_assimp - * This just convers the aiString to a parsed utf8 string - * Without removing special chars etc - */ - static String get_raw_string_from_assimp(const aiString &p_string) { - String name; - name.parse_utf8(p_string.C_Str() /*,p_string.length*/); - return name; - } - - static Ref import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return Ref(); - } - - /** - * Converts aiMatrix4x4 to godot Transform - */ - static const Transform assimp_matrix_transform(const aiMatrix4x4 p_matrix) { - aiMatrix4x4 matrix = p_matrix; - Transform xform; - xform.set(matrix.a1, matrix.a2, matrix.a3, matrix.b1, matrix.b2, matrix.b3, matrix.c1, matrix.c2, matrix.c3, matrix.a4, matrix.b4, matrix.c4); - return xform; - } - - /** Get fbx fps for time mode meta data - */ - static float get_fbx_fps(int32_t time_mode, const aiScene *p_scene) { - switch (time_mode) { - case AssetImportFbx::TIME_MODE_DEFAULT: return 24; //hack - 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: - int32_t frame_rate = -1; - p_scene->mMetaData->Get("FrameRate", frame_rate); - return frame_rate; - } - return 0; - } - - /** - * Get global transform for the current node - so we can use world space rather than - * local space coordinates - * useful if you need global - although recommend using local wherever possible over global - * as you could break fbx scaling :) - */ - static Transform _get_global_assimp_node_transform(const aiNode *p_current_node) { - aiNode const *current_node = p_current_node; - Transform xform; - while (current_node != NULL) { - xform = assimp_matrix_transform(current_node->mTransformation) * xform; - current_node = current_node->mParent; - } - return xform; - } - - /** - * Find hardcoded textures from assimp which could be in many different directories - */ - static void find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension) { - Vector paths; - paths.push_back(path.get_basename() + extension); - paths.push_back(path + extension); - paths.push_back(path); - paths.push_back(p_path.get_base_dir().plus_file(path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file(path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file(path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file())); - paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file().get_basename() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file() + extension)); - paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file())); - for (int i = 0; i < paths.size(); i++) { - if (dir.file_exists(paths[i])) { - found = true; - path = paths[i]; - return; - } - } - } - - /** find the texture path for the supplied fbx path inside godot - * very simple lookup for subfolders etc for a texture which may or may not be in a directory - */ - static void find_texture_path(const String &r_p_path, String &r_path, bool &r_found) { - _Directory dir; - - List exts; - ImageLoader::get_recognized_extensions(&exts); - - Vector split_path = r_path.get_basename().split("*"); - if (split_path.size() == 2) { - r_found = true; - return; - } - - if (dir.file_exists(r_p_path.get_base_dir() + r_path.get_file())) { - r_path = r_p_path.get_base_dir() + r_path.get_file(); - r_found = true; - return; - } - - for (int32_t i = 0; i < exts.size(); i++) { - if (r_found) { - return; - } - find_texture_path(r_p_path, dir, r_path, r_found, "." + exts[i]); - } - } - - /** - * 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 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 :) - */ - static Ref load_image(ImportState &state, const aiScene *p_scene, String p_path) { - - Map >::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 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()); - 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")) { - ERR_FAIL_COND_V(Image::_png_mem_loader_func == NULL, Ref()); - Ref img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); - ERR_FAIL_COND_V(img.is_null(), Ref()); - state.path_to_image_cache.insert(p_path, img); - return img; - } else if (tex->CheckFormat("jpg")) { - ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == NULL, Ref()); - Ref img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); - ERR_FAIL_COND_V(img.is_null(), Ref()); - state.path_to_image_cache.insert(p_path, img); - return img; - } else if (tex->CheckFormat("dds")) { - ERR_FAIL_COND_V_MSG(true, Ref(), "Open Asset Import: Embedded dds not implemented"); - } - } else { - Ref 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()); - //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()); - state.path_to_image_cache.insert(p_path, img); - return img; - } - return Ref(); - } else { - Ref texture = ResourceLoader::load(p_path); - ERR_FAIL_COND_V(texture.is_null(), Ref()); - Ref image = texture->get_data(); - ERR_FAIL_COND_V(image.is_null(), Ref()); - state.path_to_image_cache.insert(p_path, image); - return image; - } - - return Ref(); - } - - /* 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; - } -}; - -#endif // IMPORT_UTILS_IMPORTER_ASSIMP_H diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub new file mode 100644 index 000000000000..1b23900576b1 --- /dev/null +++ b/modules/fbx/SCsub @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_fbx = env_modules.Clone() + +# 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, "../../thirdparty/assimp_fbx/**.cpp") +env_fbx.add_source_files(env.modules_sources, "**.cpp") diff --git a/modules/assimp/config.py b/modules/fbx/config.py similarity index 100% rename from modules/assimp/config.py rename to modules/fbx/config.py diff --git a/modules/fbx/data/fbx_anim_container.h b/modules/fbx/data/fbx_anim_container.h new file mode 100644 index 000000000000..7b4106e5b549 --- /dev/null +++ b/modules/fbx/data/fbx_anim_container.h @@ -0,0 +1,46 @@ +/*************************************************************************/ +/* fbx_anim_container.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_ANIM_CONTAINER_H +#define MODEL_ABSTRACTION_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 keyframes; +}; + +#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H diff --git a/modules/fbx/data/fbx_bone.cpp b/modules/fbx/data/fbx_bone.cpp new file mode 100644 index 000000000000..32e5aee83da8 --- /dev/null +++ b/modules/fbx/data/fbx_bone.cpp @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* fbx_bone.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 FBXBone::get_link(const ImportState &state) const { + print_verbose("bone name: " + bone_name); + ERR_FAIL_COND_V_MSG(cluster == nullptr, nullptr, "bone has invalid cluster"); + ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node"); + + Ref 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; +} + +/* right now we just get single skin working and we can patch in the multiple tomorrow - per skin not per bone. */ +// this will work for multiple meshes :) awesomeness. +// okay so these formula's are complex and need proper understanding of +// shear, pivots, geometric pivots, pre rotation and post rotation +// additionally DO NOT EDIT THIS if your blender file isn't working. +// Contact RevoluPowered Gordon MacPherson if you are contemplating making edits to this. +Transform FBXBone::get_vertex_skin_xform(const ImportState &state, Transform mesh_global_position, bool &r_valid_pose) { + r_valid_pose = false; + print_verbose("get_vertex_skin_xform: " + bone_name); + ERR_FAIL_COND_V_MSG(cluster == nullptr, Transform(), "[serious] unable to resolve the fbx cluster for this bone " + bone_name); + // these methods will ONLY work for Maya. + if (cluster->TransformAssociateModelValid()) { + //print_error("additive skinning in use"); + Transform associate_global_init_position = cluster->TransformAssociateModel(); + Transform associate_global_current_position = Transform(); + Transform reference_global_init_position = cluster->GetTransform(); + Transform cluster_global_init_position = cluster->TransformLink(); + Ref link_node = get_link(state); + ERR_FAIL_COND_V_MSG(link_node.is_null(), Transform(), "invalid link corrupt file detected"); + r_valid_pose = true; + Transform cluster_global_current_position = link_node.is_valid() && link_node->pivot_transform.is_valid() ? link_node->pivot_transform->GlobalTransform : Transform(); + + vertex_transform_matrix = reference_global_init_position.affine_inverse() * associate_global_init_position * associate_global_current_position.affine_inverse() * + cluster_global_current_position * cluster_global_init_position.affine_inverse() * reference_global_init_position; + } else { + //print_error("non additive skinning is in use"); + Transform reference_global_position = cluster->GetTransform(); + Transform reference_global_current_position = mesh_global_position; + //Transform geometric_pivot = Transform(); // we do not use this - 3ds max only + Transform global_init_position = cluster->TransformLink(); + Transform cluster_relative_init_position = global_init_position.affine_inverse() * reference_global_position; + Transform cluster_relative_position_inverse = reference_global_current_position.affine_inverse() * global_init_position; + vertex_transform_matrix = cluster_relative_position_inverse * cluster_relative_init_position; + r_valid_pose = true; + } + + return vertex_transform_matrix; +} diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h new file mode 100644 index 000000000000..dd87ac92584c --- /dev/null +++ b/modules/fbx/data/fbx_bone.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* fbx_bone.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_FBX_BONE_H +#define MODEL_ABSTRACTION_FBX_BONE_H + +#include "fbx_node.h" +#include "import_state.h" +#include "thirdparty/assimp_fbx/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; + } + + uint64_t target_node_id; // the node target id for the skeleton element + bool valid_target = false; // only applies to bones with a mesh / in the skin. + + // 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; + + // Vertex Weight information + Transform transform_link; // todo remove + Transform transform_matrix; // todo remove + + /* get associate model - the model can be invalid sometimes */ + Ref get_associate_model() const { + return parent_bone; + } + + /* link node is the parent bone */ + Ref get_link(const ImportState &state) const; + Transform get_vertex_skin_xform(const ImportState &state, Transform mesh_global_position, bool &valid); + Transform vertex_transform_matrix; + Transform local_cluster_matrix; // set_bone_pose + + mutable const Assimp::FBX::Deformer *skin = nullptr; // let's stop copying data + mutable const Assimp::FBX::Cluster *cluster = nullptr; + mutable const Assimp::FBX::Geometry *geometry = nullptr; + + void set_pivot_xform(Ref p_pivot_xform) { + pivot_xform = p_pivot_xform; + } + + // pose node / if assigned + Transform pose_node = Transform(); + bool assigned_pose_node = false; + Ref parent_bone = Ref(); + Ref pivot_xform = Ref(); + Ref fbx_skeleton = Ref(); +}; + +#endif // MODEL_ABSTRACTION_FBX_BONE_H diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp new file mode 100644 index 000000000000..eab93468b28e --- /dev/null +++ b/modules/fbx/data/fbx_material.cpp @@ -0,0 +1,485 @@ +/*************************************************************************/ +/* fbx_material.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 + +String FBXMaterial::get_material_name() const { + return material_name; +} + +void FBXMaterial::set_imported_material(const Assimp::FBX::Material *p_material) { + material = p_material; +} + +void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector &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 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 Assimp::FBX::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 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: 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(); + const SpatialMaterial::TextureParam mapping_mode = fbx_texture_mapping_desc.at(fbx_mapping_name); + + 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 +T extract_from_prop(const Assimp::FBX::Property *prop, const T &p_default, const std::string &p_name, const String &p_type) { + const Assimp::FBX::TypedProperty *val = prop->As >(); + if (val == nullptr) { + return p_default; + } + //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 FBXMaterial::import_material(ImportState &state) { + + ERR_FAIL_COND_V(material == nullptr, nullptr); + + const String p_fbx_current_directory = state.path; + + Ref 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. + const std::vector properties_name = material->Props().get_properties_name(); + for (std::string name : properties_name) { + if (name.empty()) { + continue; + } + PropertyDesc desc = PROPERTY_DESC_NOT_FOUND; + if (fbx_properties_desc.count(name) > 0) { + desc = fbx_properties_desc.at(name); + } + + if (desc == PROPERTY_DESC_IGNORE) { + //print_verbose("The FBX material parameter: `" + String(name.c_str()) + "` is ignored."); + continue; + } + + 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 Assimp::FBX::Property *prop = material->Props().Get(name); + + if (prop == nullptr) { + continue; + } + //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(); + } + + switch (desc) { + case PROPERTY_DESC_ALBEDO_COLOR: { + const Vector3 color = extract_from_prop(prop, Vector3(0, 0, 0), name, "Vector3"); + // Make sure to not lost any eventual opacity. + Color c = spatial_material->get_albedo(); + c[0] = color[0]; + c[1] = color[1]; + c[2] = color[2]; + spatial_material->set_albedo(c); + } break; + case PROPERTY_DESC_TRANSPARENT: { + const real_t opacity = extract_from_prop(prop, 1.0f, name, "float"); + if (opacity < (1.0 - CMP_EPSILON)) { + Color c = spatial_material->get_albedo(); + c[3] = 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); + } + } break; + case PROPERTY_DESC_METALLIC: { + spatial_material->set_metallic(extract_from_prop(prop, 1.0f, name, "float")); + } break; + case PROPERTY_DESC_ROUGHNESS: { + spatial_material->set_roughness(extract_from_prop(prop, 1.0f, name, "float")); + } break; + case PROPERTY_DESC_COAT: { + spatial_material->set_clearcoat(extract_from_prop(prop, 1.0f, name, "float")); + material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT); + } break; + case PROPERTY_DESC_COAT_ROUGHNESS: { + spatial_material->set_clearcoat_gloss(1.0 - extract_from_prop(prop, 0.5f, name, "float")); + material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT); + } break; + case PROPERTY_DESC_EMISSIVE: { + const real_t emissive = extract_from_prop(prop, 0.0f, name, "float"); + if (emissive > CMP_EPSILON) { + spatial_material->set_emission_energy(emissive); + material_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION); + } + } break; + case PROPERTY_DESC_EMISSIVE_COLOR: { + const Vector3 color = extract_from_prop(prop, Vector3(0, 0, 0), name, "Vector3"); + Color c; + c[0] = color[0]; + c[1] = color[1]; + c[2] = color[2]; + spatial_material->set_emission(c); + } break; + case PROPERTY_DESC_NOT_FOUND: + case PROPERTY_DESC_IGNORE: + // Already checked, can't happen. + CRASH_NOW(); + break; + } + } + + // FBX culling normally is front only. + spatial_material->set_cull_mode(SpatialMaterial::CULL_FRONT); + + // 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; + 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 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 == NULL || 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) { + // This is an embedded texture. Extract it. + Ref 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 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; + } + + spatial_material->set_texture(mapping.map_mode, texture); + } + + if (spatial_material.is_valid()) { + spatial_material->set_name(material_name); + } + + return spatial_material; +} diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h new file mode 100644 index 000000000000..4f1a56c62333 --- /dev/null +++ b/modules/fbx/data/fbx_material.h @@ -0,0 +1,231 @@ +/*************************************************************************/ +/* fbx_material.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 GODOT_FBX_MATERIAL_H +#define GODOT_FBX_MATERIAL_H + +#include "core/reference.h" +#include "core/ustring.h" +#include "modules/fbx/tools/import_utils.h" + +struct FBXMaterial : public Reference { + String material_name = String(); + mutable const Assimp::FBX::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, + }; + + // TODO make this static? + const std::map fbx_feature_mapping_desc = { + /* Transparent */ + { "TransparentColor", SpatialMaterial::Feature::FEATURE_TRANSPARENT }, + { "Maya|opacity", SpatialMaterial::Feature::FEATURE_TRANSPARENT } + }; + + // TODO make this static? + const std::map fbx_texture_mapping_desc = { + /* Diffuse */ + { "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 }, + { "ShininessExponent", SpatialMaterial::TextureParam::TEXTURE_METALLIC }, + /* Roughness */ + { "Maya|diffuseRoughness", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS }, + { "Maya|diffuseRoughness|file", 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 }, + { "ReflectionFactor", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS }, + { "Maya|specularRoughness", 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 }, + // {"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_COAT, + PROPERTY_DESC_COAT_ROUGHNESS, + PROPERTY_DESC_EMISSIVE, + PROPERTY_DESC_EMISSIVE_COLOR, + PROPERTY_DESC_IGNORE + }; + + const std::map fbx_properties_desc = { + /* Albedo */ + { "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR }, + { "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR }, + + /* 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 }, + + /* Roughness */ + { "Maya|diffuseRoughness", PROPERTY_DESC_ROUGHNESS }, + + /* Coat */ + { "Maya|coat", PROPERTY_DESC_COAT }, + + /* Coat roughness */ + { "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS }, + + /* Emissive */ + { "Maya|emission", PROPERTY_DESC_EMISSIVE }, + + /* Emissive color */ + { "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR }, + { "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR }, + + /* Ignore */ + { "Maya", PROPERTY_DESC_IGNORE }, + { "Diffuse", PROPERTY_DESC_IGNORE }, + { "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 Assimp::FBX::Texture *texture = nullptr; + }; + + /* storing the texture properties like color */ + template + 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 &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(const Assimp::FBX::Material *p_material); + + struct MaterialInfo { + Vector textures; + Vector features; + }; + /// Extracts the material information. + MaterialInfo extract_material_info(const Assimp::FBX::Material *material) const; + + Ref import_material(ImportState &state); +}; + +#endif // GODOT_FBX_MATERIAL_H diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp new file mode 100644 index 000000000000..1a2887179b96 --- /dev/null +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -0,0 +1,1212 @@ +/*************************************************************************/ +/* fbx_mesh_data.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_mesh_data.h" + +#include "scene/resources/mesh.h" +#include "scene/resources/surface_tool.h" +#include "thirdparty/misc/triangulator.h" +#include + +template +T collect_first(const Vector > *p_data, T p_fall_back) { + if (p_data->empty()) { + return p_fall_back; + } + + return (*p_data)[0].data; +} + +template +T collect_average(const Vector > *p_data, T p_fall_back) { + if (p_data->empty()) { + return p_fall_back; + } + + T combined = (*p_data)[0].data; // Make sure the data is always correctly initialized. + for (int i = 1; i < p_data->size(); i += 1) { + combined += (*p_data)[i].data; + } + combined = combined / real_t(p_data->size()); + + return combined.normalized(); +} + +HashMap collect_uv(const Vector > *p_data, HashMap p_fall_back) { + if (p_data->empty()) { + return p_fall_back; + } + + HashMap collection; + for (int i = 0; i < p_data->size(); i += 1) { + const VertexData &vd = (*p_data)[i]; + collection[vd.polygon_index] = vd.data; + } + return collection; +} + +typedef int Vertex; +typedef int SurfaceId; +typedef int PolygonId; +typedef int DataIndex; + +struct SurfaceData { + Ref surface_tool; + // Contains vertices, calling this data so it's the same name used in the FBX format. + Vector vertices_map; + Ref material; + HashMap > surface_polygon_vertex; + Array morphs; +}; + +MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const Assimp::FBX::MeshGeometry *mesh_geometry, const Assimp::FBX::Model *model) { + + // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately. + const std::vector &material_lookup = model->GetMaterials(); + + std::vector polygon_indices = mesh_geometry->get_polygon_indices(); + std::vector vertices = mesh_geometry->get_vertices(); + + // Phase 1. Parse all FBX data. + HashMap normals = extract_per_vertex_data( + vertices.size(), + mesh_geometry->get_edge_map(), + polygon_indices, + mesh_geometry->get_normals(), + &collect_average, + Vector3(1, 0, 0)); + + HashMap uvs_0; + HashMap > uvs_0_raw = extract_per_vertex_data( + vertices.size(), + mesh_geometry->get_edge_map(), + polygon_indices, + mesh_geometry->get_uv_0(), + &collect_uv, + HashMap()); + + HashMap uvs_1; + HashMap > uvs_1_raw = extract_per_vertex_data( + vertices.size(), + mesh_geometry->get_edge_map(), + polygon_indices, + mesh_geometry->get_uv_1(), + &collect_uv, + HashMap()); + + HashMap colors = extract_per_vertex_data( + vertices.size(), + mesh_geometry->get_edge_map(), + polygon_indices, + mesh_geometry->get_colors(), + &collect_first, + Color()); + + // TODO what about tangends? + // TODO what about binormals? + // TODO there is other? + + HashMap polygon_surfaces = extract_per_polygon( + vertices.size(), + polygon_indices, + mesh_geometry->get_material_allocation_id(), + -1); + + HashMap morphs; + extract_morphs(mesh_geometry, morphs); + + // TODO please add skinning. + //mesh_id = mesh_geometry->ID(); + + sanitize_vertex_weights(); + + // Re organize polygon vertices to to correctly take into account strange + // UVs. + reorganize_vertices( + polygon_indices, + vertices, + normals, + uvs_0, + uvs_1, + colors, + morphs, + uvs_0_raw, + uvs_1_raw); + + // Make sure that from this moment on the mesh_geometry is no used anymore. + // This is a safety step, because the mesh_geometry data are no more valid + // at this point. + mesh_geometry = nullptr; + + const int vertex_count = vertices.size(); + + // The map key is the material allocator id that is also used as surface id. + HashMap surfaces; + + // Phase 2. For each material create a surface tool (So a different mesh). + { + if (polygon_surfaces.empty()) { + // No material, just use the default one with index -1. + // Set -1 to all polygons. + const int polygon_count = count_polygons(polygon_indices); + for (int p = 0; p < polygon_count; p += 1) { + polygon_surfaces[p] = -1; + } + } + + // Create the surface now. + for (const int *polygon_id = polygon_surfaces.next(nullptr); polygon_id != nullptr; polygon_id = polygon_surfaces.next(polygon_id)) { + const int surface_id = polygon_surfaces[*polygon_id]; + if (surfaces.has(surface_id) == false) { + SurfaceData sd; + sd.surface_tool.instance(); + sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + + if (surface_id < 0) { + // nothing to do + } else if (surface_id < (int)material_lookup.size()) { + const Assimp::FBX::Material *mat_mapping = material_lookup.at(surface_id); + const uint64_t mapping_id = mat_mapping->ID(); + if (state.cached_materials.has(mapping_id)) { + sd.material = state.cached_materials[mapping_id]; + } + } else { + WARN_PRINT("out of bounds surface detected, FBX file has corrupt material data"); + } + + surfaces.set(surface_id, sd); + } + } + } + + // Phase 3. Map the vertices relative to each surface, in this way we can + // just insert the vertices that we need per each surface. + { + PolygonId polygon_index = -1; + SurfaceId surface_id = -1; + SurfaceData *surface_data = nullptr; + + for (size_t polygon_vertex = 0; polygon_vertex < polygon_indices.size(); polygon_vertex += 1) { + if (is_start_of_polygon(polygon_indices, polygon_vertex)) { + polygon_index += 1; + ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is currupted, This surface_index is not expected."); + surface_id = polygon_surfaces[polygon_index]; + surface_data = surfaces.getptr(surface_id); + CRASH_COND(surface_data == nullptr); // Can't be null. + } + + const int vertex = get_vertex_from_polygon_vertex(polygon_indices, polygon_vertex); + + // The vertex position in the surface + int surface_polygon_vertex_index = surface_data->vertices_map.find(vertex); + if (surface_polygon_vertex_index < 0) { + // This is a new vertex, store it. + surface_polygon_vertex_index = surface_data->vertices_map.size(); + surface_data->vertices_map.push_back(vertex); + } + + surface_data->surface_polygon_vertex[polygon_index].push_back(surface_polygon_vertex_index); + } + } + + // Phase 4. Per each surface just insert the vertices and add the indices. + for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { + SurfaceData *surface = surfaces.getptr(*surface_id); + + // Just add the vertices data. + for (int i = 0; i < surface->vertices_map.size(); i += 1) { + const Vertex vertex = surface->vertices_map[i]; + + // This must be done before add_vertex because the surface tool is + // expecting this before the st->add_vertex() call + add_vertex( + surface->surface_tool, + state.scale, + vertex, + vertices, + normals, + uvs_0, + uvs_1, + colors); + } + + // Triangulate the various polygons and add the indices. + for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) { + const Vector *indices = surface->surface_polygon_vertex.getptr(*polygon_id); + + triangulate_polygon( + surface->surface_tool, + *indices, + surface->vertices_map, + vertices); + } + } + + // Phase 5. Compose the morphs if any. + for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { + SurfaceData *surface = surfaces.getptr(*surface_id); + + for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { + MorphVertexData *morph_data = morphs.getptr(*morph_name); + + // As said by the docs, this is not supposed to be different than + // vertex_count. + CRASH_COND(morph_data->vertices.size() != vertex_count); + CRASH_COND(morph_data->normals.size() != vertex_count); + + Vector3 *vertices_ptr = morph_data->vertices.ptrw(); + Vector3 *normals_ptr = morph_data->normals.ptrw(); + + Ref morph_st; + morph_st.instance(); + morph_st->begin(Mesh::PRIMITIVE_TRIANGLES); + + for (int vi = 0; vi < surface->vertices_map.size(); vi += 1) { + const Vertex vertex = surface->vertices_map[vi]; + add_vertex( + morph_st, + state.scale, + vertex, + vertices, + normals, + uvs_0, + uvs_1, + colors, + vertices_ptr[vertex], + normals_ptr[vertex]); + } + + morph_st->generate_tangents(); + surface->morphs.push_back(morph_st->commit_to_arrays()); + } + } + + // Phase 6. Compose the mesh and return it. + Ref mesh; + mesh.instance(); + + // Add blend shape info. + for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { + mesh->add_blend_shape(*morph_name); + } + + // TODO always normalized, Why? + mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); + + // Add surfaces. + int in_mesh_surface_id = 0; + for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { + SurfaceData *surface = surfaces.getptr(*surface_id); + + surface->surface_tool->generate_tangents(); + + mesh->add_surface_from_arrays( + Mesh::PRIMITIVE_TRIANGLES, + surface->surface_tool->commit_to_arrays(), + surface->morphs); + + if (surface->material.is_valid()) { + mesh->surface_set_name(in_mesh_surface_id, surface->material->get_name()); + mesh->surface_set_material(in_mesh_surface_id, surface->material); + } + + in_mesh_surface_id += 1; + } + + MeshInstance *godot_mesh = memnew(MeshInstance); + godot_mesh->set_mesh(mesh); + return godot_mesh; +} + +void FBXMeshData::sanitize_vertex_weights() { + const int max_bones = VS::ARRAY_WEIGHTS_SIZE; + + for (const Vertex *v = vertex_weights.next(nullptr); v != nullptr; v = vertex_weights.next(v)) { + VertexMapping *vm = vertex_weights.getptr(*v); + ERR_CONTINUE(vm->bones.size() != vm->weights.size()); // No message, already checked. + ERR_CONTINUE(vm->bones_ref.size() != vm->weights.size()); // No message, already checked. + + const int initial_size = vm->weights.size(); + + { + // Init bone id + int *bones_ptr = vm->bones.ptrw(); + Ref *bones_ref_ptr = vm->bones_ref.ptrw(); + + for (int i = 0; i < vm->weights.size(); i += 1) { + // At this point this is not possible because the skeleton is already initialized. + CRASH_COND(bones_ref_ptr[i]->godot_bone_id == -2); + bones_ptr[i] = bones_ref_ptr[i]->godot_bone_id; + } + + // From this point on the data is no more valid. + vm->bones_ref.clear(); + } + + { + // Sort + real_t *weights_ptr = vm->weights.ptrw(); + int *bones_ptr = vm->bones.ptrw(); + for (int i = 0; i < vm->weights.size(); i += 1) { + for (int x = i + 1; x < vm->weights.size(); x += 1) { + if (weights_ptr[i] < weights_ptr[x]) { + SWAP(weights_ptr[i], weights_ptr[x]); + SWAP(bones_ptr[i], bones_ptr[x]); + } + } + } + } + + { + // Resize + vm->weights.resize(max_bones); + vm->bones.resize(max_bones); + real_t *weights_ptr = vm->weights.ptrw(); + int *bones_ptr = vm->bones.ptrw(); + for (int i = initial_size; i < max_bones; i += 1) { + weights_ptr[i] = 0.0; + bones_ptr[i] = 0; + } + + // Normalize + real_t sum = 0.0; + for (int i = 0; i < max_bones; i += 1) { + sum += weights_ptr[i]; + } + if (sum > 0.0) { + for (int i = 0; i < vm->weights.size(); i += 1) { + weights_ptr[i] = weights_ptr[i] / sum; + } + } + } + } +} + +void FBXMeshData::reorganize_vertices( + std::vector &r_polygon_indices, + std::vector &r_vertices, + HashMap &r_normals, + HashMap &r_uv_1, + HashMap &r_uv_2, + HashMap &r_color, + HashMap &r_morphs, + HashMap > &r_uv_1_raw, + HashMap > &r_uv_2_raw) { + + // Key: OldVertex; Value: [New vertices]; + HashMap > duplicated_vertices; + + PolygonId polygon_index = -1; + for (int pv = 0; pv < (int)r_polygon_indices.size(); pv += 1) { + if (is_start_of_polygon(r_polygon_indices, pv)) { + polygon_index += 1; + } + const Vertex index = get_vertex_from_polygon_vertex(r_polygon_indices, pv); + + bool need_duplication = false; + Vector2 this_vert_poly_uv1 = Vector2(); + Vector2 this_vert_poly_uv2 = Vector2(); + + HashMap > *uv_raw = &r_uv_1_raw; + Vector2 *this_vert_poly_uv = &this_vert_poly_uv1; + for (int kk = 0; kk < 2; kk += 1) { + if (uv_raw->has(index)) { + const HashMap *uvs = uv_raw->getptr(index); + + if (uvs->has(polygon_index)) { + // This Polygon has its own uv. + (*this_vert_poly_uv) = *uvs->getptr(polygon_index); + + // Check if we need to duplicate it. + for (const PolygonId *pid = uvs->next(nullptr); pid != nullptr; pid = uvs->next(pid)) { + if (*pid == polygon_index) { + continue; + } + const Vector2 vert_poly_uv = *uvs->getptr(*pid); + if (((*this_vert_poly_uv) - vert_poly_uv).length() > CMP_EPSILON) { + // Yes this polygon need duplication. + need_duplication = true; + break; + } + } + } else if (uvs->has(-1)) { + // It has the default UV. + (*this_vert_poly_uv) = *uvs->getptr(-1); + } else if (uvs->size() > 0) { + // No uv, this is strange, just take the first and duplicate. + (*this_vert_poly_uv) = *uvs->getptr(*uvs->next(nullptr)); + WARN_PRINT("No UVs for this polygon, while there is no default and some other polygons have it. This FBX file may be corrupted."); + } + } + uv_raw = &r_uv_2_raw; + this_vert_poly_uv = &this_vert_poly_uv2; + } + + if (need_duplication) { + // Let's see if we already duplicated this vertex. + if (duplicated_vertices.has(index)) { + Vertex similar_vertex = -1; + // Let's see if one of the new vertices has the same data of this. + const Vector *new_vertices = duplicated_vertices.getptr(index); + for (int j = 0; j < new_vertices->size(); j += 1) { + const Vertex new_vertex = (*new_vertices)[j]; + if (r_uv_1.has(new_vertex)) { + if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { + similar_vertex = new_vertex; + break; + } + } else if (r_uv_2.has(new_vertex)) { + if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { + similar_vertex = new_vertex; + break; + } + } + } + + if (similar_vertex != -1) { + // Update polygon. + if (is_end_of_polygon(r_polygon_indices, pv)) { + r_polygon_indices[pv] = ~similar_vertex; + } else { + r_polygon_indices[pv] = similar_vertex; + } + need_duplication = false; + } + } + } + + if (need_duplication) { + const Vertex old_index = index; + const Vertex new_index = r_vertices.size(); + + // Polygon index. + if (is_end_of_polygon(r_polygon_indices, pv)) { + r_polygon_indices[pv] = ~new_index; + } else { + r_polygon_indices[pv] = new_index; + } + + // Vertex position. + r_vertices.push_back(r_vertices[old_index]); + + // Vertex normal. + if (r_normals.has(old_index)) { + r_normals[new_index] = r_normals[old_index]; + } + + // UV 0 + if (r_uv_1_raw.has(old_index)) { + r_uv_1.set(new_index, this_vert_poly_uv1); + r_uv_1_raw.getptr(old_index)->erase(polygon_index); + r_uv_1_raw[new_index][polygon_index] = this_vert_poly_uv1; + } + + // UV 1 + if (r_uv_2_raw.has(old_index)) { + r_uv_2.set(new_index, this_vert_poly_uv2); + r_uv_2_raw.getptr(old_index)->erase(polygon_index); + r_uv_2_raw[new_index][polygon_index] = this_vert_poly_uv2; + } + + // Vertex color. + if (r_color.has(old_index)) { + r_color[new_index] = r_color[old_index]; + } + + // Morphs + for (const String *mname = r_morphs.next(nullptr); mname != nullptr; mname = r_morphs.next(mname)) { + MorphVertexData *d = r_morphs.getptr(*mname); + // This can't never happen. + CRASH_COND(d == nullptr); + if (d->vertices.size() > old_index) { + d->vertices.push_back(d->vertices[old_index]); + } + if (d->normals.size() > old_index) { + d->normals.push_back(d->normals[old_index]); + } + } + + if (vertex_weights.has(old_index)) { + vertex_weights.set(new_index, vertex_weights[old_index]); + } + + duplicated_vertices[old_index].push_back(new_index); + } else { + if (r_uv_1_raw.has(index) && + r_uv_1.has(index) == false) { + r_uv_1.set(index, this_vert_poly_uv1); + } + + if (r_uv_2_raw.has(index) && + r_uv_2.has(index) == false) { + r_uv_2.set(index, this_vert_poly_uv2); + } + } + } +} + +void FBXMeshData::add_vertex( + Ref p_surface_tool, + real_t p_scale, + Vertex p_vertex, + const std::vector &p_vertices_position, + const HashMap &p_normals, + const HashMap &p_uvs_0, + const HashMap &p_uvs_1, + const HashMap &p_colors, + const Vector3 &p_morph_value, + const Vector3 &p_morph_normal) { + + ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved."); + + if (p_normals.has(p_vertex)) { + p_surface_tool->add_normal(p_normals[p_vertex] + p_morph_normal); + } + + if (p_uvs_0.has(p_vertex)) { + // Inverts Y UV. + p_surface_tool->add_uv(Vector2(p_uvs_0[p_vertex].x, 1 - p_uvs_0[p_vertex].y)); + } + + if (p_uvs_1.has(p_vertex)) { + // Inverts Y UV. + p_surface_tool->add_uv2(Vector2(p_uvs_1[p_vertex].x, 1 - p_uvs_1[p_vertex].y)); + } + + if (p_colors.has(p_vertex)) { + p_surface_tool->add_color(p_colors[p_vertex]); + } + + // TODO what about binormals? + // TODO there is other? + + gen_weight_info(p_surface_tool, p_vertex); + + // The surface tool want the vertex position as last thing. + p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale); +} + +void FBXMeshData::triangulate_polygon(Ref st, Vector p_polygon_vertex, const Vector p_surface_vertex_map, const std::vector &p_vertices) const { + const int polygon_vertex_count = p_polygon_vertex.size(); + if (polygon_vertex_count == 1) { + // point to triangle + st->add_index(p_polygon_vertex[0]); + st->add_index(p_polygon_vertex[0]); + st->add_index(p_polygon_vertex[0]); + return; + } else if (polygon_vertex_count == 2) { + // line to triangle + st->add_index(p_polygon_vertex[1]); + st->add_index(p_polygon_vertex[1]); + st->add_index(p_polygon_vertex[0]); + return; + } else if (polygon_vertex_count == 3) { + // triangle to triangle + st->add_index(p_polygon_vertex[0]); + st->add_index(p_polygon_vertex[1]); + st->add_index(p_polygon_vertex[2]); + return; + } else if (polygon_vertex_count == 4) { + // quad to triangle + st->add_index(p_polygon_vertex[0]); + st->add_index(p_polygon_vertex[1]); + st->add_index(p_polygon_vertex[2]); + st->add_index(p_polygon_vertex[2]); + st->add_index(p_polygon_vertex[3]); + st->add_index(p_polygon_vertex[0]); + return; + } else { + // non triangulated - we must run the triangulation algorithm + bool is_simple_convex = false; + + // Doesn't allow for bigger polygons because those are unlikely be convex + if (polygon_vertex_count <= 6) { + // Start from true, check if it's false. + is_simple_convex = true; + Vector3 first_vec; + for (int i = 0; i < polygon_vertex_count; i += 1) { + const Vector3 p1 = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]]; + const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]]; + const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]]; + + const Vector3 edge1 = p1 - p2; + const Vector3 edge2 = p3 - p2; + + const Vector3 res = edge1.normalized().cross(edge2.normalized()).normalized(); + if (i == 0) { + first_vec = res; + } else { + if (first_vec.dot(res) < 0.0) { + // Ok we found an angle that is not the same dir of the + // others. + is_simple_convex = false; + break; + } + } + } + } + + if (is_simple_convex) { + // This is a convex polygon, so just triangulate it. + for (int i = 0; i < (polygon_vertex_count - 2); i += 1) { + st->add_index(p_polygon_vertex[2 + i]); + st->add_index(p_polygon_vertex[1 + i]); + st->add_index(p_polygon_vertex[0]); + } + return; + } + } + + { + // This is a concave polygon. + + std::vector poly_vertices(polygon_vertex_count); + for (int i = 0; i < polygon_vertex_count; i += 1) { + poly_vertices[i] = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]]; + } + + const Vector3 poly_norm = get_poly_normal(poly_vertices); + if (poly_norm.length_squared() <= CMP_EPSILON) { + ERR_FAIL_COND_MSG(poly_norm.length_squared() <= CMP_EPSILON, "The normal of this poly was not computed. Is this FBX file corrupted."); + } + + // Select the plan coordinate. + int axis_1_coord = 0; + int axis_2_coord = 1; + { + real_t inv = poly_norm.z; + + const real_t axis_x = ABS(poly_norm.x); + const real_t axis_y = ABS(poly_norm.y); + const real_t axis_z = ABS(poly_norm.z); + + if (axis_x > axis_y) { + if (axis_x > axis_z) { + // For the most part the normal point toward X. + axis_1_coord = 1; + axis_2_coord = 2; + inv = poly_norm.x; + } + } else if (axis_y > axis_z) { + // For the most part the normal point toward Y. + axis_1_coord = 2; + axis_2_coord = 0; + inv = poly_norm.y; + } + + // Swap projection axes to take the negated projection vector into account + if (inv < 0.0f) { + SWAP(axis_1_coord, axis_2_coord); + } + } + + TriangulatorPoly triangulator_poly; + triangulator_poly.Init(polygon_vertex_count); + std::vector projected_vertices(polygon_vertex_count); + for (int i = 0; i < polygon_vertex_count; i += 1) { + const Vector2 pv(poly_vertices[i][axis_1_coord], poly_vertices[i][axis_2_coord]); + projected_vertices[i] = pv; + triangulator_poly.GetPoint(i) = pv; + } + triangulator_poly.SetOrientation(TRIANGULATOR_CCW); + + List out_poly; + + TriangulatorPartition triangulator_partition; + if (triangulator_partition.Triangulate_OPT(&triangulator_poly, &out_poly) == 0) { // Good result. + if (triangulator_partition.Triangulate_EC(&triangulator_poly, &out_poly) == 0) { // Medium result. + if (triangulator_partition.Triangulate_MONO(&triangulator_poly, &out_poly) == 0) { // Really poor result. + ERR_FAIL_MSG("The triangulation of this polygon failed, please try to triangulate your mesh or check if it has broken polygons."); + } + } + } + + std::vector tris(out_poly.size()); + for (List::Element *I = out_poly.front(); I; I = I->next()) { + TriangulatorPoly &tp = I->get(); + + ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator retuned more points, how this is possible?"); + // Find Index + for (int i = 2; i >= 0; i -= 1) { + const Vector2 vertex = tp.GetPoint(i); + bool done = false; + // Find Index + for (int y = 0; y < polygon_vertex_count; y += 1) { + if ((projected_vertices[y] - vertex).length_squared() <= CMP_EPSILON) { + // This seems the right vertex + st->add_index(p_polygon_vertex[y]); + done = true; + break; + } + } + ERR_FAIL_COND(done == false); + } + } + } +} + +void FBXMeshData::gen_weight_info(Ref st, Vertex vertex_id) const { + if (vertex_weights.empty()) { + return; + } + + if (vertex_weights.has(vertex_id)) { + // Let's extract the weight info. + const VertexMapping *vm = vertex_weights.getptr(vertex_id); + st->add_weights(vm->weights); + st->add_bones(vm->bones); + print_verbose("[doc] Triangle added weights to mesh for bones"); + } else { + // This vertex doesn't have any bone info, while the model is using the + // bones. + // So nothing more to do. + } + + print_verbose("[doc] Triangle added weights to mesh for bones"); +} + +int FBXMeshData::get_vertex_from_polygon_vertex(const std::vector &p_polygon_indices, int p_index) const { + if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { + return -1; + } + + const int vertex = p_polygon_indices[p_index]; + if (vertex >= 0) { + return vertex; + } else { + // Negative numbers are the end of the face, reversing the bits is + // possible to obtain the positive correct vertex number. + return ~vertex; + } +} + +bool FBXMeshData::is_end_of_polygon(const std::vector &p_polygon_indices, int p_index) const { + if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { + return false; + } + + const int vertex = p_polygon_indices[p_index]; + + // If the index is negative this is the end of the Polygon. + return vertex < 0; +} + +bool FBXMeshData::is_start_of_polygon(const std::vector &p_polygon_indices, int p_index) const { + if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { + return false; + } + + if (p_index == 0) { + return true; + } + + // If the previous indices is negative this is the begin of a new Polygon. + return p_polygon_indices[p_index - 1] < 0; +} + +int FBXMeshData::count_polygons(const std::vector &p_polygon_indices) const { + // The negative numbers define the end of the polygon. Counting the amount of + // negatives the numbers of polygons are obtained. + int count = 0; + for (size_t i = 0; i < p_polygon_indices.size(); i += 1) { + if (p_polygon_indices[i] < 0) { + count += 1; + } + } + return count; +} + +template +HashMap FBXMeshData::extract_per_vertex_data( + int p_vertex_count, + const std::vector &p_edge_map, + const std::vector &p_polygon_indices, + const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, + R (*collector_function)(const Vector > *p_vertex_data, R p_fall_back), + R p_fall_back) const { + + ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); + + // Aggregate vertex data. + HashMap > > aggregate_vertex_data; + + switch (p_fbx_data.map_type) { + case Assimp::FBX::MeshGeometry::MapType::none: { + // No data nothing to do. + return (HashMap()); + } + case Assimp::FBX::MeshGeometry::MapType::vertex: { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + // The data is mapped per vertex directly. + ERR_FAIL_COND_V_MSG((int)p_fbx_data.data.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR01"); + for (size_t vertex_index = 0; vertex_index < p_fbx_data.data.size(); vertex_index += 1) { + aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[vertex_index] }); + } + } else { + // The data is mapped per vertex using a reference. + // The indices array, contains a *reference_id for each vertex. + // * Note that the reference_id is the id of data into the data array. + // + // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html + ERR_FAIL_COND_V_MSG((int)p_fbx_data.index.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR02"); + for (size_t vertex_index = 0; vertex_index < p_fbx_data.index.size(); vertex_index += 1) { + ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[vertex_index], (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR03.") + aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[p_fbx_data.index[vertex_index]] }); + } + } + } break; + case Assimp::FBX::MeshGeometry::MapType::polygon_vertex: { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + // The data are mapped per polygon vertex directly. + ERR_FAIL_COND_V_MSG((int)p_polygon_indices.size() != (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR04"); + int polygon_id = -1; + for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_fbx_data.data.size(); polygon_vertex_index += 1) { + if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + polygon_id += 1; + } + const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap()), "FBX file corrupted: #ERR05"); + ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap()), "FBX file corrupted: #ERR06"); + + aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_fbx_data.data[polygon_vertex_index] }); + } + } else { + // The data is mapped per polygon_vertex using a reference. + // The indices array, contains a *reference_id for each polygon_vertex. + // * Note that the reference_id is the id of data into the data array. + // + // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html + ERR_FAIL_COND_V_MSG(p_polygon_indices.size() != p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR7"); + int polygon_id = -1; + for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_fbx_data.index.size(); polygon_vertex_index += 1) { + if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + polygon_id += 1; + } + const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap()), "FBX file corrupted: #ERR8"); + ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap()), "FBX file seems corrupted: #ERR9.") + ERR_FAIL_COND_V_MSG(p_fbx_data.index[polygon_vertex_index] < 0, (HashMap()), "FBX file seems corrupted: #ERR10.") + ERR_FAIL_COND_V_MSG(p_fbx_data.index[polygon_vertex_index] >= (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR11.") + aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_fbx_data.data[p_fbx_data.index[polygon_vertex_index]] }); + } + } + } break; + case Assimp::FBX::MeshGeometry::MapType::polygon: { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + // The data are mapped per polygon directly. + const int polygon_count = count_polygons(p_polygon_indices); + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR12"); + + // Advance each polygon vertex, each new polygon advance the polygon index. + int polygon_index = -1; + for (size_t polygon_vertex_index = 0; + polygon_vertex_index < p_polygon_indices.size(); + polygon_vertex_index += 1) { + + if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + polygon_index += 1; + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR13"); + } + + const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR14"); + + aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_fbx_data.data[polygon_index] }); + } + ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap()), "FBX file seems corrupted: #ERR16. Not all Polygons are present in the file.") + } else { + // The data is mapped per polygon using a reference. + // The indices array, contains a *reference_id for each polygon. + // * Note that the reference_id is the id of data into the data array. + // + // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html + const int polygon_count = count_polygons(p_polygon_indices); + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR17"); + + // Advance each polygon vertex, each new polygon advance the polygon index. + int polygon_index = -1; + for (size_t polygon_vertex_index = 0; + polygon_vertex_index < p_polygon_indices.size(); + polygon_vertex_index += 1) { + + if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + polygon_index += 1; + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR18"); + ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR19"); + } + + const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR20"); + + aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_fbx_data.data[p_fbx_data.index[polygon_index]] }); + } + ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap()), "FBX file seems corrupted: #ERR22. Not all Polygons are present in the file.") + } + } break; + case Assimp::FBX::MeshGeometry::MapType::edge: { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + // The data are mapped per edge directly. + ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR23"); + for (size_t edge_index = 0; edge_index < p_fbx_data.data.size(); edge_index += 1) { + const Assimp::FBX::MeshGeometry::Edge edge = Assimp::FBX::MeshGeometry::get_edge(p_edge_map, edge_index); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR24"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR25"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR26"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR27"); + aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_fbx_data.data[edge_index] }); + aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_fbx_data.data[edge_index] }); + } + } else { + // The data is mapped per edge using a reference. + // The indices array, contains a *reference_id for each polygon. + // * Note that the reference_id is the id of data into the data array. + // + // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html + ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR28"); + for (size_t edge_index = 0; edge_index < p_fbx_data.data.size(); edge_index += 1) { + const Assimp::FBX::MeshGeometry::Edge edge = Assimp::FBX::MeshGeometry::get_edge(p_edge_map, edge_index); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR29"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR30"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR31"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR32"); + ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[edge.vertex_0], (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR33"); + ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[edge.vertex_1], (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR34"); + aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_fbx_data.data[p_fbx_data.index[edge_index]] }); + aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_fbx_data.data[p_fbx_data.index[edge_index]] }); + } + } + } break; + case Assimp::FBX::MeshGeometry::MapType::all_the_same: { + // No matter the mode, no matter the data size; The first always win + // and is set to all the vertices. + ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap()), "FBX file seems corrupted: #ERR35"); + if (p_fbx_data.data.size() > 0) { + for (int vertex_index = 0; vertex_index < p_vertex_count; vertex_index += 1) { + aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[0] }); + } + } + } break; + } + + if (aggregate_vertex_data.size() == 0) { + return (HashMap()); + } + + // A map is used because turns out that the some FBX file are not well organized + // with vertices well compacted. Using a map allows avoid those issues. + HashMap result; + + // Aggregate the collected data. + for (const Vertex *index = aggregate_vertex_data.next(nullptr); index != nullptr; index = aggregate_vertex_data.next(index)) { + Vector > *aggregated_vertex = aggregate_vertex_data.getptr(*index); + // This can't be null because we are just iterating. + CRASH_COND(aggregated_vertex == nullptr); + + ERR_FAIL_INDEX_V_MSG(0, aggregated_vertex->size(), (HashMap()), "The FBX file is corrupted, No valid data for this vertex index."); + result[*index] = collector_function(aggregated_vertex, p_fall_back); + } + + // Sanitize the data now, if the file is broken we can try import it anyway. + bool problem_found = false; + for (size_t i = 0; i < p_polygon_indices.size(); i += 1) { + const Vertex vertex = get_vertex_from_polygon_vertex(p_polygon_indices, i); + if (result.has(vertex) == false) { + result[vertex] = p_fall_back; + problem_found = true; + } + } + if (problem_found) { + WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN0."); + } + + return result; +} + +template +HashMap FBXMeshData::extract_per_polygon( + int p_vertex_count, + const std::vector &p_polygon_indices, + const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, + T p_fallback_value) const { + + ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); + + const int polygon_count = count_polygons(p_polygon_indices); + + // Aggregate vertex data. + HashMap > aggregate_polygon_data; + + switch (p_fbx_data.map_type) { + case Assimp::FBX::MeshGeometry::MapType::none: { + // No data nothing to do. + return (HashMap()); + } + case Assimp::FBX::MeshGeometry::MapType::vertex: { + ERR_FAIL_V_MSG((HashMap()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per vertex. This should not happen."); + } break; + case Assimp::FBX::MeshGeometry::MapType::polygon_vertex: { + ERR_FAIL_V_MSG((HashMap()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per polygon vertex. This should not happen."); + } break; + case Assimp::FBX::MeshGeometry::MapType::polygon: { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + // The data are mapped per polygon directly. + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap()), "FBX file is corrupted: #ERR51"); + + // Advance each polygon vertex, each new polygon advance the polygon index. + for (int polygon_index = 0; + polygon_index < polygon_count; + polygon_index += 1) { + + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap()), "FBX file is corrupted: #ERR52"); + aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); + } + } else { + // The data is mapped per polygon using a reference. + // The indices array, contains a *reference_id for each polygon. + // * Note that the reference_id is the id of data into the data array. + // + // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR52"); + + // Advance each polygon vertex, each new polygon advance the polygon index. + for (int polygon_index = 0; + polygon_index < polygon_count; + polygon_index += 1) { + + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap()), "FBX file is corrupted: #ERR53"); + ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap()), "FBX file is corrupted: #ERR54"); + aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[p_fbx_data.index[polygon_index]]); + } + } + } break; + case Assimp::FBX::MeshGeometry::MapType::edge: { + ERR_FAIL_V_MSG((HashMap()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per edge. This should not happen."); + } break; + case Assimp::FBX::MeshGeometry::MapType::all_the_same: { + // No matter the mode, no matter the data size; The first always win + // and is set to all the vertices. + ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap()), "FBX file seems corrupted: #ERR55"); + if (p_fbx_data.data.size() > 0) { + for (int polygon_index = 0; polygon_index < polygon_count; polygon_index += 1) { + aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[0]); + } + } + } break; + } + + if (aggregate_polygon_data.size() == 0) { + return (HashMap()); + } + + // A map is used because turns out that the some FBX file are not well organized + // with vertices well compacted. Using a map allows avoid those issues. + HashMap polygons; + + // Take the first value for each vertex. + for (const Vertex *index = aggregate_polygon_data.next(nullptr); index != nullptr; index = aggregate_polygon_data.next(index)) { + Vector *aggregated_polygon = aggregate_polygon_data.getptr(*index); + // This can't be null because we are just iterating. + CRASH_COND(aggregated_polygon == nullptr); + + ERR_FAIL_INDEX_V_MSG(0, (int)aggregated_polygon->size(), (HashMap()), "The FBX file is corrupted, No valid data for this polygon index."); + + // Validate the final value. + polygons[*index] = (*aggregated_polygon)[0]; + } + + // Sanitize the data now, if the file is broken we can try import it anyway. + bool problem_found = false; + for (int polygon_i = 0; polygon_i < polygon_count; polygon_i += 1) { + if (polygons.has(polygon_i) == false) { + polygons[polygon_i] = p_fallback_value; + problem_found = true; + } + } + if (problem_found) { + WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN1."); + } + + return polygons; +} + +void FBXMeshData::extract_morphs(const Assimp::FBX::MeshGeometry *mesh_geometry, HashMap &r_data) { + + r_data.clear(); + + const int vertex_count = mesh_geometry->get_vertices().size(); + + for (const Assimp::FBX::BlendShape *blend_shape : mesh_geometry->get_blend_shapes()) { + for (const Assimp::FBX::BlendShapeChannel *blend_shape_channel : blend_shape->BlendShapeChannels()) { + const std::vector &shape_geometries = blend_shape_channel->GetShapeGeometries(); + for (const Assimp::FBX::ShapeGeometry *shape_geometry : shape_geometries) { + + String morph_name = ImportUtils::FBXAnimMeshName(shape_geometry->Name()).c_str(); + if (morph_name.empty()) { + morph_name = "morph"; + } + + // TODO we have only these?? + const std::vector &morphs_vertex_indices = shape_geometry->GetIndices(); + const std::vector &morphs_vertices = shape_geometry->GetVertices(); + const std::vector &morphs_normals = shape_geometry->GetNormals(); + + ERR_FAIL_COND_MSG((int)morphs_vertex_indices.size() > vertex_count, "The FBX file is corrupted: #ERR103"); + ERR_FAIL_COND_MSG(morphs_vertex_indices.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR104"); + ERR_FAIL_COND_MSG((int)morphs_vertices.size() > vertex_count, "The FBX file is corrupted: #ERR105"); + ERR_FAIL_COND_MSG(morphs_normals.size() != 0 && morphs_normals.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR106"); + + if (r_data.has(morph_name) == false) { + // This morph doesn't exist yet. + // Create it. + MorphVertexData md; + md.vertices.resize(vertex_count); + md.normals.resize(vertex_count); + r_data.set(morph_name, md); + } + + MorphVertexData *data = r_data.getptr(morph_name); + Vector3 *data_vertices_ptr = data->vertices.ptrw(); + Vector3 *data_normals_ptr = data->normals.ptrw(); + + for (int i = 0; i < (int)morphs_vertex_indices.size(); i += 1) { + const Vertex vertex = morphs_vertex_indices[i]; + + ERR_FAIL_INDEX_MSG(vertex, vertex_count, "The blend shapes of this FBX file are corrupted. It has a not valid vertex."); + + data_vertices_ptr[vertex] = morphs_vertices[i]; + + if (morphs_normals.size() != 0) { + data_normals_ptr[vertex] = morphs_normals[i]; + } + } + } + } + } +} diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h new file mode 100644 index 000000000000..6604902573b6 --- /dev/null +++ b/modules/fbx/data/fbx_mesh_data.h @@ -0,0 +1,327 @@ +/*************************************************************************/ +/* fbx_mesh_data.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_FBX_MESH_DATA_H +#define EDITOR_SCENE_FBX_MESH_DATA_H + +#include "core/hash_map.h" +#include "fbx_bone.h" +#include "import_state.h" +#include "modules/fbx/tools/import_utils.h" +#include "scene/3d/mesh_instance.h" +#include "scene/resources/surface_tool.h" +#include "thirdparty/assimp_fbx/FBXMeshGeometry.h" + +struct FBXMeshData; +struct FBXBone; +struct ImportState; + +struct FBXSplitBySurfaceVertexMapping { + // Original Mesh Data + Map vertex_with_id = Map(); + Vector uv_0, uv_1 = Vector(); + Vector normals = Vector(); + Vector colors = Vector(); + + void add_uv_0(Vector2 vec) { + vec.y = 1.0f - vec.y; + //print_verbose("added uv_0 " + vec); + uv_0.push_back(vec); + } + + void add_uv_1(Vector2 vec) { + vec.y = 1.0f - vec.y; + uv_1.push_back(vec); + } + + Vector3 get_normal(int vertex_id, bool &found) const { + found = false; + if (vertex_id < normals.size()) { + found = true; + return normals[vertex_id]; + } + return Vector3(); + } + + Color get_colors(int vertex_id, bool &found) const { + found = false; + if (vertex_id < colors.size()) { + found = true; + return colors[vertex_id]; + } + return Color(); + } + + Vector2 get_uv_0(int vertex_id, bool &found) const { + found = false; + if (vertex_id < uv_0.size()) { + found = true; + return uv_0[vertex_id]; + } + return Vector2(); + } + + Vector2 get_uv_1(int vertex_id, bool &found) const { + found = false; + if (vertex_id < uv_1.size()) { + found = true; + return uv_1[vertex_id]; + } + return Vector2(); + } + + void GenerateIndices(Ref st, uint32_t mesh_face_count) const { + // todo: can we remove the split by primitive type so it's only material + // todo: implement the fbx poly mapping thing here + // todo: convert indices to the godot format + switch (mesh_face_count) { + case 1: // todo: validate this + for (int x = 0; x < vertex_with_id.size(); x += 1) { + st->add_index(x); + st->add_index(x); + st->add_index(x); + } + break; + case 2: // todo: validate this + for (int x = 0; x < vertex_with_id.size(); x += 2) { + st->add_index(x + 1); + st->add_index(x + 1); + st->add_index(x); + } + break; + case 3: { + // triangle only + for (int x = 0; x < vertex_with_id.size(); x += 3) { + st->add_index(x + 2); + st->add_index(x + 1); + st->add_index(x); + } + } break; + case 4: { + // quad conversion to triangle + for (int x = 0; x < vertex_with_id.size(); x += 4) { + // complete first side of triangle + + // todo: unfuck this + st->add_index(x + 2); + st->add_index(x + 1); + st->add_index(x); + + // complete second side of triangle + + // top right + // bottom right + // top left + + // first triangle is + // (x+2), (x+1), (x) + // second triangle is + // (x+2), (x), (x+3) + + st->add_index(x + 2); + st->add_index(x); + st->add_index(x + 3); + + // anti clockwise rotation in indices + // note had to reverse right from left here + // [0](x) bottom right (-1,-1) + // [1](x+1) bottom left (1,-1) + // [2](x+2) top left (1,1) + // [3](x+3) top right (-1,1) + + // we have 4 points + // we have 2 triangles + // we have CCW + } + } break; + default: + print_error("number is not implemented!"); + break; + } + } + + void GenerateSurfaceMaterial(Ref st, size_t vertex_id) const { + bool uv_0 = false; + bool uv_1 = false; + bool normal_found = false; + bool color_found = false; + Vector2 uv_0_vec = get_uv_0(vertex_id, uv_0); + Vector2 uv_1_vec = get_uv_1(vertex_id, uv_1); + Vector3 normal = get_normal(vertex_id, normal_found); + Color color = get_colors(vertex_id, color_found); + if (uv_0) { + //print_verbose("added uv_0 st " + uv_0_vec); + st->add_uv(uv_0_vec); + } + if (uv_1) { + //print_verbose("added uv_1 st " + uv_1_vec); + st->add_uv2(uv_1_vec); + } + + if (normal_found) { + st->add_normal(normal); + } + + if (color_found) { + st->add_color(color); + } + } +}; + +// TODO reneme to VertexWeightMapping +struct VertexMapping { + Vector weights; + Vector 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 > bones_ref; +}; + +template +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 vertices; + /// Each element is a vertex. Not supposed to be void. + Vector normals; + }; + + /// vertex id, Weight Info + /// later: perf we can use array here + HashMap 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 Assimp::FBX::MeshGeometry *mesh_geometry, const Assimp::FBX::Model *model); + + void gen_weight_info(Ref st, int vertex_id) const; + + /* mesh maximum weight count */ + bool valid_weight_count = false; + int max_weight_count = 0; + uint64_t mesh_id = 0; // fbx mesh id + uint64_t armature_id = 0; + bool valid_armature_id = false; + MeshInstance *godot_mesh_instance = nullptr; + +private: + void sanitize_vertex_weights(); + + /// 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 &r_polygon_indices, + std::vector &r_vertices, + HashMap &r_normals, + HashMap &r_uv_1, + HashMap &r_uv_2, + HashMap &r_color, + HashMap &r_morphs, + HashMap > &r_uv_1_raw, + HashMap > &r_uv_2_raw); + + void add_vertex( + Ref p_surface_tool, + real_t p_scale, + int p_vertex, + const std::vector &p_vertices_position, + const HashMap &p_normals, + const HashMap &p_uvs_0, + const HashMap &p_uvs_1, + const HashMap &p_colors, + const Vector3 &p_morph_value = Vector3(), + const Vector3 &p_morph_normal = Vector3()); + + void triangulate_polygon(Ref st, Vector p_polygon_vertex, Vector p_surface_vertex_map, const std::vector &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 poligon vertex. + /// Returns -1 if `p_index` is invalid. + int get_vertex_from_polygon_vertex(const std::vector &p_face_indices, int p_index) const; + + /// Retuns true if this polygon_vertex_index is the end of a new polygon. + bool is_end_of_polygon(const std::vector &p_face_indices, int p_index) const; + + /// Retuns true if this polygon_vertex_index is the begin of a new polygon. + bool is_start_of_polygon(const std::vector &p_face_indices, int p_index) const; + + /// Returns the number of polygons. + int count_polygons(const std::vector &p_face_indices) const; + + /// Used to extract data from the `MappingData` alligned with vertex. + /// Useful to extract normal/uvs/colors/tangets/etc... + /// If the function fails somehow, it returns an hollow vector and print an error. + template + HashMap extract_per_vertex_data( + int p_vertex_count, + const std::vector &p_edges, + const std::vector &p_face_indices, + const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, + R (*collector_function)(const Vector > *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 materila + /// If the function fails somehow, it returns an hollow vector and print an error. + template + HashMap extract_per_polygon( + int p_vertex_count, + const std::vector &p_face_indices, + const Assimp::FBX::MeshGeometry::MappingData &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 Assimp::FBX::MeshGeometry *mesh_geometry, HashMap &r_data); +}; + +#endif // EDITOR_SCENE_FBX_MESH_DATA_H diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h new file mode 100644 index 000000000000..fd9fb3c1a64a --- /dev/null +++ b/modules/fbx/data/fbx_node.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* fbx_node.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_FBX_NODE_H +#define MODEL_ABSTRACTION_FBX_NODE_H + +#include "fbx_skeleton.h" +#include "model_abstraction.h" +#include "pivot_transform.h" +#include "thirdparty/assimp_fbx/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 skeleton_node = Ref(); + + void set_parent(Ref p_parent) { + fbx_parent = p_parent; + } + + void set_pivot_transform(Ref p_pivot_transform) { + pivot_transform = p_pivot_transform; + } + + Ref pivot_transform = Ref(); // local and global xform data + Ref fbx_parent = Ref(); // parent node +}; + +#endif // MODEL_ABSTRACTION_FBX_NODE_H diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp new file mode 100644 index 000000000000..3aeafeaf668f --- /dev/null +++ b/modules/fbx/data/fbx_skeleton.cpp @@ -0,0 +1,123 @@ +/*************************************************************************/ +/* fbx_skeleton.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "modules/fbx/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); + + Ref skeleton_parent_node; + 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(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); + 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 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; y < skeleton_bone_count; y++) { + Ref 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 > 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 bone = skeleton_bones[x]; + if (bone.is_valid()) { + skeleton->add_bone(bone->bone_name); + bone->godot_bone_id = bone_count; + bone->fbx_skeleton = Ref(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 >::Element *bone_element = bone_map.front(); bone_element; bone_element = bone_element->next()) { + Ref 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->pivot_xform->LocalTransform, state.scale)); + skeleton->set_bone_pose(bone->godot_bone_id, get_unscaled_transform(bone->pose_node, state.scale)); + // lookup parent ID + if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) { + Ref 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 + } + } + } +} diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h new file mode 100644 index 000000000000..62b6afddb6bf --- /dev/null +++ b/modules/fbx/data/fbx_skeleton.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* fbx_skeleton.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_FBX_SKELETON_H +#define EDITOR_SCENE_FBX_SKELETON_H + +#include "core/reference.h" +#include "fbx_bone.h" +#include "fbx_node.h" +#include "model_abstraction.h" +#include "scene/3d/skeleton.h" + +struct FBXNode; +struct ImportState; +struct FBXBone; + +struct FBXSkeleton : Reference, ModelAbstraction { + Ref fbx_node = Ref(); + Vector > skeleton_bones = Vector >(); + Skeleton *skeleton = nullptr; + + void init_skeleton(const ImportState &state); +}; + +#endif // EDITOR_SCENE_FBX_SKELETON_H diff --git a/modules/assimp/import_state.h b/modules/fbx/data/import_state.h similarity index 52% rename from modules/assimp/import_state.h rename to modules/fbx/data/import_state.h index f8a0f0abb443..55f786a5fba2 100644 --- a/modules/assimp/import_state.h +++ b/modules/fbx/data/import_state.h @@ -31,6 +31,10 @@ #ifndef EDITOR_SCENE_IMPORT_STATE_H #define EDITOR_SCENE_IMPORT_STATE_H +#include "fbx_mesh_data.h" +#include "modules/fbx/tools/import_utils.h" +#include "pivot_transform.h" + #include "core/bind/core_bind.h" #include "core/io/resource_importer.h" #include "core/vector.h" @@ -43,91 +47,64 @@ #include "scene/resources/animation.h" #include "scene/resources/surface_tool.h" -#include -#include -#include -#include -#include -#include - -namespace AssimpImporter { -/** Import state is for global scene import data - * This makes the code simpler and contains useful lookups. - */ -struct ImportState { +#include "thirdparty/assimp_fbx/FBXDocument.h" +#include "thirdparty/assimp_fbx/FBXImportSettings.h" +#include "thirdparty/assimp_fbx/FBXMeshGeometry.h" +#include "thirdparty/assimp_fbx/FBXParser.h" +#include "thirdparty/assimp_fbx/FBXTokenizer.h" +#include "thirdparty/assimp_fbx/FBXUtil.h" - String path; - Spatial *root; - const aiScene *assimp_scene; - uint32_t max_bone_weights; +struct FBXBone; +struct FBXMeshData; +struct FBXNode; +struct FBXSkeleton; - Map > mesh_cache; - Map > material_cache; - Map light_cache; - Map camera_cache; +struct ImportState { + bool enable_material_import = false; + bool enable_animation_import = false; - // very useful for when you need to ask assimp for the bone mesh + Map > cached_image_searches; + Map > cached_materials; - Map assimp_node_map; - Map > path_to_image_cache; + String path = String(); + Spatial *root_owner = nullptr; + Spatial *root = nullptr; + real_t scale = 0.01; + Ref fbx_root_node = Ref(); + // skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically. + Map > skeleton_map = Map >(); - // Generation 3 - determinisitic iteration - // to lower potential recursion errors - List nodes; - Map flat_node_map; - AnimationPlayer *animation_player; + // nodes on the same level get merged automatically. + //Map armature_map; + AnimationPlayer *animation_player = nullptr; - // Generation 3 - deterministic armatures - // list of armature nodes - flat and simple to parse - // assimp node, node in godot - List armature_nodes; - Map armature_skeletons; - Map skeleton_bone_map; - // Generation 3 - deterministic bone handling - // bones from the stack are popped when found - // this means we can detect - // what bones are for other armatures - List bone_stack; + // 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 > fbx_bone_map = Map >(); // this is the bone name and setup information required for joints + // this will never contain joints only bones attached to a mesh. - // EditorSceneImporter::ImportFlags - uint32_t import_flags; -}; + // 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 > fbx_node_list = List >(); -struct AssimpImageData { - Ref raw_image; - Ref texture; - aiTextureMapMode map_mode[2]; -}; + // All nodes which have been created in the scene + // this will not contain the root node of the scene + Map > fbx_target_map = Map >(); -/** Recursive state is used to push state into functions instead of specifying them - * This makes the code easier to handle too and add extra arguments without breaking things - */ -struct RecursiveState { - RecursiveState() {} // do not construct :) - RecursiveState( - Transform &_node_transform, - Skeleton *_skeleton, - Spatial *_new_node, - String &_node_name, - aiNode *_assimp_node, - Node *_parent_node, - aiBone *_bone) : - node_transform(_node_transform), - skeleton(_skeleton), - new_node(_new_node), - node_name(_node_name), - assimp_node(_assimp_node), - parent_node(_parent_node), - bone(_bone) {} + // mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins + Map > MeshNodes = Map >(); + // mesh skin map + Map > MeshSkins = Map >(); - Transform node_transform; - Skeleton *skeleton = NULL; - Spatial *new_node = NULL; - String node_name; - aiNode *assimp_node = NULL; - Node *parent_node = NULL; - aiBone *bone = NULL; + // 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 > renderer_mesh_data = Map >(); }; -} // namespace AssimpImporter #endif // EDITOR_SCENE_IMPORT_STATE_H diff --git a/modules/fbx/data/model_abstraction.h b/modules/fbx/data/model_abstraction.h new file mode 100644 index 000000000000..50a2b5aa3f57 --- /dev/null +++ b/modules/fbx/data/model_abstraction.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* model_abstraction.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_FBX_IMPORTER_H +#define MODEL_ABSTRACTION_FBX_IMPORTER_H + +#include "thirdparty/assimp_fbx/FBXDocument.h" + +struct ModelAbstraction { + mutable const Assimp::FBX::Model *fbx_model = nullptr; + + void set_model(const Assimp::FBX::Model *p_model) { + fbx_model = p_model; + } + + bool has_model() const { + return fbx_model != nullptr; + } + + const Assimp::FBX::Model *get_model() const { + return fbx_model; + } +}; + +#endif // MODEL_ABSTRACTION_FBX_IMPORTER_H diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp new file mode 100644 index 000000000000..48fd3dbc5969 --- /dev/null +++ b/modules/fbx/data/pivot_transform.cpp @@ -0,0 +1,250 @@ +/*************************************************************************/ +/* pivot_transform.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "modules/fbx/tools/import_utils.h" + +void PivotTransform::ReadTransformChain() { + const Assimp::FBX::PropertyTable &props = fbx_model->Props(); + const Assimp::FBX::Model::RotOrder &rot = fbx_model->RotationOrder(); + const Assimp::FBX::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(Assimp::FBX::PropertyGet(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(Assimp::FBX::PropertyGet(props, "PostRotation", ok)); + if (ok) { + post_rotation = ImportUtils::EulerToQuaternion(Assimp::FBX::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(Assimp::FBX::PropertyGet(props, "RotationPivot", ok)); + if (ok) { + rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot); + } + const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "RotationOffset", ok)); + if (ok) { + rotation_offset = ImportUtils::FixAxisConversions(RotationOffset); + } + const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "ScalingOffset", ok)); + if (ok) { + scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset); + } + const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "ScalingPivot", ok)); + if (ok) { + scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot); + } + const Vector3 &Translation = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "Lcl Translation", ok)); + if (ok) { + translation = ImportUtils::FixAxisConversions(Translation); + } + raw_rotation = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "Lcl Rotation", ok)); + if (ok) { + rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation)); + } + const Vector3 &Scaling = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "Lcl Scaling", ok)); + if (ok) { + scaling = Scaling; + } + const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "GeometricScaling", ok)); + if (ok) { + geometric_scaling = GeometricScaling; + } + const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "GeometricRotation", ok)); + if (ok) { + geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation)); + } + const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(Assimp::FBX::PropertyGet(props, "GeometricTranslation", ok)); + if (ok) { + geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation); + } +} + +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(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 == Assimp::FBX::Transform_RrSs) { + global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; + } else if (inherit_type == Assimp::FBX::Transform_RSrs) { + global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; + } else if (inherit_type == Assimp::FBX::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 + S.scale(scaling); + 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 == Assimp::FBX::Transform_RrSs) { + global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; + } else if (inherit_type == Assimp::FBX::Transform_RSrs) { + global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; + } else if (inherit_type == Assimp::FBX::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(); + + 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; +} diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h new file mode 100644 index 000000000000..f9d8f1d52c92 --- /dev/null +++ b/modules/fbx/data/pivot_transform.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* pivot_transform.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_PIVOT_TRANSFORM_H +#define MODEL_ABSTRACTION_PIVOT_TRANSFORM_H + +#include "core/reference.h" +#include "model_abstraction.h" +#include "modules/fbx/tools/import_utils.h" +#include "thirdparty/assimp_fbx/FBXDocument.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(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 p_parent) { + parent_transform = p_parent; + } + bool computed_global_xform = false; + Ref parent_transform = Ref(); + //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 + Assimp::FBX::TransformInheritance inherit_type = Assimp::FBX::TransformInheritance_MAX; // maya fbx requires this - sorry <3 +}; + +#endif // MODEL_ABSTRACTION_PIVOT_TRANSFORM_H diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp new file mode 100644 index 000000000000..c7d80c66747e --- /dev/null +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -0,0 +1,1478 @@ +/*************************************************************************/ +/* editor_scene_importer_fbx.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "editor_scene_importer_fbx.h" +#include "core/io/image_loader.h" +#include "data/fbx_anim_container.h" +#include "data/fbx_material.h" +#include "data/fbx_skeleton.h" +#include "editor/editor_log.h" +#include "editor/editor_node.h" +#include "editor/import/resource_importer_scene.h" +#include "modules/fbx/data/fbx_mesh_data.h" +#include "scene/3d/bone_attachment.h" +#include "scene/3d/camera.h" +#include "scene/3d/light.h" +#include "scene/3d/mesh_instance.h" +#include "scene/main/node.h" +#include "scene/resources/material.h" +#include "tools/import_utils.h" + +#include "thirdparty/assimp_fbx/FBXDocument.h" +#include "thirdparty/assimp_fbx/FBXImportSettings.h" +#include "thirdparty/assimp_fbx/FBXMeshGeometry.h" +#include "thirdparty/assimp_fbx/FBXParser.h" +#include "thirdparty/assimp_fbx/FBXProperties.h" +#include "thirdparty/assimp_fbx/FBXTokenizer.h" +#include + +void EditorSceneImporterFBX::get_extensions(List *r_extensions) const { + + const String import_setting_string = "filesystem/import/fbx/"; + + Map import_format; + { + Vector exts; + exts.push_back("fbx"); + ImportFormat import = { exts, true }; + import_format.insert("fbx", import); + } + + for (Map::Element *E = import_format.front(); E; E = E->next()) { + _register_project_setting_import(E->key(), import_setting_string, E->get().extensions, r_extensions, + E->get().is_default); + } +} + +void EditorSceneImporterFBX::_register_project_setting_import(const String generic, + const String import_setting_string, + const Vector &exts, + List *r_extensions, + const bool p_enabled) const { + const String use_generic = "use_" + generic; + _GLOBAL_DEF(import_setting_string + use_generic, p_enabled, true); + if (ProjectSettings::get_singleton()->get(import_setting_string + use_generic)) { + for (int32_t i = 0; i < exts.size(); i++) { + r_extensions->push_back(exts[i]); + } + } +} + +uint32_t EditorSceneImporterFBX::get_import_flags() const { + return IMPORT_SCENE; +} + +void EditorSceneImporterFBX::_bind_methods() { +} +Node *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, + List *r_missing_deps, Error *r_err) { + // done for performance when re-importing lots of files when testing importer in verbose only! + if (OS::get_singleton()->is_stdout_verbose()) { + EditorLog *log = EditorNode::get_log(); + log->clear(); + } + Error err; + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + + ERR_FAIL_COND_V(!f, NULL); + + PoolByteArray data; + // broadphase tokenizing pass in which we identify the core + // syntax elements of FBX (brackets, commas, key:value mappings) + Assimp::FBX::TokenList tokens; + + bool is_binary = false; + data.resize(f->get_len()); + f->get_buffer(data.write().ptr(), data.size()); + PoolByteArray fbx_header; + fbx_header.resize(64); + for (int32_t byte_i = 0; byte_i < 64; byte_i++) { + fbx_header.write()[byte_i] = data.read()[byte_i]; + } + + String fbx_header_string; + if (fbx_header.size() >= 0) { + PoolByteArray::Read r = fbx_header.read(); + fbx_header_string.parse_utf8((const char *)r.ptr(), fbx_header.size()); + } + + print_verbose("[doc] opening fbx file: " + p_path); + print_verbose("[doc] fbx header: " + fbx_header_string); + + // safer to check this way as there can be different formatted headers + if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) { + is_binary = true; + print_verbose("[doc] is binary"); + Assimp::FBX::TokenizeBinary(tokens, (const char *)data.write().ptr(), (size_t)data.size()); + } else { + print_verbose("[doc] is ascii"); + Assimp::FBX::Tokenize(tokens, (const char *)data.write().ptr()); + } + + // use this information to construct a very rudimentary + // parse-tree representing the FBX scope structure + Assimp::FBX::Parser parser(tokens, is_binary); + Assimp::FBX::ImportSettings settings; + + // 'strict' mode is dangerous this causes more fun asserts to crash engine, so don't enable it. + settings.strictMode = false; + + // take the raw parse-tree and convert it to a FBX DOM + Assimp::FBX::Document doc(parser, settings); + + // yeah so closing the file is a good idea (prevents readonly states) + f->close(); + + // safety for version handling + if (doc.IsSafeToImport()) { + return _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8); + } else { + print_error("Cannot import file: " + p_path + " version of file is unsupported, please re-export in your modelling package file version is: " + itos(doc.FBXVersion())); + } + + return memnew(Spatial); +} + +template +struct EditorSceneImporterAssetImportInterpolate { + + T lerp(const T &a, const T &b, float c) const { + + return a + (b - a) * c; + } + + T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { + + float t2 = t * t; + float t3 = t2 * t; + + return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); + } + + T bezier(T start, T control_1, T control_2, T end, float t) { + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = t * t; + real_t t3 = t2 * t; + + return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; + } +}; + +//thank you for existing, partial specialization +template <> +struct EditorSceneImporterAssetImportInterpolate { + + Quat lerp(const Quat &a, const Quat &b, float c) const { + ERR_FAIL_COND_V(!a.is_normalized(), Quat()); + ERR_FAIL_COND_V(!b.is_normalized(), Quat()); + + return a.slerp(b, c).normalized(); + } + + Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) { + ERR_FAIL_COND_V(!p1.is_normalized(), Quat()); + ERR_FAIL_COND_V(!p2.is_normalized(), Quat()); + + return p1.slerp(p2, c).normalized(); + } + + Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) { + ERR_FAIL_COND_V(!start.is_normalized(), Quat()); + ERR_FAIL_COND_V(!end.is_normalized(), Quat()); + + return start.slerp(end, t).normalized(); + } +}; + +template +T EditorSceneImporterFBX::_interpolate_track(const Vector &p_times, const Vector &p_values, float p_time, + AssetImportAnimation::Interpolation p_interp) { + //could use binary search, worth it? + int idx = -1; + for (int i = 0; i < p_times.size(); i++) { + if (p_times[i] > p_time) + break; + idx++; + } + + EditorSceneImporterAssetImportInterpolate interp; + + switch (p_interp) { + case AssetImportAnimation::INTERP_LINEAR: { + + if (idx == -1) { + return p_values[0]; + } else if (idx >= p_times.size() - 1) { + return p_values[p_times.size() - 1]; + } + + float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); + + return interp.lerp(p_values[idx], p_values[idx + 1], c); + + } break; + case AssetImportAnimation::INTERP_STEP: { + + if (idx == -1) { + return p_values[0]; + } else if (idx >= p_times.size() - 1) { + return p_values[p_times.size() - 1]; + } + + return p_values[idx]; + + } break; + case AssetImportAnimation::INTERP_CATMULLROMSPLINE: { + + if (idx == -1) { + return p_values[1]; + } else if (idx >= p_times.size() - 1) { + return p_values[1 + p_times.size() - 1]; + } + + float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); + + return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); + + } break; + case AssetImportAnimation::INTERP_CUBIC_SPLINE: { + + if (idx == -1) { + return p_values[1]; + } else if (idx >= p_times.size() - 1) { + return p_values[(p_times.size() - 1) * 3 + 1]; + } + + float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); + + T from = p_values[idx * 3 + 1]; + T c1 = from + p_values[idx * 3 + 2]; + T to = p_values[idx * 3 + 4]; + T c2 = to + p_values[idx * 3 + 3]; + + return interp.bezier(from, c1, c2, to, c); + + } break; + } + + ERR_FAIL_V(p_values[0]); +} + +void set_owner_recursive(Node *root, Node *current_node) { + current_node->set_owner(root); + + for (int child_id = 0; child_id < current_node->get_child_count(); child_id++) { + Node *child = current_node->get_child(child_id); + set_owner_recursive(root, child); // recursive + } +} + +// tool which can get the global transform for a scene which isn't loaded. +Transform get_global_transform(Spatial *root, Spatial *child_node) { + // state.root is armature and you are using this for an armature check. + if (root == child_node) { + return root->get_transform(); + } + + Transform t = Transform(); + Node *iter = child_node; + + while (iter != nullptr && iter != root) { + Spatial *spatial = Object::cast_to(iter); + if (spatial) { + t *= spatial->get_transform(); + } + + iter = iter->get_parent(); + } + + return t; +} + +Spatial * +EditorSceneImporterFBX::_generate_scene(const String &p_path, + const Assimp::FBX::Document *p_document, const uint32_t p_flags, + int p_bake_fps, const int32_t p_max_bone_weights) { + + ImportState state; + state.path = p_path; + state.animation_player = NULL; + + // create new root node for scene + Spatial *scene_root = memnew(Spatial); + state.root = memnew(Spatial); + state.root_owner = scene_root; // the real scene root... sorry compatibility code is painful... + + state.root->set_name("RootNode"); + scene_root->add_child(state.root); + state.root->set_owner(scene_root); + + state.fbx_root_node.instance(); + state.fbx_root_node->godot_node = state.root; + + // Size relative to cm. + const real_t fbx_unit_scale = p_document->GlobalSettings().UnitScaleFactor(); + + // Set FBX file scale is relative to CM must be converted to M + state.scale = fbx_unit_scale / 100.0; + print_verbose("FBX unit scale is: " + rtos(state.scale)); + + // Enabled by default. + state.enable_material_import = true; + // Enabled by default. + state.enable_animation_import = true; + Ref root_node; + root_node.instance(); + root_node->node_name = "root node"; + root_node->current_node_id = 0; + root_node->godot_node = state.root; + + // cache this node onto the fbx_target map. + state.fbx_target_map.insert(0, root_node); + + // cache basic node information from FBX document + // grabs all FBX bones + CacheNodeInformation(Ref(), state, p_document, 0L); + BuildDocumentNodes(nullptr, state, p_document, 0L, NULL); + + //print_verbose("[doc] debug fbx_bone_map size: " + itos(state.fbx_bone_map.size())); + + // do we globally allow for import of materials + // (prevents overwrite of materials; so you can handle them explicitly) + if (state.enable_material_import) { + const std::vector &materials = p_document->GetMaterialIDs(); + + for (uint64_t material_id : materials) { + + Assimp::FBX::LazyObject *lazy_material = p_document->GetObject(material_id); + const Assimp::FBX::Material *mat = lazy_material->Get(); + ERR_CONTINUE_MSG(!mat, "Could not convert fbx material by id: " + itos(material_id)); + + Ref material; + material.instance(); + material->set_imported_material(mat); + + Ref godot_material = material->import_material(state); + + state.cached_materials.insert(material_id, godot_material); + } + } + + // build skin and skeleton information + print_verbose("[doc] Skeleton Bone count: " + itos(state.fbx_bone_map.size())); + + // Importing bones using document based method from FBX directly + // We do not use the assimp bone format to determine this information anymore. + if (state.fbx_bone_map.size() > 0) { + // We are using a single skeleton only method here + // this is because we really have no concept of skeletons in FBX + // their are bones in a scene but they have no specific armature + // we can detect armatures but the issue lies in the complexity + // we opted to merge the entire scene onto one skeleton for now + // if we need to change this we have an archive of the old code. + + const std::vector &bind_pose_ids = p_document->GetBindPoseIDs(); + + for (uint64_t skin_id : bind_pose_ids) { + + Assimp::FBX::LazyObject *lazy_skin = p_document->GetObject(skin_id); + const Assimp::FBX::FbxPose *active_skin = lazy_skin->Get(); + + if (active_skin) { + const std::vector > &bind_poses = active_skin->GetBindPoses(); + + for (std::shared_ptr pose_node : bind_poses) { + Transform t = pose_node->GetBindPose(); + uint64_t fbx_node_id = pose_node->GetNodeID(); + if (state.fbx_bone_map.has(fbx_node_id)) { + Ref bone = state.fbx_bone_map[fbx_node_id]; + if (bone.is_valid()) { + print_verbose("assigned skin pose from the file for bone " + bone->bone_name + ", transform: " + t); + bone->pose_node = t; + bone->assigned_pose_node = true; + } + } + } + } + } + + // bind pose normally only has 1 per mesh but can have more than one + // this is the point of skins + // in FBX first bind pose is the master for the first skin + + // In order to handle the FBX skeleton we must also inverse any parent transforms on the bones + // just to rule out any parent node transforms in the bone data + // this is trivial to do and allows us to use the single skeleton method and merge them + // this means that the nodes from maya kLocators will be preserved as bones + // in the same rig without having to match this across skeletons and merge by detection + // we can just merge and undo any parent transforms + for (Map >::Element *bone_element = state.fbx_bone_map.front(); bone_element; bone_element = bone_element->next()) { + Ref bone = bone_element->value(); + Ref fbx_skeleton_inst; + + uint64_t armature_id = bone->armature_id; + if (state.skeleton_map.has(armature_id)) { + fbx_skeleton_inst = state.skeleton_map[armature_id]; + } else { + fbx_skeleton_inst.instance(); + state.skeleton_map.insert(armature_id, fbx_skeleton_inst); + } + + print_verbose("populating skeleton with bone: " + bone->bone_name); + + // // populate bone skeleton - since fbx has no DOM for the skeleton just a node. + // bone->bone_skeleton = fbx_skeleton_inst; + + // now populate bone on the armature node list + fbx_skeleton_inst->skeleton_bones.push_back(bone); + + // we need to have a valid armature id and the model configured for the bone to be assigned fully. + // happens once per skeleton + if (state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->has_model()) { + Ref node = state.fbx_target_map[armature_id]; + + fbx_skeleton_inst->set_model(node->get_model()); + fbx_skeleton_inst->fbx_node = node; + print_verbose("allocated fbx skeleton primary / armature node for the level: " + node->node_name); + } else if (!state.fbx_target_map.has(armature_id) && !fbx_skeleton_inst->has_model()) { + print_error("bones are not mapped to an armature node for armature id: " + itos(armature_id) + " bone: " + bone->bone_name); + // this means bone will be removed and not used, which is safe actually and no skeleton will be created. + } + } + + // setup skeleton instances if required :) + for (Map >::Element *skeleton_node = state.skeleton_map.front(); skeleton_node; skeleton_node = skeleton_node->next()) { + skeleton_node->value()->init_skeleton(state); + } + } + + // build godot node tree + if (state.fbx_node_list.size() > 0) { + for (List >::Element *node_element = state.fbx_node_list.front(); + node_element; + node_element = node_element->next()) { + Ref fbx_node = node_element->get(); + MeshInstance *mesh_node = nullptr; + Ref mesh_data_precached; + + // check for valid geometry + if (fbx_node->fbx_model == nullptr) { + print_error("[doc] fundamental flaw, submit bug immediately with full import log with verbose logging on"); + } else { + const std::vector &geometry = fbx_node->fbx_model->GetGeometry(); + for (const Assimp::FBX::Geometry *mesh : geometry) { + print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name); + + if (mesh == nullptr) + continue; + + const Assimp::FBX::MeshGeometry *mesh_geometry = dynamic_cast(mesh); + if (mesh_geometry != NULL) { + uint64_t mesh_id = mesh_geometry->ID(); + + // this data will pre-exist if vertex weight information is found + if (state.renderer_mesh_data.has(mesh_id)) { + mesh_data_precached = state.renderer_mesh_data[mesh_id]; + } else { + mesh_data_precached.instance(); + state.renderer_mesh_data.insert(mesh_id, mesh_data_precached); + } + + // mesh node, mesh id + mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model); + if (!state.MeshNodes.has(mesh_id)) { + state.MeshNodes.insert(mesh_id, fbx_node); + } + } + + const Assimp::FBX::ShapeGeometry *shape_geometry = dynamic_cast(mesh); + if (shape_geometry != nullptr) { + print_verbose("[doc] valid shape geometry converted"); + } + } + } + + Ref node_skeleton = fbx_node->skeleton_node; + + if (node_skeleton.is_valid()) { + Skeleton *skel = node_skeleton->skeleton; + fbx_node->godot_node = skel; + } else if (mesh_node == nullptr) { + fbx_node->godot_node = memnew(Spatial); + } else { + fbx_node->godot_node = mesh_node; + } + + fbx_node->godot_node->set_name(fbx_node->node_name); + + // assign parent if valid + if (fbx_node->fbx_parent.is_valid()) { + fbx_node->fbx_parent->godot_node->add_child(fbx_node->godot_node); + fbx_node->godot_node->set_owner(state.root_owner); + } + + // Node Transform debug, set local xform data. + fbx_node->godot_node->set_transform(get_unscaled_transform(fbx_node->pivot_transform->LocalTransform, state.scale)); + + // populate our mesh node reference + if (mesh_node != nullptr && mesh_data_precached.is_valid()) { + mesh_data_precached->godot_mesh_instance = mesh_node; + } + } + } + + for (Map >::Element *skin_mesh = state.MeshNodes.front(); skin_mesh; skin_mesh = skin_mesh->next()) { + create_mesh_data_skin(state, skin_mesh->value(), skin_mesh->key()); + } + + // mesh data iteration for populating skeleton mapping + for (Map >::Element *mesh_data = state.renderer_mesh_data.front(); mesh_data; mesh_data = mesh_data->next()) { + Ref mesh = mesh_data->value(); + MeshInstance *mesh_instance = mesh->godot_mesh_instance; + int mesh_weights = mesh->max_weight_count; + Ref skeleton; + bool valid_armature = mesh->valid_armature_id; + uint64_t armature = mesh->armature_id; + + if (mesh_weights > 0 && valid_armature) { + if (state.skeleton_map.has(armature)) { + skeleton = state.skeleton_map[armature]; + print_verbose("[doc] armature mesh to skeleton mapping has been allocated"); + } else { + print_error("[doc] unable to find armature mapping"); + } + + if (mesh_instance && skeleton.is_valid()) { + mesh_instance->set_skeleton_path(mesh_instance->get_path_to(skeleton->skeleton)); + print_verbose("[doc] allocated skeleton to mesh " + mesh_instance->get_name()); + + // do we have a mesh skin for this mesh + if (state.MeshSkins.has(mesh->mesh_id)) { + Ref mesh_skin = state.MeshSkins[mesh->mesh_id]; + if (mesh_skin.is_valid()) { + print_verbose("[doc] allocated skin to mesh " + mesh_instance->get_name()); + mesh_instance->set_skin(mesh_skin); + } + } + } + } + } + + // build skin and skeleton information + print_verbose("[doc] Skeleton Bone count: " + itos(state.fbx_bone_map.size())); + const Assimp::FBX::FileGlobalSettings *FBXSettings = p_document->GlobalSettingsPtr(); + + // Configure constraints + const std::vector fbx_constraints = p_document->GetConstraintStackIDs(); + + // for (uint64_t constraint_id : fbx_constraints) { + // Assimp::FBX::LazyObject *lazyObject = p_document->GetObject(constraint_id); + // const Assimp::FBX::Constraint *constraint = lazyObject->Get(); + // + // if (constraint != nullptr) { + // print_verbose("[doc] FBX constraint detected"); + // + // // We are 'inverting' our search to do inverse lookup of the constraint id where it attached. + // // todo: make ProcessDomConnections rather than singular + // std::vector connections = p_document->GetConnectionsByDestinationSequenced(constraint_id, "Model"); + // + // if (connections.size()) { + // uint64_t parent_id = 0; + // std::vector children; + // bool valid_parent = false; + // for (const Assimp::FBX::Connection *connection : connections) { + // if (connection->prop == "Source (Parent)") { + // parent_id = connection->src; + // valid_parent = true; + // } else if (connection->prop == "Constrained object (Child)") { + // children.push_back(connection->src); + // } + // } + // + // if (valid_parent && children.size() > 0) { + // + // bool parent_is_bone = state.fbx_bone_map.has(parent_id); + // bool parent_is_node = state.fbx_target_map.has(parent_id); + // + // print_error("[doc] FBX Constraint found these are banned in godot: parent: " + itos(parent_id) + " is bone " + (parent_is_bone ? "yes" : "no") + " is node " + (parent_is_node ? "yes" : "no")); + // // We can add these later if we want, they just require a lot of work, the code below can be used for this + // // for (uint64_t child_id : children) { + // // bool child_is_bone = state.fbx_bone_map.has(child_id); + // // bool child_is_node = state.fbx_target_map.has(child_id); + // // print_verbose("[doc] -- child: " + itos(child_id) + " is bone " + (child_is_bone ? "yes" : "no") + " is node " + (child_is_node ? "yes" : "no")); + // + // // // please note check bone list before you check node list. + // // // bones are always in node list but not the other way around. + // // if (!child_is_bone && !parent_is_bone) { + // + // // if (parent_is_node && child_is_node) { + // // Ref parent = state.fbx_target_map[parent_id]; + // // Ref child = state.fbx_target_map[child_id]; + // + // // print_verbose("[doc] Node to node constraint parent: " + parent->node_name + " child: " + child->node_name); + // + // // if (parent.is_valid() && child.is_valid()) { + // // if (child->godot_node && parent->godot_node) { + // // Transform t = get_global_transform(state.root, child->godot_node); + // // Transform constraint_parent_global = get_global_transform(state.root, parent->godot_node); + // // Node *previous_parent_of_child = child->godot_node->get_parent(); + // + // // previous_parent_of_child->remove_child(child->godot_node); + // // parent->godot_node->add_child(child->godot_node); + // + // // // update owner for all children - otherwise children of child are invisible + // // set_owner_recursive(state.root, child->godot_node); + // // Transform final_matrix = constraint_parent_global.inverse() * t; + // // child->godot_node->set_global_transform(final_matrix); + // // print_verbose("[doc] reparenting completed, child count of children: " + itos(child->godot_node->get_child_count())); + // // } else { + // // print_error("[doc] invalid node instancing in godot"); + // // } + // + // // } else { + // // print_error("[doc] can't resolve invalid parent!"); + // // } + // // } + // // } else if (parent_is_bone && !child_is_bone) { + // // // // // bone attachment mode + // // // Ref parent = state.fbx_bone_map[parent_id]; + // // // Ref child = state.fbx_target_map[child_id]; + // + // // // print_verbose("[doc] Bone to node constraint parent bone: " + parent->bone_name + " child node: " + child->node_name); + // + // // // if (parent.is_valid() && child.is_valid()) { + // // // if (child->godot_node) { + // // // Transform t = get_global_transform(state.root, child->godot_node); + // // // Transform bone_matrix = parent->rest_pose; + // // // //Spatial *previous_parent_of_child = Object::cast_to(child->godot_node->get_parent()); + // + // // // //print_verbose("t: " + t.origin + " bone matrix: " + bone_matrix + " parent: " + get_global_transform(state.root, previous_parent_of_child).origin); + // + // // // //print_verbose("bone: " + bone_matrix.origin + ", inverse:" + bone_matrix.inverse().origin); + // // // //print_verbose("transform: " + t.origin + ", inverse: " + t.inverse().origin); + // + // // // BoneAttachment *parent_attachment = memnew(BoneAttachment); + // // // // parent_attachment->set_bone_name(state.skeleton->get_bone_name(parent->godot_bone_id)); + // // // // state.skeleton->add_child(parent_attachment); + // // // // parent_attachment->set_owner(state.root); + // + // // // // previous_parent_of_child->remove_child(child->godot_node); + // // // // parent_attachment->add_child(child->godot_node); + // + // // // // // update owner for all children - otherwise children of child are invisible + // // // // set_owner_recursive(state.root, child->godot_node); + // // // // child->godot_node->set_global_transform(t); + // + // // // print_verbose("[doc] reparenting completed, child count of children: " + itos(child->godot_node->get_child_count())); + // // // } else { + // // // print_error("[doc] invalid node instancing in godot"); + // // // } + // + // // // } else { + // // // print_error("[doc] can't resolve invalid parent!"); + // // // } + // // } + // // } + // } + // } + // } + // } + // + // //print_verbose("Constraints count: " + itos(fbx_constraints.size())); + + // get the animation FPS + float fps_setting = ImportUtils::get_fbx_fps(FBXSettings); + + // enable animation import, only if local animation is enabled + if (state.enable_animation_import && (p_flags & IMPORT_ANIMATION)) { + // document animation stack list - get by ID so we can unload any non used animation stack + const std::vector animation_stack = p_document->GetAnimationStackIDs(); + + for (uint64_t anim_id : animation_stack) { + Assimp::FBX::LazyObject *lazyObject = p_document->GetObject(anim_id); + const Assimp::FBX::AnimationStack *stack = lazyObject->Get(); + + if (stack != nullptr) { + String animation_name = ImportUtils::FBXNodeToName(stack->Name()); + print_verbose("Valid animation stack has been found: " + animation_name); + // ReferenceTime is the same for some animations? + // LocalStop time is the start and end time + float r_start = CONVERT_FBX_TIME(stack->ReferenceStart()); + float r_stop = CONVERT_FBX_TIME(stack->ReferenceStop()); + float start_time = CONVERT_FBX_TIME(stack->LocalStart()); + float end_time = CONVERT_FBX_TIME(stack->LocalStop()); + float duration = end_time - start_time; + + print_verbose("r_start " + rtos(r_start) + ", r_stop " + rtos(r_stop)); + print_verbose("start_time" + rtos(start_time) + " end_time " + rtos(end_time)); + print_verbose("anim duration : " + rtos(duration)); + + // we can safely create the animation player + if (state.animation_player == nullptr) { + print_verbose("Creating animation player"); + state.animation_player = memnew(AnimationPlayer); + state.root->add_child(state.animation_player); + state.animation_player->set_owner(state.root); + } + + Ref animation; + animation.instance(); + animation->set_name(animation_name); + animation->set_length(duration); + + print_verbose("Animation length: " + rtos(animation->get_length()) + " seconds"); + + // i think assimp was duplicating things, this lets me know to just reference or ignore this to prevent duplicate information in tracks + // this would mean that we would be doing three times as much work per track if my theory is correct. + // this was not the case but this is a good sanity check for the animation handler from the document. + // it also lets us know if the FBX specification massively changes the animation system, in theory such a change would make this show + // an fbx specification error, so best keep it in + // the overhead is tiny. + Map CheckForDuplication; + + const std::vector &layers = stack->Layers(); + print_verbose("FBX Animation layers: " + itos(layers.size())); + for (const Assimp::FBX::AnimationLayer *layer : layers) { + std::vector node_list = layer->Nodes(); + print_verbose("Layer: " + ImportUtils::FBXNodeToName(layer->Name()) + ", " + " AnimCurveNode count " + itos(node_list.size())); + + // first thing to do here is that i need to first get the animcurvenode to a Vector3 + // we now need to put this into the track information for godot. + // to do this we need to know which track is what? + + // target id, [ track name, [time index, vector] ] + // new map needs to be [ track name, keyframe_data ] + Map > AnimCurveNodes; + + // struct AnimTrack { + // // Animation track can be + // // visible, T, R, S + // Map > animation_track; + // }; + + // Map AnimCurveNodes; + + // so really, what does this mean to make an animtion track. + // we need to know what object the curves are for. + // we need the target ID and the target name for the track reduction. + + Assimp::FBX::Model::RotOrder quat_rotation_order = Assimp::FBX::Model::RotOrder_EulerXYZ; + + // T:: R:: S:: Visible:: Custom:: + for (const Assimp::FBX::AnimationCurveNode *curve_node : node_list) { + // when Curves() is called the curves are actually read, we could replace this with our own ProcessDomConnection code here if required. + // We may need to do this but ideally we use Curves + // note: when you call this there might be a delay in opening it + // uses mutable type to 'cache' the response until the AnimationCurveNode is cleaned up. + std::map curves = curve_node->Curves(); + const Assimp::FBX::Object *object = curve_node->Target(); + const Assimp::FBX::Model *target = curve_node->TargetAsModel(); + if (target == nullptr) { + if (object != nullptr) { + print_error("[doc] warning failed to find a target Model for curve: " + String(object->Name().c_str())); + } else { + print_error("[doc] failed to resolve object"); + } + + continue; + } else { + //print_verbose("[doc] applied rotation order: " + itos(target->RotationOrder())); + quat_rotation_order = target->RotationOrder(); + } + + uint64_t target_id = target->ID(); + String target_name = ImportUtils::FBXNodeToName(target->Name()); + + const Assimp::FBX::PropertyTable &properties = curve_node->Props(); + bool got_x, got_y, got_z; + float offset_x = Assimp::FBX::PropertyGet(properties, "d|X", got_x); + float offset_y = Assimp::FBX::PropertyGet(properties, "d|Y", got_y); + float offset_z = Assimp::FBX::PropertyGet(properties, "d|Z", got_z); + + String curve_node_name = ImportUtils::FBXNodeToName(curve_node->Name()); + + // Reduce all curves for this node into a single container + // T, R, S is what we expect, although other tracks are possible + // like for example visibility tracks. + + // We are not ordered here, we don't care about ordering, this happens automagically by godot when we insert with the + // key time :), so order is unimportant because the insertion will happen at a time index + // good to know: we do not need a list of these in another format :) + //Map > unordered_track; + + // T + // R + // S + // Map[String, List] + + // So this is a reduction of the animation curve nodes + // We build this as a lookup, this is essentially our 'animation track' + //AnimCurveNodes.insert(curve_node_name, Map()); + + // create the animation curve information with the target id + // so the point of this makes a track with the name "T" for example + // the target ID is also set here, this means we don't need to do anything extra when we are in the 'create all animation tracks' step + FBXTrack &keyframe_map = AnimCurveNodes[target_id][StringName(curve_node_name)]; + + if (got_x && got_y && got_z) { + Vector3 default_value = Vector3(offset_x, offset_y, offset_z); + keyframe_map.default_value = default_value; + keyframe_map.has_default = true; + //print_verbose("track name: " + curve_node_name); + //print_verbose("xyz default: " + default_value); + } + // target id, [ track name, [time index, vector] ] + // Map > > AnimCurveNodes; + + // we probably need the target id here. + // so map[uint64_t map]... + // Map translation_keys, rotation_keys, scale_keys; + + // extra const required by C++11 colon/Range operator + // note: do not use C++17 syntax here for dicts. + // this is banned in Godot. + for (std::pair &kvp : curves) { + String curve_element = ImportUtils::FBXNodeToName(kvp.first); + const Assimp::FBX::AnimationCurve *curve = kvp.second; + String curve_name = ImportUtils::FBXNodeToName(curve->Name()); + uint64_t curve_id = curve->ID(); + + if (CheckForDuplication.has(curve_id)) { + print_error("(FBX spec changed?) We found a duplicate curve being used for an alternative node - report to godot issue tracker"); + } else { + CheckForDuplication.insert(curve_id, curve); + } + + // FBX has no name for AnimCurveNode::, most of the time, not seen any with valid name here. + const std::map track_time = curve->GetValueTimeTrack(); + + if (track_time.size() > 0) { + for (std::pair keyframe : track_time) { + if (curve_element == "d|X") { + keyframe_map.keyframes[keyframe.first].x = keyframe.second; + } else if (curve_element == "d|Y") { + keyframe_map.keyframes[keyframe.first].y = keyframe.second; + } else if (curve_element == "d|Z") { + keyframe_map.keyframes[keyframe.first].z = keyframe.second; + } else { + //print_error("FBX Unsupported element: " + curve_element); + } + + //print_verbose("[" + itos(target_id) + "] Keyframe added: " + itos(keyframe_map.size())); + + //print_verbose("Keyframe t:" + rtos(animation_track_time) + " v: " + rtos(keyframe.second)); + } + } + } + } + + // Map > > AnimCurveNodes; + // add this animation track here + + // target id, [ track name, [time index, vector] ] + //std::map > AnimCurveNodes; + for (Map >::Element *track = AnimCurveNodes.front(); track; track = track->next()) { + + // 5 tracks + // current track index + // track count is 5 + // track count is 5. + // next track id is 5. + const uint64_t target_id = track->key(); + int track_idx = animation->add_track(Animation::TYPE_TRANSFORM); + + // animation->track_set_path(track_idx, node_path); + // animation->track_set_path(track_idx, node_path); + Ref bone; + + // note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad. + // remember that state.fbx_bone_map[target_id] will create a new entry EVEN if you only read. + // this would break node animation targets, so if you change this be warned. :) + if (state.fbx_bone_map.has(target_id)) { + bone = state.fbx_bone_map[target_id]; + } + + Transform target_transform; + + if (state.fbx_target_map.has(target_id)) { + Ref node_ref = state.fbx_target_map[target_id]; + target_transform = node_ref->pivot_transform->GlobalTransform; + //print_verbose("[doc] allocated animation node transform"); + } + + //int size_targets = state.fbx_target_map.size(); + //print_verbose("Target ID map: " + itos(size_targets)); + //print_verbose("[doc] debug bone map size: " + itos(state.fbx_bone_map.size())); + + // if this is a skeleton mapped track we can just set the path for the track. + // todo: implement node paths here at some + if (state.fbx_bone_map.size() > 0 && state.fbx_bone_map.has(target_id)) { + + if (bone->fbx_skeleton.is_valid() && bone.is_valid()) { + Ref fbx_skeleton = bone->fbx_skeleton; + String bone_path = state.root->get_path_to(fbx_skeleton->skeleton); + bone_path += ":" + fbx_skeleton->skeleton->get_bone_name(bone->godot_bone_id); + print_verbose("[doc] track bone path: " + bone_path); + NodePath path = bone_path; + animation->track_set_path(track_idx, path); + } + } else if (state.fbx_target_map.has(target_id)) { + //print_verbose("[doc] we have a valid target for a node animation"); + Ref target_node = state.fbx_target_map[target_id]; + if (target_node.is_valid() && target_node->godot_node != nullptr) { + String node_path = state.root->get_path_to(target_node->godot_node); + NodePath path = node_path; + animation->track_set_path(track_idx, path); + //print_verbose("[doc] node animation path: " + node_path); + } + } else { + // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizzare effects later we should disable this. + // I am not sure if this is unsafe or not, testing will tell us this. + print_error("[doc] invalid fbx target detected for this track"); + continue; + } + + // everything in FBX and Maya is a node therefore if this happens something is seriously broken. + if (!state.fbx_target_map.has(target_id)) { + print_error("unable to resolve this to an FBX object."); + continue; + } + + Ref target_node = state.fbx_target_map[target_id]; + const Assimp::FBX::Model *model = target_node->fbx_model; + const Assimp::FBX::PropertyTable &props = model->Props(); + + Map &track_data = track->value(); + FBXTrack &translation_keys = track_data[StringName("T")]; + FBXTrack &rotation_keys = track_data[StringName("R")]; + FBXTrack &scale_keys = track_data[StringName("S")]; + + double increment = 1.0f / fps_setting; + double time = 0.0f; + + bool last = false; + + Vector pos_values; + Vector pos_times; + Vector scale_values; + Vector scale_times; + Vector rot_values; + Vector rot_times; + + double max_duration = 0; + double anim_length = animation->get_length(); + + for (std::pair position_key : translation_keys.keyframes) { + pos_values.push_back(position_key.second * state.scale); + double animation_track_time = CONVERT_FBX_TIME(position_key.first); + + if (animation_track_time > max_duration) { + max_duration = animation_track_time; + } + + //print_verbose("pos keyframe: t:" + rtos(animation_track_time) + " value " + position_key.second); + pos_times.push_back(animation_track_time); + } + + for (std::pair scale_key : scale_keys.keyframes) { + scale_values.push_back(scale_key.second); + double animation_track_time = CONVERT_FBX_TIME(scale_key.first); + + if (animation_track_time > max_duration) { + max_duration = animation_track_time; + } + //print_verbose("scale keyframe t:" + rtos(animation_track_time)); + scale_times.push_back(animation_track_time); + } + + // + // Pre and Post keyframe rotation handler + // -- Required because Maya and Autodesk <3 the pain when it comes to implementing animation code! enjoy <3 + + bool got_pre = false; + bool got_post = false; + + Quat post_rotation; + Quat pre_rotation; + + // Rotation matrix + const Vector3 &PreRotation = Assimp::FBX::PropertyGet(props, "PreRotation", got_pre); + const Vector3 &PostRotation = Assimp::FBX::PropertyGet(props, "PostRotation", got_post); + + Assimp::FBX::Model::RotOrder rot_order = model->RotationOrder(); + if (got_pre) { + pre_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PreRotation)); + } + if (got_post) { + post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation)); + } + + Quat lastQuat = Quat(); + + for (std::pair rotation_key : rotation_keys.keyframes) { + double animation_track_time = CONVERT_FBX_TIME(rotation_key.first); + + //print_verbose("euler rotation key: " + rotation_key.second); + Quat rot_key_value = ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_key.second)); + + if (lastQuat != Quat() && rot_key_value.dot(lastQuat) < 0) { + rot_key_value.x = -rot_key_value.x; + rot_key_value.y = -rot_key_value.y; + rot_key_value.z = -rot_key_value.z; + rot_key_value.w = -rot_key_value.w; + } + // pre_post rotation possibly could fix orientation + Quat final_rotation = pre_rotation * rot_key_value * post_rotation; + + lastQuat = final_rotation; + + if (animation_track_time > max_duration) { + max_duration = animation_track_time; + } + + rot_values.push_back(final_rotation); + rot_times.push_back(animation_track_time); + } + + Transform bone_rest; + int skeleton_bone = -1; + if (state.fbx_bone_map.has(target_id)) { + if (bone.is_valid() && bone->fbx_skeleton.is_valid()) { + skeleton_bone = bone->godot_bone_id; + if (skeleton_bone >= 0) { + bone_rest = bone->fbx_skeleton->skeleton->get_bone_rest(skeleton_bone); + } + } + } + + const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin; + const Quat def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quat(); + const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale(); + print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")"); + + while (true) { + Vector3 pos = def_pos; + Quat rot = def_rot; + Vector3 scale = def_scale; + + if (pos_values.size()) { + pos = _interpolate_track(pos_times, pos_values, time, + AssetImportAnimation::INTERP_LINEAR); + } + + if (rot_values.size()) { + rot = _interpolate_track(rot_times, rot_values, time, + AssetImportAnimation::INTERP_LINEAR); + } + + if (scale_values.size()) { + scale = _interpolate_track(scale_times, scale_values, time, + AssetImportAnimation::INTERP_LINEAR); + } + + // node animations must also include pivots + if (skeleton_bone >= 0) { + Transform xform = Transform(); + xform.basis.set_quat_scale(rot, scale); + xform.origin = pos; + const Transform t = bone_rest.affine_inverse() * xform; + + // populate this again + rot = t.basis.get_rotation_quat(); + rot.normalize(); + scale = t.basis.get_scale(); + pos = t.origin; + } + + animation->transform_track_insert_key(track_idx, time, pos, rot, scale); + + if (last) { + break; + } + + time += increment; + if (time > anim_length) { + last = true; + time = anim_length; + break; + } + } + } + } + state.animation_player->add_animation(animation_name, animation); + } + } + + // AnimStack elements contain start stop time and name of animation + // AnimLayer is the current active layer of the animation (multiple layers can be active we only support 1) + // AnimCurveNode has a OP link back to the model which is the real node. + // AnimCurveNode has a direct link to AnimationCurve (of which it may have more than one) + + // Store animation stack in list + // iterate over all AnimStacks like the cache node algorithm recursively + // this can then be used with ProcessDomConnection<> to link from + // AnimStack:: <-- (OO) --> AnimLayer:: <-- (OO) --> AnimCurveNode:: (which can OP resolve) to Model:: + } + + // + // Cleanup operations - explicit to prevent errors on shutdown - found that ref to ref does behave badly sometimes. + // + + state.renderer_mesh_data.clear(); + state.MeshSkins.clear(); + state.fbx_target_map.clear(); + state.fbx_node_list.clear(); + + for (Map >::Element *element = state.fbx_bone_map.front(); element; element = element->next()) { + Ref bone = element->value(); + bone->parent_bone.unref(); + bone->pivot_xform.unref(); + bone->fbx_skeleton.unref(); + } + + for (Map >::Element *element = state.skeleton_map.front(); element; element = element->next()) { + Ref skel = element->value(); + skel->fbx_node.unref(); + skel->skeleton_bones.clear(); + } + + state.fbx_bone_map.clear(); + state.skeleton_map.clear(); + state.fbx_root_node.unref(); + + return scene_root; +} +void EditorSceneImporterFBX::create_mesh_data_skin(ImportState &state, const Ref &fbx_node, uint64_t mesh_id) { + if (!state.MeshSkins.has(mesh_id)) { + print_verbose("[doc] caching skin for " + itos(mesh_id) + ", mesh node name: " + fbx_node->node_name); + Ref skin; + skin.instance(); + + for (Map >::Element *elem = state.fbx_bone_map.front(); elem; elem = elem->next()) { + Ref bone = elem->value(); + Transform ignore_t; + Ref skeleton = bone->fbx_skeleton; + + if (bone->get_link(state).is_valid()) { + bool valid_bind = false; + Transform bind = bone->get_vertex_skin_xform(state, fbx_node->pivot_transform->GlobalTransform, valid_bind); + if (valid_bind) { + skin->add_named_bind(bone->bone_name, get_unscaled_transform(bind, state.scale)); + } + } + } + state.MeshSkins[mesh_id] = skin; + } +} + +void EditorSceneImporterFBX::CacheNodeInformation(Ref p_parent_bone, + ImportState &state, const Assimp::FBX::Document *p_doc, + uint64_t p_id) { + const std::vector &conns = p_doc->GetConnectionsByDestinationSequenced(p_id, "Model"); + // FBX can do an join like this + // Model -> SubDeformer (bone) -> Deformer (skin pose) + // This is important because we need to somehow link skin back to bone id in skeleton :) + // The rules are: + // A subdeformer will exist if 'limbnode' classtag present + // The subdeformer will not neccisarily have a deformer as joints do not have one + for (const Assimp::FBX::Connection *con : conns) { + // goto: bone creation + //print_verbose("con: " + String(con->PropertyName().c_str())); + + // ignore object-property links we want the object to object links nothing else + if (con->PropertyName().length()) { + continue; + } + + // convert connection source object into Object base class + const Assimp::FBX::Object *const object = con->SourceObject(); + + if (nullptr == object) { + print_verbose("failed to convert source object for Model link"); + continue; + } + + // FBX Model::Cube, Model::Bone001, etc elements + // This detects if we can cast the object into this model structure. + const Assimp::FBX::Model *const model = dynamic_cast(object); + + // declare our bone element reference (invalid, unless we create a bone in this step) + // this lets us pass valid armature information into children objects and this is why we moved this up here + // previously this was created .instanced() on the same line. + Ref bone_element; + + if (model != nullptr) { + const Assimp::FBX::LimbNodeMaya *const limb_node = dynamic_cast(model); + if (limb_node != nullptr) { + // Write bone into bone list for FBX + if (!state.fbx_bone_map.has(limb_node->ID())) { + bool parent_is_bone = state.fbx_bone_map.find(p_id); + bone_element.instance(); + + // used to build the bone hierarchy in the skeleton + bone_element->parent_bone_id = parent_is_bone ? p_id : 0; + bone_element->valid_parent = parent_is_bone; + + // armature handling + + // parent is a node and this is the first bone + if (!parent_is_bone) { + uint64_t armature_id = p_id; + + bone_element->valid_armature_id = true; + bone_element->armature_id = armature_id; + print_verbose("[doc] valid armature has been configured for first child: " + itos(armature_id)); + } else if (p_parent_bone.is_valid()) { + if (p_parent_bone->valid_armature_id) { + bone_element->valid_armature_id = true; + bone_element->armature_id = p_parent_bone->armature_id; + print_verbose("[doc] bone has valid armature id:" + itos(bone_element->armature_id)); + } else { + print_error("[doc] unassigned armature id: " + String(limb_node->Name().c_str())); + } + } else { + print_error("[doc] error is this a bone? " + String(limb_node->Name().c_str())); + } + + if (!parent_is_bone) { + print_verbose("[doc] Root bone: " + bone_element->bone_name); + } + + // ;Deformer::, Geometry:: + // C: "OO",2188874359888,2190730951072 + uint64_t limb_id = limb_node->ID(); + + // Model "limb node" to SubDeformer to Deformer (skin) + const Assimp::FBX::Cluster *deformer = ProcessDOMConnection(p_doc, "Deformer", limb_id); + + bone_element->bone_name = ImportUtils::FBXNodeToName(model->Name()); + bone_element->parent_bone = p_parent_bone; + + if (deformer != nullptr) { + uint64_t mesh_target_id = 0; + + // inverse lookup of mesh from skin, this is because we like to reduce information down so we can re-use skins. + const Assimp::FBX::Skin *skin = ProcessDOMConnection(p_doc, "Skin", deformer->ID()); + if (skin) { + bone_element->skin = skin; // do not copy info out + //print_verbose("[doc] valid skin found! searching for geometry that this skin applies to"); + const Assimp::FBX::Geometry *geo = ProcessDOMConnection(p_doc, "Mesh", skin->ID()); + if (geo) { + bone_element->geometry = geo; + //print_verbose("[doc] valid mesh found!"); + mesh_target_id = geo->ID(); + } else { + print_error("skin element is not assigned properly to mesh - unsupported"); + } + + } else { + print_error("invalid skin layout / unsupported fbx file"); + } + + print_verbose("[doc] Mesh Cluster: " + String(deformer->Name().c_str()) + ", " + deformer->TransformLink()); + print_verbose("fbx node: debug name: " + String(model->Name().c_str()) + "bone name: " + String(deformer->Name().c_str())); + + // assign FBX animation bind pose compensation data; + // TODO Do I need scale this? + bone_element->transform_link = deformer->TransformLink(); + bone_element->transform_matrix = deformer->GetTransform(); + bone_element->cluster = deformer; + + // skin configures target node ID. + bone_element->target_node_id = deformer->TargetNode()->ID(); + bone_element->valid_target = true; + bone_element->bone_id = limb_id; + + // apply the vertex weight information + const std::vector &indexes = deformer->GetIndices(); + const std::vector &weights = deformer->GetWeights(); + + // Pipeline to move vertex weight information + // to the renderer + Ref mesh_vertex_data; + if (state.renderer_mesh_data.has(mesh_target_id)) { + mesh_vertex_data = state.renderer_mesh_data[mesh_target_id]; + } else { + mesh_vertex_data.instance(); + state.renderer_mesh_data.insert(mesh_target_id, mesh_vertex_data); + } + + // Mesh vertex data retrieved now to stream this deformer + // data into the internal mesh storage. + if (mesh_vertex_data.is_valid()) { + // tell the mesh what Armature it should use + mesh_vertex_data->armature_id = bone_element->armature_id; + mesh_vertex_data->valid_armature_id = true; + + //print_verbose("storing mesh vertex data for mesh to use later"); + ERR_FAIL_COND_MSG(indexes.size() != weights.size(), "[doc] error mismatch between weight info"); + + for (size_t idx = 0; idx < indexes.size(); idx++) { + + const size_t vertex_index = indexes[idx]; + //print_verbose("vertex index: " + itos(vertex_index)); + + const real_t influence_weight = weights[idx]; + + VertexMapping &vm = mesh_vertex_data->vertex_weights[vertex_index]; + vm.weights.push_back(influence_weight); + vm.bones.push_back(0); + vm.bones_ref.push_back(bone_element); + //print_verbose("Weight debug: " + rtos(influence_weight) + " bone id:" + bone_element->bone_name); + } + + for ( + const int *vertex_index = mesh_vertex_data->vertex_weights.next(nullptr); + vertex_index != nullptr; + vertex_index = mesh_vertex_data->vertex_weights.next(vertex_index)) { + VertexMapping *vm = mesh_vertex_data->vertex_weights.getptr(*vertex_index); + const int influence_count = vm->weights.size(); + if (influence_count > mesh_vertex_data->max_weight_count) { + mesh_vertex_data->max_weight_count = influence_count; + mesh_vertex_data->valid_weight_count = true; + } + } + + if (mesh_vertex_data->max_weight_count > 4) { + if (mesh_vertex_data->max_weight_count > 8) { + ERR_PRINT("[doc] Serious: maximum bone influences is 8 in this branch."); + } + // Clamp to 8 bone vertex influences. + mesh_vertex_data->max_weight_count = 8; + print_verbose("[doc] Using 8 vertex bone influences configuration."); + } else { + mesh_vertex_data->max_weight_count = 4; + print_verbose("[doc] Using 4 vertex bone influences configuration."); + } + } + } else { + print_verbose("[doc] warning: no skin for the deformer found: " + bone_element->bone_name); + } + + // insert limb by ID into list. + state.fbx_bone_map.insert(limb_node->ID(), bone_element); + } + } + + // recursion call - child nodes + CacheNodeInformation(bone_element, state, p_doc, model->ID()); + } + } +} + +void EditorSceneImporterFBX::BuildDocumentNodes( + Ref parent_transform, + ImportState &state, + const Assimp::FBX::Document *p_doc, + uint64_t id, + Ref parent_node) { + + // tree + // here we get the node 0 on the root by default + const std::vector &conns = p_doc->GetConnectionsByDestinationSequenced(id, "Model"); + + // branch + for (const Assimp::FBX::Connection *con : conns) { + + // ignore object-property links + if (con->PropertyName().length()) { + // really important we document why this is ignored. + print_verbose("ignoring property link - no docs on why this is ignored"); + continue; + } + + // convert connection source object into Object base class + // Source objects can exist with 'null connections' this means that we only for sure know the source exists. + const Assimp::FBX::Object *const source_object = con->SourceObject(); + + if (nullptr == source_object) { + print_verbose("failed to convert source object for Model link"); + continue; + } + + // FBX Model::Cube, Model::Bone001, etc elements + // This detects if we can cast the object into this model structure. + const Assimp::FBX::Model *const model = dynamic_cast(source_object); + // model is the current node + if (nullptr != model) { + uint64_t current_node_id = model->ID(); + + Ref new_node; + new_node.instance(); + new_node->current_node_id = current_node_id; + new_node->node_name = ImportUtils::FBXNodeToName(model->Name()); + + Ref fbx_transform; + fbx_transform.instance(); + fbx_transform->set_parent(parent_transform); + fbx_transform->set_model(model); + fbx_transform->debug_pivot_xform("name: " + new_node->node_name); + fbx_transform->Execute(); + + new_node->set_pivot_transform(fbx_transform); + + // check if this node is a bone + if (state.fbx_bone_map.has(current_node_id)) { + Ref bone = state.fbx_bone_map[current_node_id]; + if (bone.is_valid()) { + bone->set_pivot_xform(fbx_transform); + print_verbose("allocated bone data: " + bone->bone_name); + } + } + + // set the model, we can't just assign this safely + new_node->set_model(model); + + if (parent_node.is_valid()) { + new_node->set_parent(parent_node); + } else { + new_node->set_parent(state.fbx_root_node); + } + + // populate lookup tables with references + // [fbx_node_id, fbx_node] + + state.fbx_node_list.push_back(new_node); + if (!state.fbx_target_map.has(new_node->current_node_id)) { + state.fbx_target_map[new_node->current_node_id] = new_node; + } + + // print node name + print_verbose("[doc] new node " + new_node->node_name); + + // sub branches + BuildDocumentNodes(new_node->pivot_transform, state, p_doc, current_node_id, new_node); + } + } +} diff --git a/modules/assimp/editor_scene_importer_assimp.h b/modules/fbx/editor_scene_importer_fbx.h similarity index 51% rename from modules/assimp/editor_scene_importer_assimp.h rename to modules/fbx/editor_scene_importer_fbx.h index 4cd50e7681f4..e69a11cd4fb9 100644 --- a/modules/assimp/editor_scene_importer_assimp.h +++ b/modules/fbx/editor_scene_importer_fbx.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* editor_scene_importer_assimp.h */ +/* editor_scene_importer_fbx.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef EDITOR_SCENE_IMPORTER_ASSIMP_H -#define EDITOR_SCENE_IMPORTER_ASSIMP_H +#ifndef EDITOR_SCENE_FBX_IMPORTER_H +#define EDITOR_SCENE_FBX_IMPORTER_H #ifdef TOOLS_ENABLED + #include "core/bind/core_bind.h" #include "core/io/resource_importer.h" #include "core/vector.h" @@ -44,35 +45,18 @@ #include "scene/resources/animation.h" #include "scene/resources/surface_tool.h" -#include -#include -#include -#include -#include -#include -#include - -#include "import_state.h" -#include "import_utils.h" +#include "data/import_state.h" +#include "thirdparty/assimp_fbx/FBXDocument.h" +#include "thirdparty/assimp_fbx/FBXImportSettings.h" +#include "thirdparty/assimp_fbx/FBXMeshGeometry.h" +#include "thirdparty/assimp_fbx/FBXUtil.h" +#include "tools/import_utils.h" -using namespace AssimpImporter; +#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL -class AssimpStream : public Assimp::LogStream { -public: - // Constructor - AssimpStream() {} - - // Destructor - ~AssimpStream() {} - // Write something using your own functionality - void write(const char *message) { - print_verbose(String("Open Asset Import: ") + String(message).strip_edges()); - } -}; - -class EditorSceneImporterAssimp : public EditorSceneImporter { +class EditorSceneImporterFBX : public EditorSceneImporter { private: - GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter); + GDCLASS(EditorSceneImporterFBX, EditorSceneImporter); struct AssetImportAnimation { enum Interpolation { @@ -83,36 +67,52 @@ class EditorSceneImporterAssimp : public EditorSceneImporter { }; }; - struct BoneInfo { - uint32_t bone; - float weight; - }; + // ------------------------------------------------------------------------------------------------ + template + const T *ProcessDOMConnection( + const Assimp::FBX::Document *doc, + const char *element_to_find, + uint64_t current_element, + bool reverse = false) { + + const std::vector &conns = reverse ? 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 Assimp::FBX::Connection *con : conns) { + const Assimp::FBX::Object *const source_object = reverse ? con->DestinationObject() : con->SourceObject(); + const Assimp::FBX::Object *const dest_object = reverse ? con->SourceObject() : 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(reverse ? 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 CacheNodeInformation(Ref p_parent_bone, + ImportState &state, const Assimp::FBX::Document *p_doc, + uint64_t p_id); + + void BuildDocumentNodes(Ref parent_transform, ImportState &state, const Assimp::FBX::Document *doc, uint64_t id, Ref fbx_parent); - Ref _generate_mesh_from_surface_indices(ImportState &state, const Vector &p_surface_indices, - const aiNode *assimp_node, Ref &skin, - Skeleton *&skeleton_assigned); - - // simple object creation functions - Spatial *create_light(ImportState &state, - const String &node_name, - Transform &look_at_transform); - Spatial *create_camera( - ImportState &state, - const String &node_name, - Transform &look_at_transform); - // non recursive - linear so must not use recursive arguments - MeshInstance *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform); - // recursive node generator - void _generate_node(ImportState &state, const aiNode *assimp_node); - void _insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id, - int anim_fps, Ref animation, float ticks_per_second, - Skeleton *skeleton, const NodePath &node_path, - const String &node_name, aiBone *track_bone); - - void _import_animation(ImportState &state, int p_animation_index, int p_bake_fps); - Node *get_node_by_name(ImportState &state, String name); - aiBone *get_bone_from_stack(ImportState &state, aiString name); - Spatial *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights); + Spatial *_generate_scene(const String &p_path, const Assimp::FBX::Document *p_document, + const uint32_t p_flags, + int p_bake_fps, const int32_t p_max_bone_weights); template T _interpolate_track(const Vector &p_times, const Vector &p_values, float p_time, AssetImportAnimation::Interpolation p_interp); @@ -120,30 +120,31 @@ class EditorSceneImporterAssimp : public EditorSceneImporter { struct ImportFormat { Vector extensions; - bool is_default; + bool is_default = false; + ImportFormat(){}; + ImportFormat(const Vector &ext, bool def) : + extensions(ext), + is_default(def) { + } }; protected: static void _bind_methods(); public: - EditorSceneImporterAssimp() { - Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE); - unsigned int severity = Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn; - Assimp::DefaultLogger::get()->attachStream(new AssimpStream(), severity); + EditorSceneImporterFBX() { } - ~EditorSceneImporterAssimp() { - Assimp::DefaultLogger::kill(); + ~EditorSceneImporterFBX() { } virtual void get_extensions(List *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, List *r_missing_deps, Error *r_err = NULL); - Ref load_image(ImportState &state, const aiScene *p_scene, String p_path); - - static void RegenerateBoneStack(ImportState &state); - - void RegenerateBoneStack(ImportState &state, aiMesh *mesh); + void + GenFBXWeightInfo(Ref &renderer_mesh_data, const Assimp::FBX::MeshGeometry *mesh_geometry, + Ref st, size_t vertex_id) const; + void create_mesh_data_skin(ImportState &state, const Ref &fbx_node, uint64_t mesh_id); }; -#endif -#endif + +#endif // TOOLS_ENABLED +#endif // EDITOR_SCENE_FBX_IMPORTER_H diff --git a/modules/fbx/readme.md b/modules/fbx/readme.md new file mode 100644 index 000000000000..4ea671e55913 --- /dev/null +++ b/modules/fbx/readme.md @@ -0,0 +1,176 @@ +# 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. + +# 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. + +# 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 + +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 verticies[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. diff --git a/modules/assimp/register_types.cpp b/modules/fbx/register_types.cpp similarity index 92% rename from modules/assimp/register_types.cpp rename to modules/fbx/register_types.cpp index 3af8827bf9f5..176253b95379 100644 --- a/modules/assimp/register_types.cpp +++ b/modules/fbx/register_types.cpp @@ -31,23 +31,23 @@ #include "register_types.h" #include "editor/editor_node.h" -#include "editor_scene_importer_assimp.h" +#include "editor_scene_importer_fbx.h" #ifdef TOOLS_ENABLED static void _editor_init() { - Ref import_assimp; + Ref import_assimp; import_assimp.instance(); ResourceImporterScene::get_singleton()->add_importer(import_assimp); } #endif -void register_assimp_types() { +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(); + ClassDB::register_class(); ClassDB::set_current_api(prev_api); @@ -55,5 +55,5 @@ void register_assimp_types() { #endif } -void unregister_assimp_types() { +void unregister_fbx_types() { } diff --git a/modules/assimp/register_types.h b/modules/fbx/register_types.h similarity index 93% rename from modules/assimp/register_types.h rename to modules/fbx/register_types.h index f399a7acc634..b4aeccfa8af2 100644 --- a/modules/assimp/register_types.h +++ b/modules/fbx/register_types.h @@ -28,10 +28,5 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef ASSIMP_REGISTER_TYPES_H -#define ASSIMP_REGISTER_TYPES_H - -void register_assimp_types(); -void unregister_assimp_types(); - -#endif // ASSIMP_REGISTER_TYPES_H +void register_fbx_types(); +void unregister_fbx_types(); diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp new file mode 100644 index 000000000000..c0dd392cf686 --- /dev/null +++ b/modules/fbx/tools/import_utils.cpp @@ -0,0 +1,150 @@ +/*************************************************************************/ +/* import_utils.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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(Assimp::FBX::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 Assimp::FBX::Model::RotOrder_EulerXYZ: + ret.set_euler_zyx(p_rotation); + break; + + case Assimp::FBX::Model::RotOrder_EulerXZY: + ret.set_euler_yzx(p_rotation); + break; + + case Assimp::FBX::Model::RotOrder_EulerYZX: + ret.set_euler_xzy(p_rotation); + break; + + case Assimp::FBX::Model::RotOrder_EulerYXZ: + ret.set_euler_zxy(p_rotation); + break; + + case Assimp::FBX::Model::RotOrder_EulerZXY: + ret.set_euler_yxz(p_rotation); + break; + + case Assimp::FBX::Model::RotOrder_EulerZYX: + ret.set_euler_xyz(p_rotation); + break; + + case Assimp::FBX::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(Assimp::FBX::Model::RotOrder mode, const Vector3 &p_rotation) { + return ImportUtils::EulerToBasis(mode, p_rotation); +} + +Vector3 ImportUtils::BasisToEuler(Assimp::FBX::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 Assimp::FBX::Model::RotOrder_EulerXYZ: + return p_rotation.get_euler_zyx(); + + case Assimp::FBX::Model::RotOrder_EulerXZY: + return p_rotation.get_euler_yzx(); + + case Assimp::FBX::Model::RotOrder_EulerYZX: + return p_rotation.get_euler_xzy(); + + case Assimp::FBX::Model::RotOrder_EulerYXZ: + return p_rotation.get_euler_zxy(); + + case Assimp::FBX::Model::RotOrder_EulerZXY: + return p_rotation.get_euler_yxz(); + + case Assimp::FBX::Model::RotOrder_EulerZYX: + return p_rotation.get_euler_xyz(); + + case Assimp::FBX::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(Assimp::FBX::Model::RotOrder mode, const Quat &p_rotation) { + return BasisToEuler(mode, p_rotation); +} + +Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) { + return Transform(p_initial.basis, p_initial.origin * p_scale); +} + +Vector3 get_poly_normal(const std::vector &p_vertices) { + ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necesary"); + // 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); + } +} diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h new file mode 100644 index 000000000000..c5360cb9fcc6 --- /dev/null +++ b/modules/fbx/tools/import_utils.h @@ -0,0 +1,425 @@ +/*************************************************************************/ +/* import_utils.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "modules/fbx/data/import_state.h" +#include "thirdparty/assimp_fbx/FBXDocument.h" + +#include "core/io/image_loader.h" +#include + +#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL + +#define AI_PROPERTIES aiTextureType_UNKNOWN, 0 +#define AI_NULL 0, 0 +#define AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR "$raw.Maya|baseColor" +#define AI_MATKEY_FBX_MAYA_METALNESS_FACTOR "$raw.Maya|metalness" +#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR "$raw.Maya|diffuseRoughness" + +#define AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE "$raw.Maya|emissionColor|file" +#define AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR "$raw.Maya|emission" +#define AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE "$raw.Maya|metalness|file" +#define AI_MATKEY_FBX_MAYA_METALNESS_UV_XFORM "$raw.Maya|metalness|uvtrafo" +#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE "$raw.Maya|diffuseRoughness|file" +#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_UV_XFORM "$raw.Maya|diffuseRoughness|uvtrafo" +#define AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE "$raw.Maya|baseColor|file" +#define AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM "$raw.Maya|baseColor|uvtrafo" +#define AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE "$raw.Maya|normalCamera|file" +#define AI_MATKEY_FBX_MAYA_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo" + +#define AI_MATKEY_FBX_NORMAL_TEXTURE "$raw.Maya|normalCamera|file" +#define AI_MATKEY_FBX_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo" + +#define AI_MATKEY_FBX_MAYA_STINGRAY_DISPLACEMENT_SCALING_FACTOR "$raw.Maya|displacementscaling" +#define AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR "$raw.Maya|base_color" +#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR "$raw.Maya|emissive" +#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR "$raw.Maya|metallic" +#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR "$raw.Maya|roughness" +#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR "$raw.Maya|emissive_intensity" + +#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE "$raw.Maya|TEX_normal_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_UV_XFORM "$raw.Maya|TEX_normal_map|uvtrafo" +#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE "$raw.Maya|TEX_color_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM "$raw.Maya|TEX_color_map|uvtrafo" +#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE "$raw.Maya|TEX_metallic_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_UV_XFORM "$raw.Maya|TEX_metallic_map|uvtrafo" +#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE "$raw.Maya|TEX_roughness_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_UV_XFORM "$raw.Maya|TEX_roughness_map|uvtrafo" +#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE "$raw.Maya|TEX_emissive_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_UV_XFORM "$raw.Maya|TEX_emissive_map|uvtrafo" +#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_TEXTURE "$raw.Maya|TEX_ao_map|file" +#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_UV_XFORM "$raw.Maya|TEX_ao_map|uvtrafo" + +/** + * 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(Assimp::FBX::Model::RotOrder mode, const Vector3 &p_rotation); + + /// Converts rotation order vector (in rad) to quaternion. + static Quat EulerToQuaternion(Assimp::FBX::Model::RotOrder mode, const Vector3 &p_rotation); + + /// Converts basis into rotation order vector (in rad). + static Vector3 BasisToEuler(Assimp::FBX::Model::RotOrder mode, const Basis &p_rotation); + + /// Converts quaternion into rotation order vector (in rad). + static Vector3 QuaternionToEuler(Assimp::FBX::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 &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 Assimp::FBX::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 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 load_image(ImportState &state, const aiScene *p_scene, String p_path){ + + // Map >::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 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()); + // 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 img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); + // ERR_FAIL_COND_V(img.is_null(), Ref()); + // state.path_to_image_cache.insert(p_path, img); + // return img; + // } else if (tex->CheckFormat("jpg")) { + // Ref img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); + // ERR_FAIL_COND_V(img.is_null(), Ref()); + // state.path_to_image_cache.insert(p_path, img); + // return img; + // } else if (tex->CheckFormat("dds")) { + // ERR_FAIL_COND_V_MSG(true, Ref(), "Open Asset Import: Embedded dds not implemented"); + // } + // } else { + // Ref 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()); + // //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()); + // state.path_to_image_cache.insert(p_path, img); + // return img; + // } + // return Ref(); + // } else { + // Ref texture = ResourceLoader::load(p_path); + // ERR_FAIL_COND_V(texture.is_null(), Ref()); + // Ref image = texture->get_data(); + // ERR_FAIL_COND_V(image.is_null(), Ref()); + // state.path_to_image_cache.insert(p_path, image); + // return image; + // } + + // return Ref(); + //} + + // /* 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 &p_vertices); + +#endif // IMPORT_UTILS_FBX_IMPORTER_H diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index a1f0f0ef6aee..6b12dc3170d2 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -36,7 +36,7 @@ #include #include -Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) { +Error ImageLoaderJPG::jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) { jpgd::jpeg_decoder_mem_stream mem_stream(p_buffer, p_buffer_len); @@ -130,7 +130,7 @@ static Ref _jpegd_mem_loader_func(const uint8_t *p_png, int p_size) { Ref img; img.instance(); - Error err = jpeg_load_image_from_buffer(img.ptr(), p_png, p_size); + Error err = ImageLoaderJPG::jpeg_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref()); return img; } diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index 9ef37ae30308..2e8d07e2a491 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -36,6 +36,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: + static Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len); virtual Error load_image(Ref p_image, FileAccess *f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List *p_extensions) const; ImageLoaderJPG(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e4f1e976159d..15396ce3c753 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1845,7 +1845,7 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che void Viewport::_gui_input_event(Ref p_event) { - ERR_FAIL_COND(p_event.is_null()) + ERR_FAIL_COND(p_event.is_null()); //? /* diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index f386ca664211..f13d18e9090e 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -204,7 +204,10 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor } } -void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights, int p_canvas_layer_id) { +void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights) { + + if (!p_masked_lights) + return; RasterizerCanvas::Item *ci = p_canvas_item; @@ -213,7 +216,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite RasterizerCanvas::Light *light = p_masked_lights; while (light) { - if ((p_canvas_layer_id >= light->layer_min) && (p_canvas_layer_id <= light->layer_max) && (ci->light_mask & light->item_mask) && (p_z >= light->z_min) && (p_z <= light->z_max) && (ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache))) { + if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { ci->light_masked = true; } @@ -224,7 +227,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite } } -void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, int p_canvas_layer_id) { +void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { VSG::canvas_render->canvas_begin(); @@ -264,7 +267,7 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr continue; if (p_masked_lights) { - _light_mask_canvas_items(VS::CANVAS_ITEM_Z_MIN + i, z_list[i], p_masked_lights, p_canvas_layer_id); + _light_mask_canvas_items(VS::CANVAS_ITEM_Z_MIN + i, z_list[i], p_masked_lights); } VSG::canvas_render->canvas_render_items(z_list[i], VS::CANVAS_ITEM_Z_MIN + i, p_canvas->modulate, p_lights, p_transform); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 2303ec03db00..a2c641ce76f2 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -159,13 +159,13 @@ class VisualServerCanvas { private: void _render_canvas_item_tree(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); void _render_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); - void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights, int p_canvas_layer_id); + void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights); RasterizerCanvas::Item **z_list; RasterizerCanvas::Item **z_last_list; public: - void render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, int p_canvas_layer_id); + void render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect); RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 6e70e934342b..1b909743a7f6 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -229,16 +229,15 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E RasterizerCanvas::Light *canvas_lights = NULL; RasterizerCanvas::Light *ptr = lights; - int canvas_layer_id = E->get()->layer; while (ptr) { - if (canvas_layer_id >= ptr->layer_min && canvas_layer_id <= ptr->layer_max) { + if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { ptr->next_ptr = canvas_lights; canvas_lights = ptr; } ptr = ptr->filter_next_ptr; } - VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect, canvas_layer_id); + VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect); i++; if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { diff --git a/thirdparty/assimp/code/CApi/AssimpCExport.cpp b/thirdparty/assimp/code/CApi/AssimpCExport.cpp deleted file mode 100644 index 7557edcfc6a4..000000000000 --- a/thirdparty/assimp/code/CApi/AssimpCExport.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AssimpCExport.cpp -Assimp C export interface. See Exporter.cpp for some notes. -*/ - -#ifndef ASSIMP_BUILD_NO_EXPORT - -#include "CInterfaceIOWrapper.h" -#include -#include "Common/ScenePrivate.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API size_t aiGetExportFormatCount(void) -{ - return Exporter().GetExportFormatCount(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index) -{ - // Note: this is valid as the index always pertains to a built-in exporter, - // for which the returned structure is guaranteed to be of static storage duration. - Exporter exporter; - const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) ); - if (NULL == orig) { - return NULL; - } - - aiExportFormatDesc *desc = new aiExportFormatDesc; - desc->description = new char[ strlen( orig->description ) + 1 ](); - ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) ); - desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ](); - ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) ); - desc->id = new char[ strlen( orig->id ) + 1 ](); - ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) ); - - return desc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) { - if (NULL == desc) { - return; - } - - delete [] desc->description; - delete [] desc->fileExtension; - delete [] desc->id; - delete desc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut) -{ - if (!pOut || !pIn) { - return; - } - - SceneCombiner::CopyScene(pOut,pIn,true); - ScenePriv(*pOut)->mIsCopy = true; -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn) -{ - // note: aiReleaseImport() is also able to delete scene copies, but in addition - // it also handles scenes with import metadata. - delete pIn; -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing ) -{ - return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing); -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing ) -{ - Exporter exp; - - if (pIO) { - exp.SetIOHandler(new CIOSystemWrapper(pIO)); - } - return exp.Export(pScene,pFormatId,pFileName,pPreprocessing); -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing ) -{ - Exporter exp; - if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) { - return NULL; - } - const aiExportDataBlob* blob = exp.GetOrphanedBlob(); - ai_assert(blob); - - return blob; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData ) -{ - delete pData; -} - -#endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp b/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp deleted file mode 100644 index 5a3a49565a14..000000000000 --- a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 aiFileIO -> IOSystem wrapper*/ - -#include "CInterfaceIOWrapper.h" - -namespace Assimp { - -CIOStreamWrapper::~CIOStreamWrapper(void) -{ - /* Various places depend on this destructor to close the file */ - if (mFile) { - mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); - mFile = nullptr; - } -} - -// ................................................................... -size_t CIOStreamWrapper::Read(void* pvBuffer, - size_t pSize, - size_t pCount -){ - // need to typecast here as C has no void* - return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount); -} - -// ................................................................... -size_t CIOStreamWrapper::Write(const void* pvBuffer, - size_t pSize, - size_t pCount -){ - // need to typecast here as C has no void* - return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount); -} - -// ................................................................... -aiReturn CIOStreamWrapper::Seek(size_t pOffset, - aiOrigin pOrigin -){ - return mFile->SeekProc(mFile,pOffset,pOrigin); -} - -// ................................................................... -size_t CIOStreamWrapper::Tell(void) const { - return mFile->TellProc(mFile); -} - -// ................................................................... -size_t CIOStreamWrapper::FileSize() const { - return mFile->FileSizeProc(mFile); -} - -// ................................................................... -void CIOStreamWrapper::Flush () { - return mFile->FlushProc(mFile); -} - -// ------------------------------------------------------------------------------------------------ -// Custom IOStream implementation for the C-API -bool CIOSystemWrapper::Exists( const char* pFile) const { - aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb"); - if (p){ - mFileSystem->CloseProc(mFileSystem,p); - return true; - } - return false; -} - -// ................................................................... -char CIOSystemWrapper::getOsSeparator() const { -#ifndef _WIN32 - return '/'; -#else - return '\\'; -#endif -} - -// ................................................................... -IOStream* CIOSystemWrapper::Open(const char* pFile,const char* pMode) { - aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode); - if (!p) { - return NULL; - } - return new CIOStreamWrapper(p, this); -} - -// ................................................................... -void CIOSystemWrapper::Close( IOStream* pFile) { - if (!pFile) { - return; - } - delete pFile; -} - -} diff --git a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h b/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h deleted file mode 100644 index 21623203021e..000000000000 --- a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 aiFileIO -> IOSystem wrapper*/ - -#ifndef AI_CIOSYSTEM_H_INCLUDED -#define AI_CIOSYSTEM_H_INCLUDED - -#include -#include -#include - -namespace Assimp { - -class CIOSystemWrapper; - -// ------------------------------------------------------------------------------------------------ -// Custom IOStream implementation for the C-API -class CIOStreamWrapper : public IOStream -{ -public: - explicit CIOStreamWrapper(aiFile* pFile, CIOSystemWrapper* io) - : mFile(pFile), - mIO(io) - {} - ~CIOStreamWrapper(void); - - size_t Read(void* pvBuffer, size_t pSize, size_t pCount); - size_t Write(const void* pvBuffer, size_t pSize, size_t pCount); - aiReturn Seek(size_t pOffset, aiOrigin pOrigin); - size_t Tell(void) const; - size_t FileSize() const; - void Flush(); - -private: - aiFile* mFile; - CIOSystemWrapper* mIO; -}; - -class CIOSystemWrapper : public IOSystem -{ - friend class CIOStreamWrapper; -public: - explicit CIOSystemWrapper(aiFileIO* pFile) - : mFileSystem(pFile) - {} - - bool Exists( const char* pFile) const; - char getOsSeparator() const; - IOStream* Open(const char* pFile,const char* pMode = "rb"); - void Close( IOStream* pFile); -private: - aiFileIO* mFileSystem; -}; - -} - -#endif - diff --git a/thirdparty/assimp/code/Common/Assimp.cpp b/thirdparty/assimp/code/Common/Assimp.cpp deleted file mode 100644 index 178b2c01d0e8..000000000000 --- a/thirdparty/assimp/code/Common/Assimp.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Assimp.cpp - * @brief Implementation of the Plain-C API - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CApi/CInterfaceIOWrapper.h" -#include "Importer.h" -#include "ScenePrivate.h" - -#include - -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_SINGLETHREADED -# include -# include -#endif -// ------------------------------------------------------------------------------------------------ -using namespace Assimp; - -namespace Assimp { - // underlying structure for aiPropertyStore - typedef BatchLoader::PropertyMap PropertyMap; - - /** Stores the LogStream objects for all active C log streams */ - struct mpred { - bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { - return s0.callback LogStreamMap; - - /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ - typedef std::list PredefLogStreamMap; - - /** Local storage of all active log streams */ - static LogStreamMap gActiveLogStreams; - - /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ - static PredefLogStreamMap gPredefinedStreams; - - /** Error message of the last failed import process */ - static std::string gLastErrorString; - - /** Verbose logging active or not? */ - static aiBool gVerboseLogging = false; - - /** will return all registered importers. */ - void GetImporterInstanceList(std::vector< BaseImporter* >& out); - - /** will delete all registered importers. */ - void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); -} // namespace assimp - - -#ifndef ASSIMP_BUILD_SINGLETHREADED -/** Global mutex to manage the access to the log-stream map */ -static std::mutex gLogStreamMutex; -#endif - -// ------------------------------------------------------------------------------------------------ -// Custom LogStream implementation for the C-API -class LogToCallbackRedirector : public LogStream { -public: - explicit LogToCallbackRedirector(const aiLogStream& s) - : stream (s) { - ai_assert(NULL != s.callback); - } - - ~LogToCallbackRedirector() { -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(gLogStreamMutex); -#endif - // (HACK) Check whether the 'stream.user' pointer points to a - // custom LogStream allocated by #aiGetPredefinedLogStream. - // In this case, we need to delete it, too. Of course, this - // might cause strange problems, but the chance is quite low. - - PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), - gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); - - if (it != gPredefinedStreams.end()) { - delete *it; - gPredefinedStreams.erase(it); - } - } - - /** @copydoc LogStream::write */ - void write(const char* message) { - stream.callback(message,stream.user); - } - -private: - aiLogStream stream; -}; - -// ------------------------------------------------------------------------------------------------ -void ReportSceneNotFoundError() { - ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. " - "The C-API does not accept scenes produced by the C++ API and vice versa"); - - ai_assert(false); -} - -// ------------------------------------------------------------------------------------------------ -// Reads the given file and returns its content. -const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) { - return aiImportFileEx(pFile,pFlags,NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) { - return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, - aiFileIO* pFS, const aiPropertyStore* props) { - ai_assert(NULL != pFile); - - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); - - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } - // setup a custom IO system if necessary - if (pFS) { - imp->SetIOHandler( new CIOSystemWrapper (pFS) ); - } - - // and have it read the file - scene = imp->ReadFile( pFile, pFlags); - - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } - - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - - return scene; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemory( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint) -{ - return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemoryWithProperties( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint, - const aiPropertyStore* props) -{ - ai_assert( NULL != pBuffer ); - ai_assert( 0 != pLength ); - - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); - - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } - - // and have it read the file from the memory buffer - scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); - - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } - else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return scene; -} - -// ------------------------------------------------------------------------------------------------ -// Releases all resources associated with the given import process. -void aiReleaseImport( const aiScene* pScene) -{ - if (!pScene) { - return; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - delete pScene; - } - else { - // deleting the Importer also deletes the scene - // Note: the reason that this is not written as 'delete priv->mOrigImporter' - // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) - Importer* importer = priv->mOrigImporter; - delete importer; - } - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, - unsigned int pFlags) -{ - const aiScene* sc = NULL; - - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return NULL; - } - - sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); - - if (!sc) { - aiReleaseImport(pScene); - return NULL; - } - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return sc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene, - BaseProcess* process, - bool requestValidation ) { - const aiScene* sc( NULL ); - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv( scene ); - if ( NULL == priv || NULL == priv->mOrigImporter ) { - ReportSceneNotFoundError(); - return NULL; - } - - sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation ); - - if ( !sc ) { - aiReleaseImport( scene ); - return NULL; - } - - ASSIMP_END_EXCEPTION_REGION( const aiScene* ); - - return sc; -} - -// ------------------------------------------------------------------------------------------------ -void CallbackToLogRedirector (const char* msg, char* dt) -{ - ai_assert( NULL != msg ); - ai_assert( NULL != dt ); - LogStream* s = (LogStream*)dt; - - s->write(msg); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file) -{ - aiLogStream sout; - - ASSIMP_BEGIN_EXCEPTION_REGION(); - LogStream* stream = LogStream::createDefaultStream(pStream,file); - if (!stream) { - sout.callback = NULL; - sout.user = NULL; - } - else { - sout.callback = &CallbackToLogRedirector; - sout.user = (char*)stream; - } - gPredefinedStreams.push_back(stream); - ASSIMP_END_EXCEPTION_REGION(aiLogStream); - return sout; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiAttachLogStream( const aiLogStream* stream ) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(gLogStreamMutex); -#endif - - LogStream* lg = new LogToCallbackRedirector(*stream); - gActiveLogStreams[*stream] = lg; - - if (DefaultLogger::isNullLogger()) { - DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - DefaultLogger::get()->attachStream(lg); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(gLogStreamMutex); -#endif - // find the log-stream associated with this data - LogStreamMap::iterator it = gActiveLogStreams.find( *stream); - // it should be there... else the user is playing fools with us - if( it == gActiveLogStreams.end()) { - return AI_FAILURE; - } - DefaultLogger::get()->detatchStream( it->second ); - delete it->second; - - gActiveLogStreams.erase( it); - - if (gActiveLogStreams.empty()) { - DefaultLogger::kill(); - } - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiDetachAllLogStreams(void) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(gLogStreamMutex); -#endif - Logger *logger( DefaultLogger::get() ); - if ( NULL == logger ) { - return; - } - - for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { - logger->detatchStream( it->second ); - delete it->second; - } - gActiveLogStreams.clear(); - DefaultLogger::kill(); - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiEnableVerboseLogging(aiBool d) -{ - if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - gVerboseLogging = d; -} - -// ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. -const char* aiGetErrorString() -{ - return gLastErrorString.c_str(); -} - -// ----------------------------------------------------------------------------------------------- -// Return the description of a importer given its index -const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex) -{ - return Importer().GetImporterInfo(pIndex); -} - -// ----------------------------------------------------------------------------------------------- -// Return the number of importers -size_t aiGetImportFormatCount(void) -{ - return Importer().GetImporterCount(); -} - -// ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. -aiBool aiIsExtensionSupported(const char* szExtension) -{ - ai_assert(NULL != szExtension); - aiBool candoit=AI_FALSE; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; - - ASSIMP_END_EXCEPTION_REGION(aiBool); - return candoit; -} - -// ------------------------------------------------------------------------------------------------ -// Get a list of all file extensions supported by ASSIMP -void aiGetExtensionList(aiString* szOut) -{ - ai_assert(NULL != szOut); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - tmp.GetExtensionList(*szOut); - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements for a particular import. -void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn, - C_STRUCT aiMemoryInfo* in) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pIn); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return; - } - - return priv->mOrigImporter->GetMemoryRequirements(*in); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) -{ - return reinterpret_cast( new PropertyMap() ); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) -{ - delete reinterpret_cast(p); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyInteger -ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->ints,szName,value); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyFloat -ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, ai_real value) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->floats,szName,value); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyString -ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName, - const C_STRUCT aiString* st) -{ - if (!st) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->strings,szName,std::string(st->C_Str())); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyMatrix -ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName, - const C_STRUCT aiMatrix4x4* mat) -{ - if (!mat) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast(p); - SetGenericProperty(pp->matrices,szName,*mat); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Rotation matrix to quaternion -ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) -{ - ai_assert( NULL != quat ); - ai_assert( NULL != mat ); - *quat = aiQuaternion(*mat); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix decomposition -ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, - aiQuaternion* rotation, - aiVector3D* position) -{ - ai_assert( NULL != rotation ); - ai_assert( NULL != position ); - ai_assert( NULL != scaling ); - ai_assert( NULL != mat ); - mat->Decompose(*scaling,*rotation,*position); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix transpose -ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) -{ - ai_assert(NULL != mat); - mat->Transpose(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) -{ - ai_assert(NULL != mat); - mat->Transpose(); -} - -// ------------------------------------------------------------------------------------------------ -// Vector transformation -ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, - const aiMatrix3x3* mat) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != vec); - *vec *= (*mat); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, - const aiMatrix4x4* mat) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != vec ); - - *vec *= (*mat); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix multiplication -ASSIMP_API void aiMultiplyMatrix4( - aiMatrix4x4* dst, - const aiMatrix4x4* src) -{ - ai_assert( NULL != dst ); - ai_assert( NULL != src ); - *dst = (*dst) * (*src); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiMultiplyMatrix3( - aiMatrix3x3* dst, - const aiMatrix3x3* src) -{ - ai_assert( NULL != dst ); - ai_assert( NULL != src ); - *dst = (*dst) * (*src); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix identity -ASSIMP_API void aiIdentityMatrix3( - aiMatrix3x3* mat) -{ - ai_assert(NULL != mat); - *mat = aiMatrix3x3(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiIdentityMatrix4( - aiMatrix4x4* mat) -{ - ai_assert(NULL != mat); - *mat = aiMatrix4x4(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) { - if( NULL == extension ) { - return NULL; - } - const aiImporterDesc *desc( NULL ); - std::vector< BaseImporter* > out; - GetImporterInstanceList( out ); - for( size_t i = 0; i < out.size(); ++i ) { - if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) { - desc = out[ i ]->GetInfo(); - break; - } - } - - DeleteImporterInstanceList(out); - - return desc; -} - -// ------------------------------------------------------------------------------------------------ diff --git a/thirdparty/assimp/code/Common/BaseImporter.cpp b/thirdparty/assimp/code/Common/BaseImporter.cpp deleted file mode 100644 index 5c1e60554949..000000000000 --- a/thirdparty/assimp/code/Common/BaseImporter.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 BaseImporter.cpp - * @brief Implementation of BaseImporter - */ - -#include -#include -#include "FileSystemFilter.h" -#include "Importer.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -BaseImporter::BaseImporter() AI_NO_EXCEPT -: m_progress() { - /** - * Assimp Importer - * unit conversions available - * if you need another measurment unit add it below. - * it's currently defined in assimp that we prefer meters. - * - * NOTE: Initialised here rather than in the header file - * to workaround a VS2013 bug with brace initialisers - * */ - importerUnits[ImporterUnits::M] = 1.0; - importerUnits[ImporterUnits::CM] = 0.01; - importerUnits[ImporterUnits::MM] = 0.001; - importerUnits[ImporterUnits::INCHES] = 0.0254; - importerUnits[ImporterUnits::FEET] = 0.3048; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseImporter::~BaseImporter() { - // nothing to do here -} - -void BaseImporter::UpdateImporterScale( Importer* pImp ) -{ - ai_assert(pImp != nullptr); - ai_assert(importerScale != 0.0); - ai_assert(fileScale != 0.0); - - double activeScale = importerScale * fileScale; - - // Set active scaling - pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast( activeScale) ); - - ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale ); -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file and returns the imported data. -aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) { - - - m_progress = pImp->GetProgressHandler(); - if (nullptr == m_progress) { - return nullptr; - } - - ai_assert(m_progress); - - // Gather configuration properties for this run - SetupProperties( pImp ); - - // Construct a file system filter to improve our success ratio at reading external files - FileSystemFilter filter(pFile,pIOHandler); - - // create a scene object to hold the data - std::unique_ptr sc(new aiScene()); - - // dispatch importing - try - { - InternReadFile( pFile, sc.get(), &filter); - - // Calculate import scale hook - required because pImp not available anywhere else - // passes scale into ScaleProcess - UpdateImporterScale(pImp); - - - } catch( const std::exception& err ) { - // extract error description - m_ErrorText = err.what(); - ASSIMP_LOG_ERROR(m_ErrorText); - return nullptr; - } - - // return what we gathered from the import. - return sc.release(); -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::SetupProperties(const Importer* pImp) -{ - // the default implementation does nothing -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::GetExtensionList(std::set& extensions) { - const aiImporterDesc* desc = GetInfo(); - ai_assert(desc != nullptr); - - const char* ext = desc->mFileExtensions; - ai_assert(ext != nullptr ); - - const char* last = ext; - do { - if (!*ext || *ext == ' ') { - extensions.insert(std::string(last,ext-last)); - ai_assert(ext-last > 0); - last = ext; - while(*last == ' ') { - ++last; - } - } - } - while(*ext++); -} - -// ------------------------------------------------------------------------------------------------ -/*static*/ bool BaseImporter::SearchFileHeaderForToken( IOSystem* pIOHandler, - const std::string& pFile, - const char** tokens, - unsigned int numTokens, - unsigned int searchBytes /* = 200 */, - bool tokensSol /* false */, - bool noAlphaBeforeTokens /* false */) -{ - ai_assert( nullptr != tokens ); - ai_assert( 0 != numTokens ); - ai_assert( 0 != searchBytes); - - if ( nullptr == pIOHandler ) { - return false; - } - - std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - // read 200 characters from the file - std::unique_ptr _buffer (new char[searchBytes+1 /* for the '\0' */]); - char *buffer( _buffer.get() ); - const size_t read( pStream->Read(buffer,1,searchBytes) ); - if( 0 == read ) { - return false; - } - - for( size_t i = 0; i < read; ++i ) { - buffer[ i ] = static_cast( ::tolower( buffer[ i ] ) ); - } - - // It is not a proper handling of unicode files here ... - // ehm ... but it works in most cases. - char* cur = buffer,*cur2 = buffer,*end = &buffer[read]; - while (cur != end) { - if( *cur ) { - *cur2++ = *cur; - } - ++cur; - } - *cur2 = '\0'; - - std::string token; - for (unsigned int i = 0; i < numTokens; ++i ) { - ai_assert( nullptr != tokens[i] ); - const size_t len( strlen( tokens[ i ] ) ); - token.clear(); - const char *ptr( tokens[ i ] ); - for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) { - token.push_back( static_cast( tolower( *ptr ) ) ); - ++ptr; - } - const char* r = strstr( buffer, token.c_str() ); - if( !r ) { - continue; - } - // We need to make sure that we didn't accidentially identify the end of another token as our token, - // e.g. in a previous version the "gltf " present in some gltf files was detected as "f " - if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) { - continue; - } - // We got a match, either we don't care where it is, or it happens to - // be in the beginning of the file / line - if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { - ASSIMP_LOG_DEBUG_F( "Found positive match for header keyword: ", tokens[i] ); - return true; - } - } - } - - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Simple check for file extension -/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, - const char* ext0, - const char* ext1, - const char* ext2) -{ - std::string::size_type pos = pFile.find_last_of('.'); - - // no file extension - can't read - if( pos == std::string::npos) - return false; - - const char* ext_real = & pFile[ pos+1 ]; - if( !ASSIMP_stricmp(ext_real,ext0) ) - return true; - - // check for other, optional, file extensions - if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) - return true; - - if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) - return true; - - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Get file extension from path -std::string BaseImporter::GetExtension( const std::string& file ) { - std::string::size_type pos = file.find_last_of('.'); - - // no file extension at all - if (pos == std::string::npos) { - return ""; - } - - - // thanks to Andy Maloney for the hint - std::string ret = file.substr( pos + 1 ); - std::transform( ret.begin(), ret.end(), ret.begin(), ToLower); - - return ret; -} - -// ------------------------------------------------------------------------------------------------ -// Check for magic bytes at the beginning of the file. -/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, - const void* _magic, unsigned int num, unsigned int offset, unsigned int size) -{ - ai_assert( size <= 16 ); - ai_assert( _magic ); - - if (!pIOHandler) { - return false; - } - union { - const char* magic; - const uint16_t* magic_u16; - const uint32_t* magic_u32; - }; - magic = reinterpret_cast(_magic); - std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - - // skip to offset - pStream->Seek(offset,aiOrigin_SET); - - // read 'size' characters from the file - union { - char data[16]; - uint16_t data_u16[8]; - uint32_t data_u32[4]; - }; - if(size != pStream->Read(data,1,size)) { - return false; - } - - for (unsigned int i = 0; i < num; ++i) { - // also check against big endian versions of tokens with size 2,4 - // that's just for convenience, the chance that we cause conflicts - // is quite low and it can save some lines and prevent nasty bugs - if (2 == size) { - uint16_t rev = *magic_u16; - ByteSwap::Swap(&rev); - if (data_u16[0] == *magic_u16 || data_u16[0] == rev) { - return true; - } - } - else if (4 == size) { - uint32_t rev = *magic_u32; - ByteSwap::Swap(&rev); - if (data_u32[0] == *magic_u32 || data_u32[0] == rev) { - return true; - } - } - else { - // any length ... just compare - if(!memcmp(magic,data,size)) { - return true; - } - } - magic += size; - } - } - return false; -} - -#ifdef ASSIMP_USE_HUNTER -# include -#else -# include "../contrib/utf8cpp/source/utf8.h" -#endif - -// ------------------------------------------------------------------------------------------------ -// Convert to UTF8 data -void BaseImporter::ConvertToUTF8(std::vector& data) -{ - //ConversionResult result; - if(data.size() < 8) { - throw DeadlyImportError("File is too small"); - } - - // UTF 8 with BOM - if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { - ASSIMP_LOG_DEBUG("Found UTF-8 BOM ..."); - - std::copy(data.begin()+3,data.end(),data.begin()); - data.resize(data.size()-3); - return; - } - - - // UTF 32 BE with BOM - if(*((uint32_t*)&data.front()) == 0xFFFE0000) { - - // swap the endianness .. - for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) { - AI_SWAP4P(p); - } - } - - // UTF 32 LE with BOM - if(*((uint32_t*)&data.front()) == 0x0000FFFE) { - ASSIMP_LOG_DEBUG("Found UTF-32 BOM ..."); - - std::vector output; - int *ptr = (int*)&data[ 0 ]; - int *end = ptr + ( data.size() / sizeof(int) ) +1; - utf8::utf32to8( ptr, end, back_inserter(output)); - return; - } - - // UTF 16 BE with BOM - if(*((uint16_t*)&data.front()) == 0xFFFE) { - - // swap the endianness .. - for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) { - ByteSwap::Swap2(p); - } - } - - // UTF 16 LE with BOM - if(*((uint16_t*)&data.front()) == 0xFEFF) { - ASSIMP_LOG_DEBUG("Found UTF-16 BOM ..."); - - std::vector output; - utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); - return; - } -} - -// ------------------------------------------------------------------------------------------------ -// Convert to UTF8 data to ISO-8859-1 -void BaseImporter::ConvertUTF8toISO8859_1(std::string& data) -{ - size_t size = data.size(); - size_t i = 0, j = 0; - - while(i < size) { - if ((unsigned char) data[i] < (size_t) 0x80) { - data[j] = data[i]; - } else if(i < size - 1) { - if((unsigned char) data[i] == 0xC2) { - data[j] = data[++i]; - } else if((unsigned char) data[i] == 0xC3) { - data[j] = ((unsigned char) data[++i] + 0x40); - } else { - std::stringstream stream; - stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; - ASSIMP_LOG_ERROR( stream.str() ); - - data[j++] = data[i++]; - data[j] = data[i]; - } - } else { - ASSIMP_LOG_ERROR("UTF8 code but only one character remaining"); - - data[j] = data[i]; - } - - i++; j++; - } - - data.resize(j); -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::TextFileToBuffer(IOStream* stream, - std::vector& data, - TextFileMode mode) -{ - ai_assert(nullptr != stream); - - const size_t fileSize = stream->FileSize(); - if (mode == FORBID_EMPTY) { - if(!fileSize) { - throw DeadlyImportError("File is empty"); - } - } - - data.reserve(fileSize+1); - data.resize(fileSize); - if(fileSize > 0) { - if(fileSize != stream->Read( &data[0], 1, fileSize)) { - throw DeadlyImportError("File read error"); - } - - ConvertToUTF8(data); - } - - // append a binary zero to simplify string parsing - data.push_back(0); -} - -// ------------------------------------------------------------------------------------------------ -namespace Assimp { - // Represents an import request - struct LoadRequest { - LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) - : file(_file) - , flags(_flags) - , refCnt(1) - , scene(NULL) - , loaded(false) - , id(_id) { - if ( _map ) { - map = *_map; - } - } - - bool operator== ( const std::string& f ) const { - return file == f; - } - - const std::string file; - unsigned int flags; - unsigned int refCnt; - aiScene *scene; - bool loaded; - BatchLoader::PropertyMap map; - unsigned int id; - }; -} - -// ------------------------------------------------------------------------------------------------ -// BatchLoader::pimpl data structure -struct Assimp::BatchData { - BatchData( IOSystem* pIO, bool validate ) - : pIOSystem( pIO ) - , pImporter( nullptr ) - , next_id(0xffff) - , validate( validate ) { - ai_assert( nullptr != pIO ); - - pImporter = new Importer(); - pImporter->SetIOHandler( pIO ); - } - - ~BatchData() { - pImporter->SetIOHandler( nullptr ); /* get pointer back into our possession */ - delete pImporter; - } - - // IO system to be used for all imports - IOSystem* pIOSystem; - - // Importer used to load all meshes - Importer* pImporter; - - // List of all imports - std::list requests; - - // Base path - std::string pathBase; - - // Id for next item - unsigned int next_id; - - // Validation enabled state - bool validate; -}; - -typedef std::list::iterator LoadReqIt; - -// ------------------------------------------------------------------------------------------------ -BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) { - ai_assert(nullptr != pIO); - - m_data = new BatchData( pIO, validate ); -} - -// ------------------------------------------------------------------------------------------------ -BatchLoader::~BatchLoader() -{ - // delete all scenes what have not been polled by the user - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - delete (*it).scene; - } - delete m_data; -} - -// ------------------------------------------------------------------------------------------------ -void BatchLoader::setValidation( bool enabled ) { - m_data->validate = enabled; -} - -// ------------------------------------------------------------------------------------------------ -bool BatchLoader::getValidation() const { - return m_data->validate; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int BatchLoader::AddLoadRequest(const std::string& file, - unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) -{ - ai_assert(!file.empty()); - - // check whether we have this loading request already - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - // Call IOSystem's path comparison function here - if ( m_data->pIOSystem->ComparePaths((*it).file,file)) { - if (map) { - if ( !( ( *it ).map == *map ) ) { - continue; - } - } - else if ( !( *it ).map.empty() ) { - continue; - } - - (*it).refCnt++; - return (*it).id; - } - } - - // no, we don't have it. So add it to the queue ... - m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id)); - return m_data->next_id++; -} - -// ------------------------------------------------------------------------------------------------ -aiScene* BatchLoader::GetImport( unsigned int which ) -{ - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - if ((*it).id == which && (*it).loaded) { - aiScene* sc = (*it).scene; - if (!(--(*it).refCnt)) { - m_data->requests.erase(it); - } - return sc; - } - } - return nullptr; -} - - - -// ------------------------------------------------------------------------------------------------ -void BatchLoader::LoadAll() -{ - // no threaded implementation for the moment - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - // force validation in debug builds - unsigned int pp = (*it).flags; - if ( m_data->validate ) { - pp |= aiProcess_ValidateDataStructure; - } - - // setup config properties if necessary - ImporterPimpl* pimpl = m_data->pImporter->Pimpl(); - pimpl->mFloatProperties = (*it).map.floats; - pimpl->mIntProperties = (*it).map.ints; - pimpl->mStringProperties = (*it).map.strings; - pimpl->mMatrixProperties = (*it).map.matrices; - - if (!DefaultLogger::isNullLogger()) - { - ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%"); - ASSIMP_LOG_INFO_F("File: ", (*it).file); - } - m_data->pImporter->ReadFile((*it).file,pp); - (*it).scene = m_data->pImporter->GetOrphanedScene(); - (*it).loaded = true; - - ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%"); - } -} diff --git a/thirdparty/assimp/code/Common/BaseProcess.cpp b/thirdparty/assimp/code/Common/BaseProcess.cpp deleted file mode 100644 index e247be418d06..000000000000 --- a/thirdparty/assimp/code/Common/BaseProcess.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of BaseProcess */ - -#include -#include "BaseProcess.h" -#include -#include -#include "Importer.h" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -BaseProcess::BaseProcess() AI_NO_EXCEPT -: shared() -, progress() -{ -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseProcess::~BaseProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -void BaseProcess::ExecuteOnScene( Importer* pImp) -{ - ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); - - progress = pImp->GetProgressHandler(); - ai_assert(progress); - - SetupProperties( pImp ); - - // catch exceptions thrown inside the PostProcess-Step - try - { - Execute(pImp->Pimpl()->mScene); - - } catch( const std::exception& err ) { - - // extract error description - pImp->Pimpl()->mErrorString = err.what(); - ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString); - - // and kill the partially imported data - delete pImp->Pimpl()->mScene; - pImp->Pimpl()->mScene = nullptr; - } -} - -// ------------------------------------------------------------------------------------------------ -void BaseProcess::SetupProperties(const Importer* /*pImp*/) -{ - // the default implementation does nothing -} - -// ------------------------------------------------------------------------------------------------ -bool BaseProcess::RequireVerboseFormat() const -{ - return true; -} - diff --git a/thirdparty/assimp/code/Common/BaseProcess.h b/thirdparty/assimp/code/Common/BaseProcess.h deleted file mode 100644 index 4d5c7a76bec1..000000000000 --- a/thirdparty/assimp/code/Common/BaseProcess.h +++ /dev/null @@ -1,290 +0,0 @@ -/* -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 Base class of all import post processing steps */ -#ifndef INCLUDED_AI_BASEPROCESS_H -#define INCLUDED_AI_BASEPROCESS_H - -#include -#include - -struct aiScene; - -namespace Assimp { - -class Importer; - -// --------------------------------------------------------------------------- -/** Helper class to allow post-processing steps to interact with each other. - * - * The class maintains a simple property list that can be used by pp-steps - * to provide additional information to other steps. This is primarily - * intended for cross-step optimizations. - */ -class SharedPostProcessInfo -{ -public: - - struct Base - { - virtual ~Base() - {} - }; - - //! Represents data that is allocated on the heap, thus needs to be deleted - template - struct THeapData : public Base - { - explicit THeapData(T* in) - : data (in) - {} - - ~THeapData() - { - delete data; - } - T* data; - }; - - //! Represents static, by-value data not allocated on the heap - template - struct TStaticData : public Base - { - explicit TStaticData(T in) - : data (in) - {} - - ~TStaticData() - {} - - T data; - }; - - // some typedefs for cleaner code - typedef unsigned int KeyType; - typedef std::map PropertyMap; - -public: - - //! Destructor - ~SharedPostProcessInfo() - { - Clean(); - } - - //! Remove all stored properties from the table - void Clean() - { - // invoke the virtual destructor for all stored properties - for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); - it != end; ++it) - { - delete (*it).second; - } - pmap.clear(); - } - - //! Add a heap property to the list - template - void AddProperty( const char* name, T* in ){ - AddProperty(name,(Base*)new THeapData(in)); - } - - //! Add a static by-value property to the list - template - void AddProperty( const char* name, T in ){ - AddProperty(name,(Base*)new TStaticData(in)); - } - - - //! Get a heap property - template - bool GetProperty( const char* name, T*& out ) const - { - THeapData* t = (THeapData*)GetPropertyInternal(name); - if(!t) - { - out = NULL; - return false; - } - out = t->data; - return true; - } - - //! Get a static, by-value property - template - bool GetProperty( const char* name, T& out ) const - { - TStaticData* t = (TStaticData*)GetPropertyInternal(name); - if(!t)return false; - out = t->data; - return true; - } - - //! Remove a property of a specific type - void RemoveProperty( const char* name) { - SetGenericPropertyPtr(pmap,name,NULL); - } - -private: - - void AddProperty( const char* name, Base* data) { - SetGenericPropertyPtr(pmap,name,data); - } - - Base* GetPropertyInternal( const char* name) const { - return GetGenericProperty(pmap,name,NULL); - } - -private: - - //! Map of all stored properties - PropertyMap pmap; -}; - -#if 0 - -// --------------------------------------------------------------------------- -/** @brief Represents a dependency table for a postprocessing steps. - * - * For future use. - */ - struct PPDependencyTable - { - unsigned int execute_me_before_these; - unsigned int execute_me_after_these; - unsigned int only_if_these_are_not_specified; - unsigned int mutually_exclusive_with; - }; - -#endif - - -#define AI_SPP_SPATIAL_SORT "$Spat" - -// --------------------------------------------------------------------------- -/** The BaseProcess defines a common interface for all post processing steps. - * A post processing step is run after a successful import if the caller - * specified the corresponding flag when calling ReadFile(). - * Enum #aiPostProcessSteps defines which flags are available. - * After a successful import the Importer iterates over its internal array - * of processes and calls IsActive() on each process to evaluate if the step - * should be executed. If the function returns true, the class' Execute() - * function is called subsequently. - */ -class ASSIMP_API_WINONLY BaseProcess { - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - BaseProcess() AI_NO_EXCEPT; - - /** Destructor, private as well */ - virtual ~BaseProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - virtual bool IsActive( unsigned int pFlags) const = 0; - - // ------------------------------------------------------------------- - /** Check whether this step expects its input vertex data to be - * in verbose format. */ - virtual bool RequireVerboseFormat() const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * The function deletes the scene if the postprocess step fails ( - * the object pointer will be set to NULL). - * @param pImp Importer instance (pImp->mScene must be valid) - */ - void ExecuteOnScene( Importer* pImp); - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * A process should throw an ImportErrorException* if it fails. - * This method must be implemented by deriving classes. - * @param pScene The imported data to work at. - */ - virtual void Execute( aiScene* pScene) = 0; - - - // ------------------------------------------------------------------- - /** Assign a new SharedPostProcessInfo to the step. This object - * allows multiple postprocess steps to share data. - * @param sh May be NULL - */ - inline void SetSharedData(SharedPostProcessInfo* sh) { - shared = sh; - } - - // ------------------------------------------------------------------- - /** Get the shared data that is assigned to the step. - */ - inline SharedPostProcessInfo* GetSharedData() { - return shared; - } - -protected: - - /** See the doc of #SharedPostProcessInfo for more details */ - SharedPostProcessInfo* shared; - - /** Currently active progress handler */ - ProgressHandler* progress; -}; - - -} // end of namespace Assimp - -#endif // AI_BASEPROCESS_H_INC diff --git a/thirdparty/assimp/code/Common/Bitmap.cpp b/thirdparty/assimp/code/Common/Bitmap.cpp deleted file mode 100644 index b22b71ea9e82..000000000000 --- a/thirdparty/assimp/code/Common/Bitmap.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Bitmap.cpp - * @brief Defines bitmap format helper for textures - * - * Used for file formats which embed their textures into the model file. - */ - - -#include -#include -#include -#include - -namespace Assimp { - - void Bitmap::Save(aiTexture* texture, IOStream* file) { - if(file != NULL) { - Header header; - DIB dib; - - dib.size = DIB::dib_size; - dib.width = texture->mWidth; - dib.height = texture->mHeight; - dib.planes = 1; - dib.bits_per_pixel = 8 * mBytesPerPixel; - dib.compression = 0; - dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height; - dib.x_resolution = 0; - dib.y_resolution = 0; - dib.nb_colors = 0; - dib.nb_important_colors = 0; - - header.type = 0x4D42; // 'BM' - header.offset = Header::header_size + DIB::dib_size; - header.size = header.offset + dib.image_size; - header.reserved1 = 0; - header.reserved2 = 0; - - WriteHeader(header, file); - WriteDIB(dib, file); - WriteData(texture, file); - } - } - - template - inline - std::size_t Copy(uint8_t* data, const T &field) { -#ifdef AI_BUILD_BIG_ENDIAN - T field_swapped=AI_BE(field); - std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field); -#else - std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); -#endif - } - - void Bitmap::WriteHeader(Header& header, IOStream* file) { - uint8_t data[Header::header_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], header.type); - offset += Copy(&data[offset], header.size); - offset += Copy(&data[offset], header.reserved1); - offset += Copy(&data[offset], header.reserved2); - Copy(&data[offset], header.offset); - - file->Write(data, Header::header_size, 1); - } - - void Bitmap::WriteDIB(DIB& dib, IOStream* file) { - uint8_t data[DIB::dib_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], dib.size); - offset += Copy(&data[offset], dib.width); - offset += Copy(&data[offset], dib.height); - offset += Copy(&data[offset], dib.planes); - offset += Copy(&data[offset], dib.bits_per_pixel); - offset += Copy(&data[offset], dib.compression); - offset += Copy(&data[offset], dib.image_size); - offset += Copy(&data[offset], dib.x_resolution); - offset += Copy(&data[offset], dib.y_resolution); - offset += Copy(&data[offset], dib.nb_colors); - Copy(&data[offset], dib.nb_important_colors); - - file->Write(data, DIB::dib_size, 1); - } - - void Bitmap::WriteData(aiTexture* texture, IOStream* file) { - static const std::size_t padding_offset = 4; - static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0}; - - unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset; - uint8_t pixel[mBytesPerPixel]; - - for(std::size_t i = 0; i < texture->mHeight; ++i) { - for(std::size_t j = 0; j < texture->mWidth; ++j) { - const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format - - pixel[0] = texel.r; - pixel[1] = texel.g; - pixel[2] = texel.b; - pixel[3] = texel.a; - - file->Write(pixel, mBytesPerPixel, 1); - } - - file->Write(padding_data, padding, 1); - } - } - -} diff --git a/thirdparty/assimp/code/Common/CreateAnimMesh.cpp b/thirdparty/assimp/code/Common/CreateAnimMesh.cpp deleted file mode 100644 index 98b60e531949..000000000000 --- a/thirdparty/assimp/code/Common/CreateAnimMesh.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (C) 2016 The Qt Company Ltd. -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. ---------------------------------------------------------------------------- -*/ - -#include - -namespace Assimp { - -aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh) -{ - aiAnimMesh *animesh = new aiAnimMesh; - animesh->mNumVertices = mesh->mNumVertices; - if (mesh->mVertices) { - animesh->mVertices = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mNormals) { - animesh->mNormals = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mTangents) { - animesh->mTangents = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mBitangents) { - animesh->mBitangents = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D)); - } - - for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { - if (mesh->mColors[i]) { - animesh->mColors[i] = new aiColor4D[animesh->mNumVertices]; - std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D)); - } else { - animesh->mColors[i] = NULL; - } - } - - for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->mTextureCoords[i]) { - animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D)); - } else { - animesh->mTextureCoords[i] = NULL; - } - } - return animesh; -} - -} // end of namespace Assimp diff --git a/thirdparty/assimp/code/Common/DefaultIOStream.cpp b/thirdparty/assimp/code/Common/DefaultIOStream.cpp deleted file mode 100644 index 1c100b618974..000000000000 --- a/thirdparty/assimp/code/Common/DefaultIOStream.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 DefaultIOStream.cpp - * @brief Default File I/O implementation for #Importer - */ - - -#include -#include -#include -#include - -using namespace Assimp; - -// ---------------------------------------------------------------------------------- -DefaultIOStream::~DefaultIOStream() -{ - if (mFile) { - ::fclose(mFile); - mFile = nullptr; - } -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Read(void* pvBuffer, - size_t pSize, - size_t pCount) -{ - ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Write(const void* pvBuffer, - size_t pSize, - size_t pCount) -{ - ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0); -} - -// ---------------------------------------------------------------------------------- -aiReturn DefaultIOStream::Seek(size_t pOffset, - aiOrigin pOrigin) -{ - if (!mFile) { - return AI_FAILURE; - } - - // Just to check whether our enum maps one to one with the CRT constants - static_assert(aiOrigin_CUR == SEEK_CUR && - aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET, "aiOrigin_CUR == SEEK_CUR && \ - aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET"); - - // do the seek - return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Tell() const -{ - if (!mFile) { - return 0; - } - return ::ftell(mFile); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::FileSize() const -{ - if (! mFile || mFilename.empty()) { - return 0; - } - - if (SIZE_MAX == mCachedSize ) { - - // Although fseek/ftell would allow us to reuse the existing file handle here, - // it is generally unsafe because: - // - For binary streams, it is not technically well-defined - // - For text files the results are meaningless - // That's why we use the safer variant fstat here. - // - // See here for details: - // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file -#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) - struct __stat64 fileStat; - //using fileno + fstat avoids having to handle the filename - int err = _fstat64( _fileno(mFile), &fileStat ); - if (0 != err) - return 0; - mCachedSize = (size_t) (fileStat.st_size); -#elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__ - struct stat fileStat; - int err = stat(mFilename.c_str(), &fileStat ); - if (0 != err) - return 0; - const unsigned long long cachedSize = fileStat.st_size; - mCachedSize = static_cast< size_t >( cachedSize ); -#else -# error "Unknown platform" -#endif - } - return mCachedSize; -} - -// ---------------------------------------------------------------------------------- -void DefaultIOStream::Flush() -{ - if (mFile) { - ::fflush(mFile); - } -} - -// ---------------------------------------------------------------------------------- diff --git a/thirdparty/assimp/code/Common/DefaultIOSystem.cpp b/thirdparty/assimp/code/Common/DefaultIOSystem.cpp deleted file mode 100644 index 6fdc24dd8000..000000000000 --- a/thirdparty/assimp/code/Common/DefaultIOSystem.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Default implementation of IOSystem using the standard C file functions */ - -#include - -#include -#include -#include -#include -#include - -#ifdef __unix__ -#include -#include -#endif - -#ifdef _WIN32 -#include -#endif - -using namespace Assimp; - -#ifdef _WIN32 -static std::wstring Utf8ToWide(const char* in) -{ - int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0); - // size includes terminating null; std::wstring adds null automatically - std::wstring out(static_cast(size) - 1, L'\0'); - MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size); - return out; -} - -static std::string WideToUtf8(const wchar_t* in) -{ - int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr); - // size includes terminating null; std::string adds null automatically - std::string out(static_cast(size) - 1, '\0'); - WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr); - return out; -} -#endif - -// ------------------------------------------------------------------------------------------------ -// Tests for the existence of a file at the given path. -bool DefaultIOSystem::Exists(const char* pFile) const -{ -#ifdef _WIN32 - struct __stat64 filestat; - if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { - return false; - } -#else - FILE* file = ::fopen(pFile, "rb"); - if (!file) - return false; - - ::fclose(file); -#endif - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Open a new file with a given path. -IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode) -{ - ai_assert(strFile != nullptr); - ai_assert(strMode != nullptr); - FILE* file; -#ifdef _WIN32 - file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str()); -#else - file = ::fopen(strFile, strMode); -#endif - if (!file) - return nullptr; - - return new DefaultIOStream(file, strFile); -} - -// ------------------------------------------------------------------------------------------------ -// Closes the given file and releases all resources associated with it. -void DefaultIOSystem::Close(IOStream* pFile) -{ - delete pFile; -} - -// ------------------------------------------------------------------------------------------------ -// Returns the operation specific directory separator -char DefaultIOSystem::getOsSeparator() const -{ -#ifndef _WIN32 - return '/'; -#else - return '\\'; -#endif -} - -// ------------------------------------------------------------------------------------------------ -// IOSystem default implementation (ComparePaths isn't a pure virtual function) -bool IOSystem::ComparePaths(const char* one, const char* second) const -{ - return !ASSIMP_stricmp(one, second); -} - -// ------------------------------------------------------------------------------------------------ -// Convert a relative path into an absolute path -inline static std::string MakeAbsolutePath(const char* in) -{ - ai_assert(in); - std::string out; -#ifdef _WIN32 - wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); - if (ret) { - out = WideToUtf8(ret); - free(ret); - } -#else - char* ret = realpath(in, nullptr); - if (ret) { - out = ret; - free(ret); - } -#endif - if (!ret) { - // preserve the input path, maybe someone else is able to fix - // the path before it is accessed (e.g. our file system filter) - ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); - out = in; - } - return out; -} - -// ------------------------------------------------------------------------------------------------ -// DefaultIOSystem's more specialized implementation -bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const -{ - // chances are quite good both paths are formatted identically, - // so we can hopefully return here already - if (!ASSIMP_stricmp(one, second)) - return true; - - std::string temp1 = MakeAbsolutePath(one); - std::string temp2 = MakeAbsolutePath(second); - - return !ASSIMP_stricmp(temp1, temp2); -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::fileName(const std::string& path) -{ - std::string ret = path; - std::size_t last = ret.find_last_of("\\/"); - if (last != std::string::npos) ret = ret.substr(last + 1); - return ret; -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::completeBaseName(const std::string& path) -{ - std::string ret = fileName(path); - std::size_t pos = ret.find_last_of('.'); - if (pos != std::string::npos) ret = ret.substr(0, pos); - return ret; -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::absolutePath(const std::string& path) -{ - std::string ret = path; - std::size_t last = ret.find_last_of("\\/"); - if (last != std::string::npos) ret = ret.substr(0, last); - return ret; -} - -// ------------------------------------------------------------------------------------------------ diff --git a/thirdparty/assimp/code/Common/DefaultLogger.cpp b/thirdparty/assimp/code/Common/DefaultLogger.cpp deleted file mode 100644 index de3528d2b42d..000000000000 --- a/thirdparty/assimp/code/Common/DefaultLogger.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 DefaultLogger.cpp - * @brief Implementation of DefaultLogger (and Logger) - */ - -// Default log streams -#include "Win32DebugLogStream.h" -#include "StdOStreamLogStream.h" -#include "FileLogStream.h" -#include - -#include -#include -#include -#include -#include -#include - -#ifndef ASSIMP_BUILD_SINGLETHREADED -# include -# include - std::mutex loggerMutex; -#endif - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -NullLogger DefaultLogger::s_pNullLogger; -Logger *DefaultLogger::m_pLogger = &DefaultLogger::s_pNullLogger; - -static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; - -// ---------------------------------------------------------------------------------- -// Represents a log-stream + its error severity -struct LogStreamInfo { - unsigned int m_uiErrorSeverity; - LogStream *m_pStream; - - // Constructor - LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) : - m_uiErrorSeverity( uiErrorSev ), - m_pStream( pStream ) { - // empty - } - - // Destructor - ~LogStreamInfo() { - delete m_pStream; - } -}; - -// ---------------------------------------------------------------------------------- -// Construct a default log stream -LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, - const char* name /*= "AssimpLog.txt"*/, - IOSystem* io /*= NULL*/) -{ - switch (streams) - { - // This is a platform-specific feature - case aiDefaultLogStream_DEBUGGER: -#ifdef WIN32 - return new Win32DebugLogStream(); -#else - return nullptr; -#endif - - // Platform-independent default streams - case aiDefaultLogStream_STDERR: - return new StdOStreamLogStream(std::cerr); - case aiDefaultLogStream_STDOUT: - return new StdOStreamLogStream(std::cout); - case aiDefaultLogStream_FILE: - return (name && *name ? new FileLogStream(name,io) : nullptr ); - default: - // We don't know this default log stream, so raise an assertion - ai_assert(false); - - }; - - // For compilers without dead code path detection - return NULL; -} - -// ---------------------------------------------------------------------------------- -// Creates the only singleton instance -Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/, - LogSeverity severity /*= NORMAL*/, - unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/, - IOSystem* io /*= NULL*/) { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(loggerMutex); -#endif - - if ( m_pLogger && !isNullLogger() ) { - delete m_pLogger; - } - - m_pLogger = new DefaultLogger( severity ); - - // Attach default log streams - // Stream the log to the MSVC debugger? - if ( defStreams & aiDefaultLogStream_DEBUGGER ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) ); - } - - // Stream the log to COUT? - if ( defStreams & aiDefaultLogStream_STDOUT ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) ); - } - - // Stream the log to CERR? - if ( defStreams & aiDefaultLogStream_STDERR ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) ); - } - - // Stream the log to a file - if ( defStreams & aiDefaultLogStream_FILE && name && *name ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) ); - } - - return m_pLogger; -} - -// ---------------------------------------------------------------------------------- -void Logger::debug(const char* message) { - - // SECURITY FIX: otherwise it's easy to produce overruns since - // sometimes importers will include data from the input file - // (i.e. node names) in their messages. - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnDebug(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::info(const char* message) { - - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnInfo(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::warn(const char* message) { - - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnWarn(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::error(const char* message) { - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnError(message); -} - -// ---------------------------------------------------------------------------------- -void DefaultLogger::set( Logger *logger ) { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(loggerMutex); -#endif - - if ( nullptr == logger ) { - logger = &s_pNullLogger; - } - if ( nullptr != m_pLogger && !isNullLogger() ) { - delete m_pLogger; - } - - DefaultLogger::m_pLogger = logger; -} - -// ---------------------------------------------------------------------------------- -bool DefaultLogger::isNullLogger() { - return m_pLogger == &s_pNullLogger; -} - -// ---------------------------------------------------------------------------------- -Logger *DefaultLogger::get() { - return m_pLogger; -} - -// ---------------------------------------------------------------------------------- -// Kills the only instance -void DefaultLogger::kill() { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard lock(loggerMutex); -#endif - - if ( m_pLogger == &s_pNullLogger ) { - return; - } - delete m_pLogger; - m_pLogger = &s_pNullLogger; -} - -// ---------------------------------------------------------------------------------- -// Debug message -void DefaultLogger::OnDebug( const char* message ) { - if ( m_Severity == Logger::NORMAL ) { - return; - } - - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Debug, T%u: %s", GetThreadID(), message); - - WriteToStreams( msg, Logger::Debugging ); -} - -// ---------------------------------------------------------------------------------- -// Logs an info -void DefaultLogger::OnInfo( const char* message ){ - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg , Logger::Info ); -} - -// ---------------------------------------------------------------------------------- -// Logs a warning -void DefaultLogger::OnWarn( const char* message ) { - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg, Logger::Warn ); -} - -// ---------------------------------------------------------------------------------- -// Logs an error -void DefaultLogger::OnError( const char* message ) { - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[ Size ]; - ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg, Logger::Err ); -} - -// ---------------------------------------------------------------------------------- -// Will attach a new stream -bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) { - if ( nullptr == pStream ) { - return false; - } - - if (0 == severity) { - severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; - } - - for ( StreamIt it = m_StreamArray.begin(); - it != m_StreamArray.end(); - ++it ) - { - if ( (*it)->m_pStream == pStream ) { - (*it)->m_uiErrorSeverity |= severity; - return true; - } - } - - LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream ); - m_StreamArray.push_back( pInfo ); - return true; -} - -// ---------------------------------------------------------------------------------- -// Detach a stream -bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) { - if ( nullptr == pStream ) { - return false; - } - - if (0 == severity) { - severity = SeverityAll; - } - - bool res( false ); - for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) { - if ( (*it)->m_pStream == pStream ) { - (*it)->m_uiErrorSeverity &= ~severity; - if ( (*it)->m_uiErrorSeverity == 0 ) { - // don't delete the underlying stream 'cause the caller gains ownership again - (**it).m_pStream = nullptr; - delete *it; - m_StreamArray.erase( it ); - res = true; - break; - } - return true; - } - } - return res; -} - -// ---------------------------------------------------------------------------------- -// Constructor -DefaultLogger::DefaultLogger(LogSeverity severity) - : Logger ( severity ) - , noRepeatMsg (false) - , lastLen( 0 ) { - lastMsg[0] = '\0'; -} - -// ---------------------------------------------------------------------------------- -// Destructor -DefaultLogger::~DefaultLogger() { - for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) { - // also frees the underlying stream, we are its owner. - delete *it; - } -} - -// ---------------------------------------------------------------------------------- -// Writes message to stream -void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) { - ai_assert(nullptr != message); - - // Check whether this is a repeated message - if (! ::strncmp( message,lastMsg, lastLen-1)) - { - if (!noRepeatMsg) - { - noRepeatMsg = true; - message = "Skipping one or more lines with the same contents\n"; - } - else return; - } - else - { - // append a new-line character to the message to be printed - lastLen = ::strlen(message); - ::memcpy(lastMsg,message,lastLen+1); - ::strcat(lastMsg+lastLen,"\n"); - - message = lastMsg; - noRepeatMsg = false; - ++lastLen; - } - for ( ConstStreamIt it = m_StreamArray.begin(); - it != m_StreamArray.end(); - ++it) - { - if ( ErrorSev & (*it)->m_uiErrorSeverity ) - (*it)->m_pStream->write( message); - } -} - -// ---------------------------------------------------------------------------------- -// Returns thread id, if not supported only a zero will be returned. -unsigned int DefaultLogger::GetThreadID() -{ - // fixme: we can get this value via std::threads - // std::this_thread::get_id().hash() returns a (big) size_t, not sure if this is useful in this case. -#ifdef WIN32 - return (unsigned int)::GetCurrentThreadId(); -#else - return 0; // not supported -#endif -} - -// ---------------------------------------------------------------------------------- - -} // !namespace Assimp diff --git a/thirdparty/assimp/code/Common/DefaultProgressHandler.h b/thirdparty/assimp/code/Common/DefaultProgressHandler.h deleted file mode 100644 index bd2cce00be73..000000000000 --- a/thirdparty/assimp/code/Common/DefaultProgressHandler.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -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 ProgressHandler.hpp - * @brief Abstract base class 'ProgressHandler'. - */ -#ifndef INCLUDED_AI_DEFAULTPROGRESSHANDLER_H -#define INCLUDED_AI_DEFAULTPROGRESSHANDLER_H - -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------------ -/** @brief Internal default implementation of the #ProgressHandler interface. */ -class DefaultProgressHandler : public ProgressHandler { - - virtual bool Update(float /*percentage*/) { - return false; - } - - -}; // !class DefaultProgressHandler -} // Namespace Assimp - -#endif diff --git a/thirdparty/assimp/code/Common/Exporter.cpp b/thirdparty/assimp/code/Common/Exporter.cpp deleted file mode 100644 index 4ce1a2bd801b..000000000000 --- a/thirdparty/assimp/code/Common/Exporter.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Exporter.cpp - -Assimp export interface. While it's public interface bears many similarities -to the import interface (in fact, it is largely symmetric), the internal -implementations differs a lot. Exporters are considered stateless and are -simple callbacks which we maintain in a global list along with their -description strings. - -Here we implement only the C++ interface (Assimp::Exporter). -*/ - -#ifndef ASSIMP_BUILD_NO_EXPORT - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Common/DefaultProgressHandler.h" -#include "Common/BaseProcess.h" -#include "Common/ScenePrivate.h" -#include "PostProcessing/CalcTangentsProcess.h" -#include "PostProcessing/MakeVerboseFormat.h" -#include "PostProcessing/JoinVerticesProcess.h" -#include "PostProcessing/ConvertToLHProcess.h" -#include "PostProcessing/PretransformVertices.h" - -#include - -namespace Assimp { - -// PostStepRegistry.cpp -void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); - -// ------------------------------------------------------------------------------------------------ -// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype -// do not use const, because some exporter need to convert the scene temporary -void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); -void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); - -// ------------------------------------------------------------------------------------------------ -// global array of all export formats which Assimp supports in its current build -Exporter::ExportFormatEntry gExporters[] = -{ -#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER - Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ), -#endif - -#ifndef ASSIMP_BUILD_NO_X_EXPORTER - Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile, - aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ), -#endif - -#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER - Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER - Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), - Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), -#endif - -#ifndef ASSIMP_BUILD_NO_STL_EXPORTER - Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), -#endif - -#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER - Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, - aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary, - aiProcess_PreTransformVertices - ), -#endif - -#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER - Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS, - aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ), -#endif - -#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER - Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER - Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER - Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER - Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), - Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER - Exporter::ExportFormatEntry( "m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0 ), - Exporter::ExportFormatEntry( "a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER - Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER - Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0) -#endif -}; - -#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) - - -class ExporterPimpl { -public: - ExporterPimpl() - : blob() - , mIOSystem(new Assimp::DefaultIOSystem()) - , mIsDefaultIOHandler(true) - , mProgressHandler( nullptr ) - , mIsDefaultProgressHandler( true ) - , mPostProcessingSteps() - , mError() - , mExporters() { - GetPostProcessingStepInstanceList(mPostProcessingSteps); - - // grab all built-in exporters - if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) { - mExporters.resize( ASSIMP_NUM_EXPORTERS ); - std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() ); - } - } - - ~ExporterPimpl() { - delete blob; - - // Delete all post-processing plug-ins - for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) { - delete mPostProcessingSteps[a]; - } - delete mProgressHandler; - } - -public: - aiExportDataBlob* blob; - std::shared_ptr< Assimp::IOSystem > mIOSystem; - bool mIsDefaultIOHandler; - - /** The progress handler */ - ProgressHandler *mProgressHandler; - bool mIsDefaultProgressHandler; - - /** Post processing steps we can apply at the imported data. */ - std::vector< BaseProcess* > mPostProcessingSteps; - - /** Last fatal export error */ - std::string mError; - - /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */ - std::vector mExporters; -}; - -} // end of namespace Assimp - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -Exporter :: Exporter() -: pimpl(new ExporterPimpl()) { - pimpl->mProgressHandler = new DefaultProgressHandler(); -} - -// ------------------------------------------------------------------------------------------------ -Exporter::~Exporter() { - FreeBlob(); - delete pimpl; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::SetIOHandler( IOSystem* pIOHandler) { - pimpl->mIsDefaultIOHandler = !pIOHandler; - pimpl->mIOSystem.reset(pIOHandler); -} - -// ------------------------------------------------------------------------------------------------ -IOSystem* Exporter::GetIOHandler() const { - return pimpl->mIOSystem.get(); -} - -// ------------------------------------------------------------------------------------------------ -bool Exporter::IsDefaultIOHandler() const { - return pimpl->mIsDefaultIOHandler; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::SetProgressHandler(ProgressHandler* pHandler) { - ai_assert(nullptr != pimpl); - - if ( nullptr == pHandler) { - // Release pointer in the possession of the caller - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - return; - } - - if (pimpl->mProgressHandler == pHandler) { - return; - } - - delete pimpl->mProgressHandler; - pimpl->mProgressHandler = pHandler; - pimpl->mIsDefaultProgressHandler = false; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId, - unsigned int pPreprocessing, const ExportProperties* pProperties) { - if (pimpl->blob) { - delete pimpl->blob; - pimpl->blob = nullptr; - } - - std::shared_ptr old = pimpl->mIOSystem; - BlobIOSystem* blobio = new BlobIOSystem(); - pimpl->mIOSystem = std::shared_ptr( blobio ); - - if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) { - pimpl->mIOSystem = old; - return nullptr; - } - - pimpl->blob = blobio->GetBlobChain(); - pimpl->mIOSystem = old; - - return pimpl->blob; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, - unsigned int pPreprocessing, const ExportProperties* pProperties) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // when they create scenes from scratch, users will likely create them not in verbose - // format. They will likely not be aware that there is a flag in the scene to indicate - // this, however. To avoid surprises and bug reports, we check for duplicates in - // meshes upfront. - const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene); - - pimpl->mProgressHandler->UpdateFileWrite(0, 4); - - pimpl->mError = ""; - for (size_t i = 0; i < pimpl->mExporters.size(); ++i) { - const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i]; - if (!strcmp(exp.mDescription.id,pFormatId)) { - try { - // Always create a full copy of the scene. We might optimize this one day, - // but for now it is the most pragmatic way. - aiScene* scenecopy_tmp = nullptr; - SceneCombiner::CopyScene(&scenecopy_tmp,pScene); - - pimpl->mProgressHandler->UpdateFileWrite(1, 4); - - std::unique_ptr scenecopy(scenecopy_tmp); - const ScenePrivateData* const priv = ScenePriv(pScene); - - // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the - // original state before the step was applied first. When checking which steps we don't need - // to run, those are excluded. - const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded; - - // Erase all pp steps that were already applied to this scene - const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy - ? (priv->mPPStepsApplied & ~nonIdempotentSteps) - : 0u); - - // If no extra post-processing was specified, and we obtained this scene from an - // Assimp importer, apply the reverse steps automatically. - // TODO: either drop this, or document it. Otherwise it is just a bad surprise. - //if (!pPreprocessing && priv) { - // pp |= (nonIdempotentSteps & priv->mPPStepsApplied); - //} - - // If the input scene is not in verbose format, but there is at least post-processing step that relies on it, - // we need to run the MakeVerboseFormat step first. - bool must_join_again = false; - if (!is_verbose_format) { - bool verbosify = false; - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* const p = pimpl->mPostProcessingSteps[a]; - - if (p->IsActive(pp) && p->RequireVerboseFormat()) { - verbosify = true; - break; - } - } - - if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { - ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); - - MakeVerboseFormatProcess proc; - proc.Execute(scenecopy.get()); - - if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { - must_join_again = true; - } - } - } - - pimpl->mProgressHandler->UpdateFileWrite(2, 4); - - if (pp) { - // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout - { - FlipWindingOrderProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - { - FlipUVsProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - { - MakeLeftHandedProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - bool exportPointCloud(false); - if (nullptr != pProperties) { - exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); - } - - // dispatch other processes - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* const p = pimpl->mPostProcessingSteps[a]; - - if (p->IsActive(pp) - && !dynamic_cast(p) - && !dynamic_cast(p) - && !dynamic_cast(p)) { - if (dynamic_cast(p) && exportPointCloud) { - continue; - } - p->Execute(scenecopy.get()); - } - } - ScenePrivateData* const privOut = ScenePriv(scenecopy.get()); - ai_assert(nullptr != privOut); - - privOut->mPPStepsApplied |= pp; - } - - pimpl->mProgressHandler->UpdateFileWrite(3, 4); - - if(must_join_again) { - JoinVerticesProcess proc; - proc.Execute(scenecopy.get()); - } - - ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. - ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; - pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); - - pimpl->mProgressHandler->UpdateFileWrite(4, 4); - } catch (DeadlyExportError& err) { - pimpl->mError = err.what(); - return AI_FAILURE; - } - return AI_SUCCESS; - } - } - - pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId; - ASSIMP_END_EXCEPTION_REGION(aiReturn); - - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -const char* Exporter::GetErrorString() const { - return pimpl->mError.c_str(); -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::FreeBlob() { - delete pimpl->blob; - pimpl->blob = nullptr; - - pimpl->mError = ""; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::GetBlob() const { - return pimpl->blob; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::GetOrphanedBlob() const { - const aiExportDataBlob* tmp = pimpl->blob; - pimpl->blob = nullptr; - return tmp; -} - -// ------------------------------------------------------------------------------------------------ -size_t Exporter::GetExportFormatCount() const { - return pimpl->mExporters.size(); -} - -// ------------------------------------------------------------------------------------------------ -const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const { - if (index >= GetExportFormatCount()) { - return nullptr; - } - - // Return from static storage if the requested index is built-in. - if (index < sizeof(gExporters) / sizeof(gExporters[0])) { - return &gExporters[index].mDescription; - } - - return &pimpl->mExporters[index].mDescription; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { - for(const ExportFormatEntry& e : pimpl->mExporters) { - if (!strcmp(e.mDescription.id,desc.mDescription.id)) { - return aiReturn_FAILURE; - } - } - - pimpl->mExporters.push_back(desc); - return aiReturn_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::UnregisterExporter(const char* id) { - for(std::vector::iterator it = pimpl->mExporters.begin(); - it != pimpl->mExporters.end(); ++it) { - if (!strcmp((*it).mDescription.id,id)) { - pimpl->mExporters.erase(it); - break; - } - } -} - -// ------------------------------------------------------------------------------------------------ -ExportProperties::ExportProperties() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -ExportProperties::ExportProperties(const ExportProperties &other) -: mIntProperties(other.mIntProperties) -, mFloatProperties(other.mFloatProperties) -, mStringProperties(other.mStringProperties) -, mMatrixProperties(other.mMatrixProperties) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) { - return SetGenericProperty(mIntProperties, szName,iValue); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) { - return SetGenericProperty(mFloatProperties, szName,iValue); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) { - return SetGenericProperty(mStringProperties, szName,value); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) { - return SetGenericProperty(mMatrixProperties, szName,value); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const { - return GetGenericProperty(mIntProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const { - return GetGenericProperty(mFloatProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const std::string ExportProperties::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const { - return GetGenericProperty(mStringProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const { - return GetGenericProperty(mMatrixProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyInteger(const char* szName) const { - return HasGenericProperty(mIntProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyBool(const char* szName) const { - return HasGenericProperty(mIntProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyFloat(const char* szName) const { - return HasGenericProperty(mFloatProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyString(const char* szName) const { - return HasGenericProperty(mStringProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyMatrix(const char* szName) const { - return HasGenericProperty(mMatrixProperties, szName); -} - - -#endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/Common/FileLogStream.h b/thirdparty/assimp/code/Common/FileLogStream.h deleted file mode 100644 index 740c503192e1..000000000000 --- a/thirdparty/assimp/code/Common/FileLogStream.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -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 FileLofStream.h -*/ -#ifndef ASSIMP_FILELOGSTREAM_H_INC -#define ASSIMP_FILELOGSTREAM_H_INC - -#include -#include -#include - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** @class FileLogStream - * @brief Logstream to write into a file. - */ -class FileLogStream : - public LogStream -{ -public: - FileLogStream( const char* file, IOSystem* io = NULL ); - ~FileLogStream(); - void write( const char* message ); - -private: - IOStream *m_pStream; -}; - -// ---------------------------------------------------------------------------------- -// Constructor -inline FileLogStream::FileLogStream( const char* file, IOSystem* io ) : - m_pStream(NULL) -{ - if ( !file || 0 == *file ) - return; - - // If no IOSystem is specified: take a default one - if (!io) - { - DefaultIOSystem FileSystem; - m_pStream = FileSystem.Open( file, "wt"); - } - else m_pStream = io->Open( file, "wt" ); -} - -// ---------------------------------------------------------------------------------- -// Destructor -inline FileLogStream::~FileLogStream() -{ - // The virtual d'tor should destroy the underlying file - delete m_pStream; -} - -// ---------------------------------------------------------------------------------- -// Write method -inline void FileLogStream::write( const char* message ) -{ - if (m_pStream != NULL) - { - m_pStream->Write(message, sizeof(char), ::strlen(message)); - m_pStream->Flush(); - } -} - -// ---------------------------------------------------------------------------------- -} // !Namespace Assimp - -#endif // !! ASSIMP_FILELOGSTREAM_H_INC diff --git a/thirdparty/assimp/code/Common/FileSystemFilter.h b/thirdparty/assimp/code/Common/FileSystemFilter.h deleted file mode 100644 index 9923cdbdd35d..000000000000 --- a/thirdparty/assimp/code/Common/FileSystemFilter.h +++ /dev/null @@ -1,345 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2008, 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 FileSystemFilter.h - * Implements a filter system to filter calls to Exists() and Open() - * in order to improve the success rate of file opening ... - */ -#pragma once -#ifndef AI_FILESYSTEMFILTER_H_INC -#define AI_FILESYSTEMFILTER_H_INC - -#include -#include -#include -#include - -namespace Assimp { - -inline bool IsHex(char s) { - return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F'); -} - -// --------------------------------------------------------------------------- -/** File system filter - */ -class FileSystemFilter : public IOSystem -{ -public: - /** Constructor. */ - FileSystemFilter(const std::string& file, IOSystem* old) - : mWrapped (old) - , mSrc_file(file) - , mSep(mWrapped->getOsSeparator()) { - ai_assert(nullptr != mWrapped); - - // Determine base directory - mBase = mSrc_file; - std::string::size_type ss2; - if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) { - mBase.erase(ss2,mBase.length()-ss2); - } else { - mBase = ""; - } - - // make sure the directory is terminated properly - char s; - - if ( mBase.empty() ) { - mBase = "."; - mBase += getOsSeparator(); - } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') { - mBase += getOsSeparator(); - } - - DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'"); - } - - /** Destructor. */ - ~FileSystemFilter() { - // empty - } - - // ------------------------------------------------------------------- - /** Tests for the existence of a file at the given path. */ - bool Exists( const char* pFile) const { - ai_assert( nullptr != mWrapped ); - - std::string tmp = pFile; - - // Currently this IOSystem is also used to open THE ONE FILE. - if (tmp != mSrc_file) { - BuildPath(tmp); - Cleanup(tmp); - } - - return mWrapped->Exists(tmp); - } - - // ------------------------------------------------------------------- - /** Returns the directory separator. */ - char getOsSeparator() const { - return mSep; - } - - // ------------------------------------------------------------------- - /** Open a new file with a given path. */ - IOStream* Open( const char* pFile, const char* pMode = "rb") { - ai_assert( nullptr != mWrapped ); - if ( nullptr == pFile || nullptr == pMode ) { - return nullptr; - } - - ai_assert( nullptr != pFile ); - ai_assert( nullptr != pMode ); - - // First try the unchanged path - IOStream* s = mWrapped->Open(pFile,pMode); - - if (nullptr == s) { - std::string tmp = pFile; - - // Try to convert between absolute and relative paths - BuildPath(tmp); - s = mWrapped->Open(tmp,pMode); - - if (nullptr == s) { - // Finally, look for typical issues with paths - // and try to correct them. This is our last - // resort. - tmp = pFile; - Cleanup(tmp); - BuildPath(tmp); - s = mWrapped->Open(tmp,pMode); - } - } - - return s; - } - - // ------------------------------------------------------------------- - /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* pFile) { - ai_assert( nullptr != mWrapped ); - return mWrapped->Close(pFile); - } - - // ------------------------------------------------------------------- - /** Compare two paths */ - bool ComparePaths (const char* one, const char* second) const { - ai_assert( nullptr != mWrapped ); - return mWrapped->ComparePaths (one,second); - } - - // ------------------------------------------------------------------- - /** Pushes a new directory onto the directory stack. */ - bool PushDirectory(const std::string &path ) { - ai_assert( nullptr != mWrapped ); - return mWrapped->PushDirectory(path); - } - - // ------------------------------------------------------------------- - /** Returns the top directory from the stack. */ - const std::string &CurrentDirectory() const { - ai_assert( nullptr != mWrapped ); - return mWrapped->CurrentDirectory(); - } - - // ------------------------------------------------------------------- - /** Returns the number of directories stored on the stack. */ - size_t StackSize() const { - ai_assert( nullptr != mWrapped ); - return mWrapped->StackSize(); - } - - // ------------------------------------------------------------------- - /** Pops the top directory from the stack. */ - bool PopDirectory() { - ai_assert( nullptr != mWrapped ); - return mWrapped->PopDirectory(); - } - - // ------------------------------------------------------------------- - /** Creates an new directory at the given path. */ - bool CreateDirectory(const std::string &path) { - ai_assert( nullptr != mWrapped ); - return mWrapped->CreateDirectory(path); - } - - // ------------------------------------------------------------------- - /** Will change the current directory to the given path. */ - bool ChangeDirectory(const std::string &path) { - ai_assert( nullptr != mWrapped ); - return mWrapped->ChangeDirectory(path); - } - - // ------------------------------------------------------------------- - /** Delete file. */ - bool DeleteFile(const std::string &file) { - ai_assert( nullptr != mWrapped ); - return mWrapped->DeleteFile(file); - } - -private: - // ------------------------------------------------------------------- - /** Build a valid path from a given relative or absolute path. - */ - void BuildPath (std::string& in) const { - ai_assert( nullptr != mWrapped ); - // if we can already access the file, great. - if (in.length() < 3 || mWrapped->Exists(in)) { - return; - } - - // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows). - if (in[1] != ':') { - - // append base path and try - const std::string tmp = mBase + in; - if (mWrapped->Exists(tmp)) { - in = tmp; - return; - } - } - - // Chop of the file name and look in the model directory, if - // this fails try all sub paths of the given path, i.e. - // if the given path is foo/bar/something.lwo, try - // /something.lwo - // /bar/something.lwo - // /foo/bar/something.lwo - std::string::size_type pos = in.rfind('/'); - if (std::string::npos == pos) { - pos = in.rfind('\\'); - } - - if (std::string::npos != pos) { - std::string tmp; - std::string::size_type last_dirsep = std::string::npos; - - while(true) { - tmp = mBase; - tmp += mSep; - - std::string::size_type dirsep = in.rfind('/', last_dirsep); - if (std::string::npos == dirsep) { - dirsep = in.rfind('\\', last_dirsep); - } - - if (std::string::npos == dirsep || dirsep == 0) { - // we did try this already. - break; - } - - last_dirsep = dirsep-1; - - tmp += in.substr(dirsep+1, in.length()-pos); - if (mWrapped->Exists(tmp)) { - in = tmp; - return; - } - } - } - - // hopefully the underlying file system has another few tricks to access this file ... - } - - // ------------------------------------------------------------------- - /** Cleanup the given path - */ - void Cleanup (std::string& in) const { - if(in.empty()) { - return; - } - - // Remove a very common issue when we're parsing file names: spaces at the - // beginning of the path. - char last = 0; - std::string::iterator it = in.begin(); - while (IsSpaceOrNewLine( *it ))++it; - if (it != in.begin()) { - in.erase(in.begin(),it+1); - } - - const char separator = getOsSeparator(); - for (it = in.begin(); it != in.end(); ++it) { - // Exclude :// and \\, which remain untouched. - // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632 - if ( !strncmp(&*it, "://", 3 )) { - it += 3; - continue; - } - if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) { - it += 2; - continue; - } - - // Cleanup path delimiters - if (*it == '/' || (*it) == '\\') { - *it = separator; - - // And we're removing double delimiters, frequent issue with - // incorrectly composited paths ... - if (last == *it) { - it = in.erase(it); - --it; - } - } else if (*it == '%' && in.end() - it > 2) { - // Hex sequence in URIs - if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) { - *it = HexOctetToDecimal(&*it); - it = in.erase(it+1,it+2); - --it; - } - } - - last = *it; - } - } - -private: - IOSystem *mWrapped; - std::string mSrc_file, mBase; - char mSep; -}; - -} //!ns Assimp - -#endif //AI_DEFAULTIOSYSTEM_H_INC diff --git a/thirdparty/assimp/code/Common/IFF.h b/thirdparty/assimp/code/Common/IFF.h deleted file mode 100644 index 91d7d4828951..000000000000 --- a/thirdparty/assimp/code/Common/IFF.h +++ /dev/null @@ -1,102 +0,0 @@ -// Definitions for the Interchange File Format (IFF) -// Alexander Gessler, 2006 -// Adapted to Assimp August 2008 - -#ifndef AI_IFF_H_INCLUDED -#define AI_IFF_H_INCLUDED - -#include - -namespace Assimp { -namespace IFF { - -///////////////////////////////////////////////////////////////////////////////// -//! Describes an IFF chunk header -///////////////////////////////////////////////////////////////////////////////// -struct ChunkHeader -{ - //! Type of the chunk header - FourCC - uint32_t type; - - //! Length of the chunk data, in bytes - uint32_t length; -}; - - -///////////////////////////////////////////////////////////////////////////////// -//! Describes an IFF sub chunk header -///////////////////////////////////////////////////////////////////////////////// -struct SubChunkHeader -{ - //! Type of the chunk header - FourCC - uint32_t type; - - //! Length of the chunk data, in bytes - uint16_t length; -}; - - -#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \ - ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d))) - - -#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M') - - -///////////////////////////////////////////////////////////////////////////////// -//! Load a chunk header -//! @param outFile Pointer to the file data - points to the chunk data afterwards -//! @return Copy of the chunk header -///////////////////////////////////////////////////////////////////////////////// -inline ChunkHeader LoadChunk(uint8_t*& outFile) -{ - ChunkHeader head; - ::memcpy(&head.type, outFile, 4); - outFile += 4; - ::memcpy(&head.length, outFile, 4); - outFile += 4; - AI_LSWAP4(head.length); - AI_LSWAP4(head.type); - return head; -} - -///////////////////////////////////////////////////////////////////////////////// -//! Load a sub chunk header -//! @param outFile Pointer to the file data - points to the chunk data afterwards -//! @return Copy of the sub chunk header -///////////////////////////////////////////////////////////////////////////////// -inline SubChunkHeader LoadSubChunk(uint8_t*& outFile) -{ - SubChunkHeader head; - ::memcpy(&head.type, outFile, 4); - outFile += 4; - ::memcpy(&head.length, outFile, 2); - outFile += 2; - AI_LSWAP2(head.length); - AI_LSWAP4(head.type); - return head; -} - -///////////////////////////////////////////////////////////////////////////////// -//! Read the file header and return the type of the file and its size -//! @param outFile Pointer to the file data. The buffer must at -//! least be 12 bytes large. -//! @param fileType Receives the type of the file -//! @return 0 if everything was OK, otherwise an error message -///////////////////////////////////////////////////////////////////////////////// -inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType) -{ - ChunkHeader head = LoadChunk(outFile); - if(AI_IFF_FOURCC_FORM != head.type) - { - return "The file is not an IFF file: FORM chunk is missing"; - } - ::memcpy(&fileType, outFile, 4); - AI_LSWAP4(fileType); - return 0; -} - - -}} - -#endif // !! AI_IFF_H_INCLUDED diff --git a/thirdparty/assimp/code/Common/Importer.cpp b/thirdparty/assimp/code/Common/Importer.cpp deleted file mode 100644 index 91b50859a09b..000000000000 --- a/thirdparty/assimp/code/Common/Importer.cpp +++ /dev/null @@ -1,1174 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Importer.cpp - * @brief Implementation of the CPP-API class #Importer - */ - -#include -#include -#include - -// ------------------------------------------------------------------------------------------------ -/* Uncomment this line to prevent Assimp from catching unknown exceptions. - * - * Note that any Exception except DeadlyImportError may lead to - * undefined behaviour -> loaders could remain in an unusable state and - * further imports with the same Importer instance could fail/crash/burn ... - */ -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_DEBUG -# define ASSIMP_CATCH_GLOBAL_EXCEPTIONS -#endif - -// ------------------------------------------------------------------------------------------------ -// Internal headers -// ------------------------------------------------------------------------------------------------ -#include "Common/Importer.h" -#include "Common/BaseProcess.h" -#include "Common/DefaultProgressHandler.h" -#include "PostProcessing/ProcessHelper.h" -#include "Common/ScenePreprocessor.h" -#include "Common/ScenePrivate.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS -# include "PostProcessing/ValidateDataStructure.h" -#endif - -using namespace Assimp::Profiling; -using namespace Assimp::Formatter; - -namespace Assimp { - // ImporterRegistry.cpp - void GetImporterInstanceList(std::vector< BaseImporter* >& out); - void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); - - // PostStepRegistry.cpp - void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); -} - -using namespace Assimp; -using namespace Assimp::Intern; - -// ------------------------------------------------------------------------------------------------ -// Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides -// new and delete (and their array counterparts) of public API classes (e.g. Logger) to -// utilize our DLL heap. -// See http://www.gotw.ca/publications/mill15.htm -// ------------------------------------------------------------------------------------------------ -void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) { - return ::operator new(num_bytes); -} - -void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() { - try { - return AllocateFromAssimpHeap::operator new( num_bytes ); - } - catch( ... ) { - return NULL; - } -} - -void AllocateFromAssimpHeap::operator delete ( void* data) { - return ::operator delete(data); -} - -void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { - return ::operator new[](num_bytes); -} - -void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { - try { - return AllocateFromAssimpHeap::operator new[]( num_bytes ); - } - catch( ... ) { - return NULL; - } -} - -void AllocateFromAssimpHeap::operator delete[] ( void* data) { - return ::operator delete[](data); -} - -// ------------------------------------------------------------------------------------------------ -// Importer constructor. -Importer::Importer() - : pimpl( new ImporterPimpl ) { - pimpl->mScene = NULL; - pimpl->mErrorString = ""; - - // Allocate a default IO handler - pimpl->mIOHandler = new DefaultIOSystem; - pimpl->mIsDefaultHandler = true; - pimpl->bExtraVerbose = false; // disable extra verbose mode by default - - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - - GetImporterInstanceList(pimpl->mImporter); - GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps); - - // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list. - pimpl->mPPShared = new SharedPostProcessInfo(); - for (std::vector::iterator it = pimpl->mPostProcessingSteps.begin(); - it != pimpl->mPostProcessingSteps.end(); - ++it) { - - (*it)->SetSharedData(pimpl->mPPShared); - } -} - -// ------------------------------------------------------------------------------------------------ -// Destructor of Importer -Importer::~Importer() -{ - // Delete all import plugins - DeleteImporterInstanceList(pimpl->mImporter); - - // Delete all post-processing plug-ins - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) - delete pimpl->mPostProcessingSteps[a]; - - // Delete the assigned IO and progress handler - delete pimpl->mIOHandler; - delete pimpl->mProgressHandler; - - // Kill imported scene. Destructor's should do that recursively - delete pimpl->mScene; - - // Delete shared post-processing data - delete pimpl->mPPShared; - - // and finally the pimpl itself - delete pimpl; -} - -// ------------------------------------------------------------------------------------------------ -// Register a custom post-processing step -aiReturn Importer::RegisterPPStep(BaseProcess* pImp) -{ - ai_assert(NULL != pImp); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - pimpl->mPostProcessingSteps.push_back(pImp); - ASSIMP_LOG_INFO("Registering custom post-processing step"); - - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Register a custom loader plugin -aiReturn Importer::RegisterLoader(BaseImporter* pImp) -{ - ai_assert(NULL != pImp); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // -------------------------------------------------------------------- - // Check whether we would have two loaders for the same file extension - // This is absolutely OK, but we should warn the developer of the new - // loader that his code will probably never be called if the first - // loader is a bit too lazy in his file checking. - // -------------------------------------------------------------------- - std::set st; - std::string baked; - pImp->GetExtensionList(st); - - for(std::set::const_iterator it = st.begin(); it != st.end(); ++it) { - -#ifdef ASSIMP_BUILD_DEBUG - if (IsExtensionSupported(*it)) { - ASSIMP_LOG_WARN_F("The file extension ", *it, " is already in use"); - } -#endif - baked += *it; - } - - // add the loader - pimpl->mImporter.push_back(pImp); - ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Unregister a custom loader plugin -aiReturn Importer::UnregisterLoader(BaseImporter* pImp) -{ - if(!pImp) { - // unregistering a NULL importer is no problem for us ... really! - return AI_SUCCESS; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::vector::iterator it = std::find(pimpl->mImporter.begin(), - pimpl->mImporter.end(),pImp); - - if (it != pimpl->mImporter.end()) { - pimpl->mImporter.erase(it); - ASSIMP_LOG_INFO("Unregistering custom importer: "); - return AI_SUCCESS; - } - ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ..."); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Unregister a custom loader plugin -aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) -{ - if(!pImp) { - // unregistering a NULL ppstep is no problem for us ... really! - return AI_SUCCESS; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::vector::iterator it = std::find(pimpl->mPostProcessingSteps.begin(), - pimpl->mPostProcessingSteps.end(),pImp); - - if (it != pimpl->mPostProcessingSteps.end()) { - pimpl->mPostProcessingSteps.erase(it); - ASSIMP_LOG_INFO("Unregistering custom post-processing step"); - return AI_SUCCESS; - } - ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you .."); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Supplies a custom IO handler to the importer to open and access files. -void Importer::SetIOHandler( IOSystem* pIOHandler) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // If the new handler is zero, allocate a default IO implementation. - if (!pIOHandler) - { - // Release pointer in the possession of the caller - pimpl->mIOHandler = new DefaultIOSystem(); - pimpl->mIsDefaultHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mIOHandler != pIOHandler) - { - delete pimpl->mIOHandler; - pimpl->mIOHandler = pIOHandler; - pimpl->mIsDefaultHandler = false; - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the currently set IO handler -IOSystem* Importer::GetIOHandler() const { - return pimpl->mIOHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a custom IO handler is currently set -bool Importer::IsDefaultIOHandler() const { - return pimpl->mIsDefaultHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Supplies a custom progress handler to get regular callbacks during importing -void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - // If the new handler is zero, allocate a default implementation. - if (!pHandler) - { - // Release pointer in the possession of the caller - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mProgressHandler != pHandler) - { - delete pimpl->mProgressHandler; - pimpl->mProgressHandler = pHandler; - pimpl->mIsDefaultProgressHandler = false; - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the currently set progress handler -ProgressHandler* Importer::GetProgressHandler() const { - return pimpl->mProgressHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a custom progress handler is currently set -bool Importer::IsDefaultProgressHandler() const { - return pimpl->mIsDefaultProgressHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Validate post process step flags -bool _ValidateFlags(unsigned int pFlags) -{ - if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { - ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); - return false; - } - if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) { - ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible"); - return false; - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Free the current scene -void Importer::FreeScene( ) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - - delete pimpl->mScene; - pimpl->mScene = NULL; - - pimpl->mErrorString = ""; - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the current error string, if any -const char* Importer::GetErrorString() const -{ - /* Must remain valid as long as ReadFile() or FreeFile() are not called */ - return pimpl->mErrorString.c_str(); -} - -// ------------------------------------------------------------------------------------------------ -// Enable extra-verbose mode -void Importer::SetExtraVerbose(bool bDo) -{ - pimpl->bExtraVerbose = bDo; -} - -// ------------------------------------------------------------------------------------------------ -// Get the current scene -const aiScene* Importer::GetScene() const -{ - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -// Orphan the current scene and return it. -aiScene* Importer::GetOrphanedScene() -{ - aiScene* s = pimpl->mScene; - - ASSIMP_BEGIN_EXCEPTION_REGION(); - pimpl->mScene = NULL; - - pimpl->mErrorString = ""; /* reset error string */ - ASSIMP_END_EXCEPTION_REGION(aiScene*); - return s; -} - -// ------------------------------------------------------------------------------------------------ -// Validate post-processing flags -bool Importer::ValidateFlags(unsigned int pFlags) const -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // run basic checks for mutually exclusive flags - if(!_ValidateFlags(pFlags)) { - return false; - } - - // ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ... -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - if (pFlags & aiProcess_ValidateDataStructure) { - return false; - } -#endif - pFlags &= ~aiProcess_ValidateDataStructure; - - // Now iterate through all bits which are set in the flags and check whether we find at least - // one pp plugin which handles it. - for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) { - - if (pFlags & mask) { - - bool have = false; - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) { - - have = true; - break; - } - } - if (!have) { - return false; - } - } - } - ASSIMP_END_EXCEPTION_REGION(bool); - return true; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, - size_t pLength, - unsigned int pFlags, - const char* pHint /*= ""*/) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - if (!pHint) { - pHint = ""; - } - - if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { - pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; - return NULL; - } - - // prevent deletion of the previous IOHandler - IOSystem* io = pimpl->mIOHandler; - pimpl->mIOHandler = NULL; - - SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); - - // read the file and recover the previous IOSystem - static const size_t BufSize(Importer::MaxLenHint + 28); - char fbuff[BufSize]; - ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); - - ReadFile(fbuff,pFlags); - SetIOHandler(io); - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -void WriteLogOpening(const std::string& file) -{ - ASSIMP_LOG_INFO_F("Load ", file); - - // print a full version dump. This is nice because we don't - // need to ask the authors of incoming bug reports for - // the library version they're using - a log dump is - // sufficient. - const unsigned int flags( aiGetCompileFlags() ); - std::stringstream stream; - stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " " -#if defined(ASSIMP_BUILD_ARCHITECTURE) - << ASSIMP_BUILD_ARCHITECTURE -#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__) - << "x86" -#elif defined(_M_X64) || defined(__x86_64__) - << "amd64" -#elif defined(_M_IA64) || defined(__ia64__) - << "itanium" -#elif defined(__ppc__) || defined(__powerpc__) - << "ppc32" -#elif defined(__powerpc64__) - << "ppc64" -#elif defined(__arm__) - << "arm" -#else - << "" -#endif - << " " -#if defined(ASSIMP_BUILD_COMPILER) - << ( ASSIMP_BUILD_COMPILER ) -#elif defined(_MSC_VER) - << "msvc" -#elif defined(__GNUC__) - << "gcc" -#else - << "" -#endif - -#ifdef ASSIMP_BUILD_DEBUG - << " debug" -#endif - - << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "") - << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "") - << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : ""); - - ASSIMP_LOG_DEBUG(stream.str()); -} - -// ------------------------------------------------------------------------------------------------ -// Reads the given file and returns its contents if successful. -const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - const std::string pFile(_pFile); - - // ---------------------------------------------------------------------- - // Put a large try block around everything to catch all std::exception's - // that might be thrown by STL containers or by new(). - // ImportErrorException's are throw by ourselves and caught elsewhere. - //----------------------------------------------------------------------- - - WriteLogOpening(pFile); - -#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - try -#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS - { - // Check whether this Importer instance has already loaded - // a scene. In this case we need to delete the old one - if (pimpl->mScene) { - - ASSIMP_LOG_DEBUG("(Deleting previous scene)"); - FreeScene(); - } - - // First check if the file is accessible at all - if( !pimpl->mIOHandler->Exists( pFile)) { - - pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; - ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; - } - - std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); - if (profiler) { - profiler->BeginRegion("total"); - } - - // Find an worker class which can handle the file - BaseImporter* imp = NULL; - SetPropertyInteger("importerIndex", -1); - for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { - - if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) { - imp = pimpl->mImporter[a]; - SetPropertyInteger("importerIndex", a); - break; - } - } - - if (!imp) { - // not so bad yet ... try format auto detection. - const std::string::size_type s = pFile.find_last_of('.'); - if (s != std::string::npos) { - ASSIMP_LOG_INFO("File extension not known, trying signature-based detection"); - for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { - if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { - imp = pimpl->mImporter[a]; - SetPropertyInteger("importerIndex", a); - break; - } - } - } - // Put a proper error message if no suitable importer was found - if( !imp) { - pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; - ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; - } - } - - // Get file size for progress handler - IOStream * fileIO = pimpl->mIOHandler->Open( pFile ); - uint32_t fileSize = 0; - if (fileIO) - { - fileSize = static_cast(fileIO->FileSize()); - pimpl->mIOHandler->Close( fileIO ); - } - - // Dispatch the reading to the worker class for this format - const aiImporterDesc *desc( imp->GetInfo() ); - std::string ext( "unknown" ); - if ( NULL != desc ) { - ext = desc->mName; - } - ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); - pimpl->mProgressHandler->UpdateFileRead( 0, fileSize ); - - if (profiler) { - profiler->BeginRegion("import"); - } - - pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler); - pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize ); - - if (profiler) { - profiler->EndRegion("import"); - } - - SetPropertyString("sourceFilePath", pFile); - - // If successful, apply all active post processing steps to the imported data - if( pimpl->mScene) { - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. - if (pFlags & aiProcess_ValidateDataStructure) - { - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if (!pimpl->mScene) { - return NULL; - } - } -#endif // no validation - - // Preprocess the scene and prepare it for post-processing - if (profiler) { - profiler->BeginRegion("preprocess"); - } - - ScenePreprocessor pre(pimpl->mScene); - pre.ProcessScene(); - - if (profiler) { - profiler->EndRegion("preprocess"); - } - - // Ensure that the validation process won't be called twice - ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure)); - } - // if failed, extract the error string - else if( !pimpl->mScene) { - pimpl->mErrorString = imp->GetErrorText(); - } - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - - if (profiler) { - profiler->EndRegion("total"); - } - } -#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - catch (std::exception &e) - { -#if (defined _MSC_VER) && (defined _CPPRTTI) - // if we have RTTI get the full name of the exception that occurred - pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); -#else - pimpl->mErrorString = std::string("std::exception: ") + e.what(); -#endif - - ASSIMP_LOG_ERROR(pimpl->mErrorString); - delete pimpl->mScene; pimpl->mScene = NULL; - } -#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS - - // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - - -// ------------------------------------------------------------------------------------------------ -// Apply post-processing to the currently bound scene -const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // Return immediately if no scene is active - if (!pimpl->mScene) { - return NULL; - } - - // If no flags are given, return the current scene with no further action - if (!pFlags) { - return pimpl->mScene; - } - - // In debug builds: run basic flag validation - ai_assert(_ValidateFlags(pFlags)); - ASSIMP_LOG_INFO("Entering post processing pipeline"); - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process plays an exceptional role. It isn't contained in the global - // list of post-processing steps, so we need to call it manually. - if (pFlags & aiProcess_ValidateDataStructure) - { - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if (!pimpl->mScene) { - return NULL; - } - } -#endif // no validation -#ifdef ASSIMP_BUILD_DEBUG - if (pimpl->bExtraVerbose) - { -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings"); -#endif // no validation - pFlags |= aiProcess_ValidateDataStructure; - } -#else - if (pimpl->bExtraVerbose) { - ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting"); - } -#endif // ! DEBUG - - std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - - BaseProcess* process = pimpl->mPostProcessingSteps[a]; - pimpl->mProgressHandler->UpdatePostProcess(static_cast(a), static_cast(pimpl->mPostProcessingSteps.size()) ); - if( process->IsActive( pFlags)) { - - if (profiler) { - profiler->BeginRegion("postprocess"); - } - - process->ExecuteOnScene ( this ); - - if (profiler) { - profiler->EndRegion("postprocess"); - } - } - if( !pimpl->mScene) { - break; - } -#ifdef ASSIMP_BUILD_DEBUG - -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - continue; -#endif // no validation - - // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step - if (pimpl->bExtraVerbose) { - ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures"); - - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if( !pimpl->mScene) { - ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures"); - break; - } - } -#endif // ! DEBUG - } - pimpl->mProgressHandler->UpdatePostProcess( static_cast(pimpl->mPostProcessingSteps.size()), - static_cast(pimpl->mPostProcessingSteps.size()) ); - - // update private scene flags - if( pimpl->mScene ) - ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - ASSIMP_LOG_INFO("Leaving post processing pipeline"); - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // Return immediately if no scene is active - if ( NULL == pimpl->mScene ) { - return NULL; - } - - // If no flags are given, return the current scene with no further action - if ( NULL == rootProcess ) { - return pimpl->mScene; - } - - // In debug builds: run basic flag validation - ASSIMP_LOG_INFO( "Entering customized post processing pipeline" ); - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process plays an exceptional role. It isn't contained in the global - // list of post-processing steps, so we need to call it manually. - if ( requestValidation ) - { - ValidateDSProcess ds; - ds.ExecuteOnScene( this ); - if ( !pimpl->mScene ) { - return NULL; - } - } -#endif // no validation -#ifdef ASSIMP_BUILD_DEBUG - if ( pimpl->bExtraVerbose ) - { -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" ); -#endif // no validation - } -#else - if ( pimpl->bExtraVerbose ) { - ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" ); - } -#endif // ! DEBUG - - std::unique_ptr profiler( GetPropertyInteger( AI_CONFIG_GLOB_MEASURE_TIME, 0 ) ? new Profiler() : NULL ); - - if ( profiler ) { - profiler->BeginRegion( "postprocess" ); - } - - rootProcess->ExecuteOnScene( this ); - - if ( profiler ) { - profiler->EndRegion( "postprocess" ); - } - - // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step - if ( pimpl->bExtraVerbose || requestValidation ) { - ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" ); - - ValidateDSProcess ds; - ds.ExecuteOnScene( this ); - if ( !pimpl->mScene ) { - ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" ); - } - } - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" ); - - ASSIMP_END_EXCEPTION_REGION( const aiScene* ); - - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -// Helper function to check whether an extension is supported by ASSIMP -bool Importer::IsExtensionSupported(const char* szExtension) const -{ - return nullptr != GetImporter(szExtension); -} - -// ------------------------------------------------------------------------------------------------ -size_t Importer::GetImporterCount() const -{ - return pimpl->mImporter.size(); -} - -// ------------------------------------------------------------------------------------------------ -const aiImporterDesc* Importer::GetImporterInfo(size_t index) const -{ - if (index >= pimpl->mImporter.size()) { - return NULL; - } - return pimpl->mImporter[index]->GetInfo(); -} - - -// ------------------------------------------------------------------------------------------------ -BaseImporter* Importer::GetImporter (size_t index) const -{ - if (index >= pimpl->mImporter.size()) { - return NULL; - } - return pimpl->mImporter[index]; -} - -// ------------------------------------------------------------------------------------------------ -// Find a loader plugin for a given file extension -BaseImporter* Importer::GetImporter (const char* szExtension) const -{ - return GetImporter(GetImporterIndex(szExtension)); -} - -// ------------------------------------------------------------------------------------------------ -// Find a loader plugin for a given file extension -size_t Importer::GetImporterIndex (const char* szExtension) const { - ai_assert(nullptr != szExtension); - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // skip over wildcard and dot characters at string head -- - for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension ); - - std::string ext(szExtension); - if (ext.empty()) { - return static_cast(-1); - } - std::transform( ext.begin(), ext.end(), ext.begin(), ToLower ); - - std::set str; - for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { - str.clear(); - - (*i)->GetExtensionList(str); - for (std::set::const_iterator it = str.begin(); it != str.end(); ++it) { - if (ext == *it) { - return std::distance(static_cast< std::vector::const_iterator >(pimpl->mImporter.begin()), i); - } - } - } - ASSIMP_END_EXCEPTION_REGION(size_t); - return static_cast(-1); -} - -// ------------------------------------------------------------------------------------------------ -// Helper function to build a list of all file extensions supported by ASSIMP -void Importer::GetExtensionList(aiString& szOut) const -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::set str; - for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { - (*i)->GetExtensionList(str); - } - - // List can be empty - if( !str.empty() ) { - for (std::set::const_iterator it = str.begin();; ) { - szOut.Append("*."); - szOut.Append((*it).c_str()); - - if (++it == str.end()) { - break; - } - szOut.Append(";"); - } - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyInteger(const char* szName, int iValue) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty(pimpl->mIntProperties, szName,iValue); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty(pimpl->mFloatProperties, szName,iValue); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyString(const char* szName, const std::string& value) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty(pimpl->mStringProperties, szName,value); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty(pimpl->mMatrixProperties, szName,value); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -int Importer::GetPropertyInteger(const char* szName, - int iErrorReturn /*= 0xffffffff*/) const -{ - return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -ai_real Importer::GetPropertyFloat(const char* szName, - ai_real iErrorReturn /*= 10e10*/) const -{ - return GetGenericProperty(pimpl->mFloatProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const std::string Importer::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const -{ - return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const -{ - return GetGenericProperty(pimpl->mMatrixProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements of a single node -inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) -{ - iScene += sizeof(aiNode); - iScene += sizeof(unsigned int) * pcNode->mNumMeshes; - iScene += sizeof(void*) * pcNode->mNumChildren; - - for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { - AddNodeWeight(iScene,pcNode->mChildren[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements of the scene -void Importer::GetMemoryRequirements(aiMemoryInfo& in) const -{ - in = aiMemoryInfo(); - aiScene* mScene = pimpl->mScene; - - // return if we have no scene loaded - if (!pimpl->mScene) - return; - - - in.total = sizeof(aiScene); - - // add all meshes - for (unsigned int i = 0; i < mScene->mNumMeshes;++i) - { - in.meshes += sizeof(aiMesh); - if (mScene->mMeshes[i]->HasPositions()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - - if (mScene->mMeshes[i]->HasNormals()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - - if (mScene->mMeshes[i]->HasTangentsAndBitangents()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2; - } - - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { - if (mScene->mMeshes[i]->HasVertexColors(a)) { - in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; - } - else break; - } - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { - if (mScene->mMeshes[i]->HasTextureCoords(a)) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - else break; - } - if (mScene->mMeshes[i]->HasBones()) { - in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; - for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) { - in.meshes += sizeof(aiBone); - in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight); - } - } - in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces; - } - in.total += in.meshes; - - // add all embedded textures - for (unsigned int i = 0; i < mScene->mNumTextures;++i) { - const aiTexture* pc = mScene->mTextures[i]; - in.textures += sizeof(aiTexture); - if (pc->mHeight) { - in.textures += 4 * pc->mHeight * pc->mWidth; - } - else in.textures += pc->mWidth; - } - in.total += in.textures; - - // add all animations - for (unsigned int i = 0; i < mScene->mNumAnimations;++i) { - const aiAnimation* pc = mScene->mAnimations[i]; - in.animations += sizeof(aiAnimation); - - // add all bone anims - for (unsigned int a = 0; a < pc->mNumChannels; ++a) { - const aiNodeAnim* pc2 = pc->mChannels[i]; - in.animations += sizeof(aiNodeAnim); - in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey); - in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey); - in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey); - } - } - in.total += in.animations; - - // add all cameras and all lights - in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras; - in.total += in.lights = sizeof(aiLight) * mScene->mNumLights; - - // add all nodes - AddNodeWeight(in.nodes,mScene->mRootNode); - in.total += in.nodes; - - // add all materials - for (unsigned int i = 0; i < mScene->mNumMaterials;++i) { - const aiMaterial* pc = mScene->mMaterials[i]; - in.materials += sizeof(aiMaterial); - in.materials += pc->mNumAllocated * sizeof(void*); - - for (unsigned int a = 0; a < pc->mNumProperties;++a) { - in.materials += pc->mProperties[a]->mDataLength; - } - } - in.total += in.materials; -} diff --git a/thirdparty/assimp/code/Common/Importer.h b/thirdparty/assimp/code/Common/Importer.h deleted file mode 100644 index a439d99c2f20..000000000000 --- a/thirdparty/assimp/code/Common/Importer.h +++ /dev/null @@ -1,247 +0,0 @@ -/* -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 Importer.h mostly internal stuff for use by #Assimp::Importer */ -#pragma once -#ifndef INCLUDED_AI_IMPORTER_H -#define INCLUDED_AI_IMPORTER_H - -#include -#include -#include -#include - -struct aiScene; - -namespace Assimp { - class ProgressHandler; - class IOSystem; - class BaseImporter; - class BaseProcess; - class SharedPostProcessInfo; - - -//! @cond never -// --------------------------------------------------------------------------- -/** @brief Internal PIMPL implementation for Assimp::Importer - * - * Using this idiom here allows us to drop the dependency from - * std::vector and std::map in the public headers. Furthermore we are dropping - * any STL interface problems caused by mismatching STL settings. All - * size calculation are now done by us, not the app heap. */ -class ImporterPimpl { -public: - // Data type to store the key hash - typedef unsigned int KeyType; - - // typedefs for our four configuration maps. - // We don't need more, so there is no need for a generic solution - typedef std::map IntPropertyMap; - typedef std::map FloatPropertyMap; - typedef std::map StringPropertyMap; - typedef std::map MatrixPropertyMap; - - /** IO handler to use for all file accesses. */ - IOSystem* mIOHandler; - bool mIsDefaultHandler; - - /** Progress handler for feedback. */ - ProgressHandler* mProgressHandler; - bool mIsDefaultProgressHandler; - - /** Format-specific importer worker objects - one for each format we can read.*/ - std::vector< BaseImporter* > mImporter; - - /** Post processing steps we can apply at the imported data. */ - std::vector< BaseProcess* > mPostProcessingSteps; - - /** The imported data, if ReadFile() was successful, NULL otherwise. */ - aiScene* mScene; - - /** The error description, if there was one. */ - std::string mErrorString; - - /** List of integer properties */ - IntPropertyMap mIntProperties; - - /** List of floating-point properties */ - FloatPropertyMap mFloatProperties; - - /** List of string properties */ - StringPropertyMap mStringProperties; - - /** List of Matrix properties */ - MatrixPropertyMap mMatrixProperties; - - /** Used for testing - extra verbose mode causes the ValidateDataStructure-Step - * to be executed before and after every single post-process step */ - bool bExtraVerbose; - - /** Used by post-process steps to share data */ - SharedPostProcessInfo* mPPShared; - - /// The default class constructor. - ImporterPimpl() AI_NO_EXCEPT; -}; - -inline -ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT -: mIOHandler( nullptr ) -, mIsDefaultHandler( false ) -, mProgressHandler( nullptr ) -, mIsDefaultProgressHandler( false ) -, mImporter() -, mPostProcessingSteps() -, mScene( nullptr ) -, mErrorString() -, mIntProperties() -, mFloatProperties() -, mStringProperties() -, mMatrixProperties() -, bExtraVerbose( false ) -, mPPShared( nullptr ) { - // empty -} -//! @endcond - - -struct BatchData; - -// --------------------------------------------------------------------------- -/** FOR IMPORTER PLUGINS ONLY: A helper class to the pleasure of importers - * that need to load many external meshes recursively. - * - * The class uses several threads to load these meshes (or at least it - * could, this has not yet been implemented at the moment). - * - * @note The class may not be used by more than one thread*/ -class ASSIMP_API BatchLoader -{ - // friend of Importer - -public: - //! @cond never - // ------------------------------------------------------------------- - /** Wraps a full list of configuration properties for an importer. - * Properties can be set using SetGenericProperty */ - struct PropertyMap - { - ImporterPimpl::IntPropertyMap ints; - ImporterPimpl::FloatPropertyMap floats; - ImporterPimpl::StringPropertyMap strings; - ImporterPimpl::MatrixPropertyMap matrices; - - bool operator == (const PropertyMap& prop) const { - // fixme: really isocpp? gcc complains - return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices; - } - - bool empty () const { - return ints.empty() && floats.empty() && strings.empty() && matrices.empty(); - } - }; - //! @endcond - -public: - // ------------------------------------------------------------------- - /** Construct a batch loader from a given IO system to be used - * to access external files - */ - explicit BatchLoader(IOSystem* pIO, bool validate = false ); - - // ------------------------------------------------------------------- - /** The class destructor. - */ - ~BatchLoader(); - - // ------------------------------------------------------------------- - /** Sets the validation step. True for enable validation during postprocess. - * @param enable True for validation. - */ - void setValidation( bool enabled ); - - // ------------------------------------------------------------------- - /** Returns the current validation step. - * @return The current validation step. - */ - bool getValidation() const; - - // ------------------------------------------------------------------- - /** Add a new file to the list of files to be loaded. - * @param file File to be loaded - * @param steps Post-processing steps to be executed on the file - * @param map Optional configuration properties - * @return 'Load request channel' - an unique ID that can later - * be used to access the imported file data. - * @see GetImport */ - unsigned int AddLoadRequest ( - const std::string& file, - unsigned int steps = 0, - const PropertyMap* map = NULL - ); - - // ------------------------------------------------------------------- - /** Get an imported scene. - * This polls the import from the internal request list. - * If an import is requested several times, this function - * can be called several times, too. - * - * @param which LRWC returned by AddLoadRequest(). - * @return NULL if there is no scene with this file name - * in the queue of the scene hasn't been loaded yet. */ - aiScene* GetImport( - unsigned int which - ); - - // ------------------------------------------------------------------- - /** Waits until all scenes have been loaded. This returns - * immediately if no scenes are queued.*/ - void LoadAll(); - -private: - // No need to have that in the public API ... - BatchData *m_data; -}; - -} // Namespace Assimp - -#endif // INCLUDED_AI_IMPORTER_H diff --git a/thirdparty/assimp/code/Common/ImporterRegistry.cpp b/thirdparty/assimp/code/Common/ImporterRegistry.cpp deleted file mode 100644 index b9f28f03561e..000000000000 --- a/thirdparty/assimp/code/Common/ImporterRegistry.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 ImporterRegistry.cpp - -Central registry for all importers available. Do not edit this file -directly (unless you are adding new loaders), instead use the -corresponding preprocessor flag to selectively disable formats. -*/ - -#include -#include - -// ------------------------------------------------------------------------------------------------ -// Importers -// (include_new_importers_here) -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_NO_X_IMPORTER -# include "X/XFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER -# include "AMF/AMFImporter.hpp" -#endif -#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER -# include "3DS/3DSLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD3_IMPORTER -# include "MD3/MD3Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER -# include "MDL/MDLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER -# include "MD2/MD2Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_PLY_IMPORTER -# include "Ply/PlyLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER -# include "ASE/ASELoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER -# include "Obj/ObjFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_HMP_IMPORTER -# include "HMP/HMPLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_SMD_IMPORTER -# include "SMD/SMDLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MDC_IMPORTER -# include "MDC/MDCLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER -# include "MD5/MD5Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_STL_IMPORTER -# include "STL/STLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER -# include "LWO/LWOLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER -# include "DXF/DXFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_NFF_IMPORTER -# include "NFF/NFFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_RAW_IMPORTER -# include "Raw/RawLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER -# include "SIB/SIBImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_OFF_IMPORTER -# include "OFF/OFFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_AC_IMPORTER -# include "AC/ACLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER -# include "BVH/BVHLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER -# include "Irr/IRRMeshLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER -# include "Irr/IRRLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER -# include "Q3D/Q3DLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER -# include "B3D/B3DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER -# include "Collada/ColladaLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER -# include "Terragen/TerragenLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER -# include "CSM/CSMLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_3D_IMPORTER -# include "Unreal/UnrealLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER -# include "LWS/LWSLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER -# include "Ogre/OgreImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER -# include "OpenGEX/OpenGEXImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER -# include "MS3D/MS3DLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_COB_IMPORTER -# include "COB/COBLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER -# include "Blender/BlenderLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER -# include "Q3BSP/Q3BSPFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_NDO_IMPORTER -# include "NDO/NDOLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER -# include "Importer/IFC/IFCLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER -# include "XGL/XGLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER -# include "FBX/FBXImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER -# include "Assbin/AssbinLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER -# include "glTF/glTFImporter.h" -# include "glTF2/glTF2Importer.h" -#endif -#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER -# include "C4D/C4DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER -# include "3MF/D3MFImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER -# include "X3D/X3DImporter.hpp" -#endif -#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER -# include "MMD/MMDImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER -# include "M3D/M3DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER -# include "Importer/StepFile/StepFileImporter.h" -#endif - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -void GetImporterInstanceList(std::vector< BaseImporter* >& out) -{ - // ---------------------------------------------------------------------------- - // Add an instance of each worker class here - // (register_new_importers_here) - // ---------------------------------------------------------------------------- - out.reserve(64); -#if (!defined ASSIMP_BUILD_NO_X_IMPORTER) - out.push_back( new XFileImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER) - out.push_back( new ObjFileImporter()); -#endif -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER - out.push_back( new AMFImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) - out.push_back( new Discreet3DSImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER) - out.push_back( new M3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER) - out.push_back( new MD3Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER) - out.push_back( new MD2Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER) - out.push_back( new PLYImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER) - out.push_back( new MDLImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER) - #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) - out.push_back( new ASEImporter()); -# endif -#endif -#if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER) - out.push_back( new HMPImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER) - out.push_back( new SMDImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER) - out.push_back( new MDCImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER) - out.push_back( new MD5Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_STL_IMPORTER) - out.push_back( new STLImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) - out.push_back( new LWOImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER) - out.push_back( new DXFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER) - out.push_back( new NFFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER) - out.push_back( new RAWImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER) - out.push_back( new SIBImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER) - out.push_back( new OFFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_AC_IMPORTER) - out.push_back( new AC3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER) - out.push_back( new BVHLoader()); -#endif -#if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER) - out.push_back( new IRRMeshImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER) - out.push_back( new IRRImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER) - out.push_back( new Q3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER) - out.push_back( new B3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER) - out.push_back( new ColladaLoader()); -#endif -#if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER) - out.push_back( new TerragenImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER) - out.push_back( new CSMImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_3D_IMPORTER) - out.push_back( new UnrealImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER) - out.push_back( new LWSImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER) - out.push_back( new Ogre::OgreImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER ) - out.push_back( new OpenGEX::OpenGEXImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER) - out.push_back( new MS3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_COB_IMPORTER) - out.push_back( new COBImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER) - out.push_back( new BlenderImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER) - out.push_back( new Q3BSPFileImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER) - out.push_back( new NDOImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER) - out.push_back( new IFCImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_XGL_IMPORTER ) - out.push_back( new XGLImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER ) - out.push_back( new FBXImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER ) - out.push_back( new AssbinImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER ) - out.push_back( new glTFImporter() ); - out.push_back( new glTF2Importer() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER ) - out.push_back( new C4DImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER ) - out.push_back( new D3MFImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER - out.push_back( new X3DImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER - out.push_back( new MMDImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER - out.push_back(new StepFile::StepFileImporter()); -#endif -} - -/** will delete all registered importers. */ -void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){ - for(size_t i= 0; i -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------- -/** Compute the signed area of a triangle. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template -inline double GetArea2D(const T& v1, const T& v2, const T& v3) -{ - return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y)); -} - -// ------------------------------------------------------------------------------- -/** Test if a given point p2 is on the left side of the line formed by p0-p1. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template -inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) -{ - return GetArea2D(p0,p2,p1) > 0; -} - -// ------------------------------------------------------------------------------- -/** Test if a given point is inside a given triangle in R2. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template -inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) -{ - // Point in triangle test using baryzentric coordinates - const aiVector2D v0 = p1 - p0; - const aiVector2D v1 = p2 - p0; - const aiVector2D v2 = pp - p0; - - double dot00 = v0 * v0; - double dot01 = v0 * v1; - double dot02 = v0 * v2; - double dot11 = v1 * v1; - double dot12 = v1 * v2; - - const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom; - dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom; - - return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1); -} - - -// ------------------------------------------------------------------------------- -/** Check whether the winding order of a given polygon is counter-clockwise. - * The function accepts an unconstrained template parameter, but is intended - * to be used only with aiVector2D and aiVector3D (z axis is ignored, only - * x and y are taken into account). - * @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++ - */ -template -inline bool IsCCW(T* in, size_t npoints) { - double aa, bb, cc, b, c, theta; - double convex_turn; - double convex_sum = 0; - - ai_assert(npoints >= 3); - - for (size_t i = 0; i < npoints - 2; i++) { - aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) + - ((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y)); - - bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) + - ((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y)); - - cc = ((in[i+2].x - in[i+1].x) * - (in[i+2].x - in[i+1].x)) + - ((-in[i+2].y + in[i+1].y) * - (-in[i+2].y + in[i+1].y)); - - b = std::sqrt(bb); - c = std::sqrt(cc); - theta = std::acos((bb + cc - aa) / (2 * b * c)); - - if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) { - // if (convex(in[i].x, in[i].y, - // in[i+1].x, in[i+1].y, - // in[i+2].x, in[i+2].y)) { - convex_turn = AI_MATH_PI_F - theta; - convex_sum += convex_turn; - } - else { - convex_sum -= AI_MATH_PI_F - theta; - } - } - aa = ((in[1].x - in[npoints-2].x) * - (in[1].x - in[npoints-2].x)) + - ((-in[1].y + in[npoints-2].y) * - (-in[1].y + in[npoints-2].y)); - - bb = ((in[0].x - in[npoints-2].x) * - (in[0].x - in[npoints-2].x)) + - ((-in[0].y + in[npoints-2].y) * - (-in[0].y + in[npoints-2].y)); - - cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) + - ((-in[1].y + in[0].y) * (-in[1].y + in[0].y)); - - b = std::sqrt(bb); - c = std::sqrt(cc); - theta = std::acos((bb + cc - aa) / (2 * b * c)); - - //if (convex(in[npoints-2].x, in[npoints-2].y, - // in[0].x, in[0].y, - // in[1].x, in[1].y)) { - if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) { - convex_turn = AI_MATH_PI_F - theta; - convex_sum += convex_turn; - } - else { - convex_sum -= AI_MATH_PI_F - theta; - } - - return convex_sum >= (2 * AI_MATH_PI_F); -} - - -// ------------------------------------------------------------------------------- -/** Compute the normal of an arbitrary polygon in R3. - * - * The code is based on Newell's formula, that is a polygons normal is the ratio - * of its area when projected onto the three coordinate axes. - * - * @param out Receives the output normal - * @param num Number of input vertices - * @param x X data source. x[ofs_x*n] is the n'th element. - * @param y Y data source. y[ofs_y*n] is the y'th element - * @param z Z data source. z[ofs_z*n] is the z'th element - * - * @note The data arrays must have storage for at least num+2 elements. Using - * this method is much faster than the 'other' NewellNormal() - */ -template -inline void NewellNormal (aiVector3t& out, int num, TReal* x, TReal* y, TReal* z) -{ - // Duplicate the first two vertices at the end - x[(num+0)*ofs_x] = x[0]; - x[(num+1)*ofs_x] = x[ofs_x]; - - y[(num+0)*ofs_y] = y[0]; - y[(num+1)*ofs_y] = y[ofs_y]; - - z[(num+0)*ofs_z] = z[0]; - z[(num+1)*ofs_z] = z[ofs_z]; - - TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0; - - TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2; - TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2; - TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2; - - for (int tmp=0; tmp < num; tmp++) { - sum_xy += (*xptr) * ( (*yhigh) - (*ylow) ); - sum_yz += (*yptr) * ( (*zhigh) - (*zlow) ); - sum_zx += (*zptr) * ( (*xhigh) - (*xlow) ); - - xptr += ofs_x; - xlow += ofs_x; - xhigh += ofs_x; - - yptr += ofs_y; - ylow += ofs_y; - yhigh += ofs_y; - - zptr += ofs_z; - zlow += ofs_z; - zhigh += ofs_z; - } - out = aiVector3t(sum_yz,sum_zx,sum_xy); -} - -} // ! Assimp - -#endif diff --git a/thirdparty/assimp/code/Common/PostStepRegistry.cpp b/thirdparty/assimp/code/Common/PostStepRegistry.cpp deleted file mode 100644 index 8ff4af040062..000000000000 --- a/thirdparty/assimp/code/Common/PostStepRegistry.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 ImporterRegistry.cpp - -Central registry for all postprocessing steps available. Do not edit this file -directly (unless you are adding new steps), instead use the -corresponding preprocessor flag to selectively disable steps. -*/ - -#include "PostProcessing/ProcessHelper.h" - -#ifndef ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS -# include "PostProcessing/CalcTangentsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS -# include "PostProcessing/JoinVerticesProcess.h" -#endif -#if !(defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS && defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS && defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS) -# include "PostProcessing/ConvertToLHProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS -# include "PostProcessing/TriangulateProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_DROPFACENORMALS_PROCESS -# include "PostProcessing/DropFaceNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS -# include "PostProcessing/GenFaceNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS -# include "PostProcessing/GenVertexNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_REMOVEVC_PROCESS -# include "PostProcessing/RemoveVCProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS -# include "PostProcessing/SplitLargeMeshes.h" -#endif -#ifndef ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS -# include "PostProcessing/PretransformVertices.h" -#endif -#ifndef ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS -# include "PostProcessing/LimitBoneWeightsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS -# include "PostProcessing/ValidateDataStructure.h" -#endif -#ifndef ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS -# include "PostProcessing/ImproveCacheLocality.h" -#endif -#ifndef ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS -# include "PostProcessing/FixNormalsStep.h" -#endif -#ifndef ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS -# include "PostProcessing/RemoveRedundantMaterials.h" -#endif -#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) -# include "PostProcessing/EmbedTexturesProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS -# include "PostProcessing/FindInvalidDataProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS -# include "PostProcessing/FindDegenerates.h" -#endif -#ifndef ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS -# include "PostProcessing/SortByPTypeProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS -# include "PostProcessing/ComputeUVMappingProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS -# include "PostProcessing/TextureTransform.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS -# include "PostProcessing/FindInstancesProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS -# include "PostProcessing/OptimizeMeshes.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS -# include "PostProcessing/OptimizeGraph.h" -#endif -#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS -# include "Common/SplitByBoneCountProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS -# include "PostProcessing/DeboneProcess.h" -#endif -#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) -# include "PostProcessing/ScaleProcess.h" -#endif -#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS) -# include "PostProcessing/ArmaturePopulate.h" -#endif -#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) -# include "PostProcessing/GenBoundingBoxesProcess.h" -#endif - - - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) -{ - // ---------------------------------------------------------------------------- - // Add an instance of each post processing step here in the order - // of sequence it is executed. Steps that are added here are not - // validated - as RegisterPPStep() does - all dependencies must be given. - // ---------------------------------------------------------------------------- - out.reserve(31); -#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS) - out.push_back( new MakeLeftHandedProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS) - out.push_back( new FlipUVsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS) - out.push_back( new FlipWindingOrderProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS) - out.push_back( new RemoveVCProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) - out.push_back( new RemoveRedundantMatsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) - out.push_back( new EmbedTexturesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS) - out.push_back( new FindInstancesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS) - out.push_back( new OptimizeGraphProcess()); -#endif -#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS - out.push_back( new ComputeUVMappingProcess()); -#endif -#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS - out.push_back( new TextureTransformStep()); -#endif -#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) - out.push_back( new ScaleProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS) - out.push_back( new ArmaturePopulate()); -#endif -#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) - out.push_back( new PretransformVertices()); -#endif -#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS) - out.push_back( new TriangulateProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS) - //find degenerates should run after triangulation (to sort out small - //generated triangles) but before sort by p types (in case there are lines - //and points generated and inserted into a mesh) - out.push_back( new FindDegeneratesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS) - out.push_back( new SortByPTypeProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS) - out.push_back( new FindInvalidDataProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS) - out.push_back( new OptimizeMeshesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS) - out.push_back( new FixInfacingNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS) - out.push_back( new SplitByBoneCountProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS) - out.push_back( new SplitLargeMeshesProcess_Triangle()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) - out.push_back( new DropFaceNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) - out.push_back( new GenFaceNormalsProcess()); -#endif - // ......................................................................... - // DON'T change the order of these five .. - // XXX this is actually a design weakness that dates back to the time - // when Importer would maintain the postprocessing step list exclusively. - // Now that others access it too, we need a better solution. - out.push_back( new ComputeSpatialSortProcess()); - // ......................................................................... - -#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS) - out.push_back( new GenVertexNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS) - out.push_back( new CalcTangentsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS) - out.push_back( new JoinVerticesProcess()); -#endif - - // ......................................................................... - out.push_back( new DestroySpatialSortProcess()); - // ......................................................................... - -#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS) - out.push_back( new SplitLargeMeshesProcess_Vertex()); -#endif -#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS) - out.push_back( new DeboneProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS) - out.push_back( new LimitBoneWeightsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS) - out.push_back( new ImproveCacheLocalityProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) - out.push_back(new GenBoundingBoxesProcess); -#endif -} - -} diff --git a/thirdparty/assimp/code/Common/RemoveComments.cpp b/thirdparty/assimp/code/Common/RemoveComments.cpp deleted file mode 100644 index 91700a76999d..000000000000 --- a/thirdparty/assimp/code/Common/RemoveComments.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -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 RemoveComments.cpp - * @brief Defines the CommentRemover utility class - */ - -#include -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -// Remove line comments from a file -void CommentRemover::RemoveLineComments(const char* szComment, - char* szBuffer, char chReplacement /* = ' ' */) -{ - // validate parameters - ai_assert(NULL != szComment && NULL != szBuffer && *szComment); - - const size_t len = strlen(szComment); - while (*szBuffer) { - - // skip over quotes - if (*szBuffer == '\"' || *szBuffer == '\'') - while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); - - if (!strncmp(szBuffer,szComment,len)) { - while (!IsLineEnd(*szBuffer)) - *szBuffer++ = chReplacement; - - if (!*szBuffer) { - break; - } - } - ++szBuffer; - } -} - -// ------------------------------------------------------------------------------------------------ -// Remove multi-line comments from a file -void CommentRemover::RemoveMultiLineComments(const char* szCommentStart, - const char* szCommentEnd,char* szBuffer, - char chReplacement) -{ - // validate parameters - ai_assert(NULL != szCommentStart && NULL != szCommentEnd && - NULL != szBuffer && *szCommentStart && *szCommentEnd); - - const size_t len = strlen(szCommentEnd); - const size_t len2 = strlen(szCommentStart); - - while (*szBuffer) { - // skip over quotes - if (*szBuffer == '\"' || *szBuffer == '\'') - while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); - - if (!strncmp(szBuffer,szCommentStart,len2)) { - while (*szBuffer) { - if (!::strncmp(szBuffer,szCommentEnd,len)) { - for (unsigned int i = 0; i < len;++i) - *szBuffer++ = chReplacement; - - break; - } - *szBuffer++ = chReplacement; - } - continue; - } - ++szBuffer; - } -} - -} // !! Assimp diff --git a/thirdparty/assimp/code/Common/SGSpatialSort.cpp b/thirdparty/assimp/code/Common/SGSpatialSort.cpp deleted file mode 100644 index 120070b0aa43..000000000000 --- a/thirdparty/assimp/code/Common/SGSpatialSort.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the helper class to quickly find -vertices close to a given position. Special implementation for -the 3ds loader handling smooth groups correctly */ - -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -SGSpatialSort::SGSpatialSort() -{ - // define the reference plane. We choose some arbitrary vector away from all basic axises - // in the hope that no model spreads all its vertices along this plane. - mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f); - mPlaneNormal.Normalize(); -} -// ------------------------------------------------------------------------------------------------ -// Destructor -SGSpatialSort::~SGSpatialSort() -{ - // nothing to do here, everything destructs automatically -} -// ------------------------------------------------------------------------------------------------ -void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index, - unsigned int smoothingGroup) -{ - // store position by index and distance - float distance = vPosition * mPlaneNormal; - mPositions.push_back( Entry( index, vPosition, - distance, smoothingGroup)); -} -// ------------------------------------------------------------------------------------------------ -void SGSpatialSort::Prepare() -{ - // now sort the array ascending by distance. - std::sort( this->mPositions.begin(), this->mPositions.end()); -} -// ------------------------------------------------------------------------------------------------ -// Returns an iterator for all positions close to the given position. -void SGSpatialSort::FindPositions( const aiVector3D& pPosition, - uint32_t pSG, - float pRadius, - std::vector& poResults, - bool exactMatch /*= false*/) const -{ - float dist = pPosition * mPlaneNormal; - float minDist = dist - pRadius, maxDist = dist + pRadius; - - // clear the array - poResults.clear(); - - // quick check for positions outside the range - if( mPositions.empty() ) - return; - if( maxDist < mPositions.front().mDistance) - return; - if( minDist > mPositions.back().mDistance) - return; - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - if( mPositions[index].mDistance < minDist) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && mPositions[index].mDistance > minDist) - index--; - while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist) - index++; - - // Mow start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the given radius to the result aray - - float squareEpsilon = pRadius * pRadius; - std::vector::const_iterator it = mPositions.begin() + index; - std::vector::const_iterator end = mPositions.end(); - - if (exactMatch) - { - while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG) - { - poResults.push_back( it->mIndex); - } - ++it; - if( end == it )break; - } - } - else - { - // if the given smoothing group is 0, we'll return all surrounding vertices - if (!pSG) - { - while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon) - poResults.push_back( it->mIndex); - ++it; - if( end == it)break; - } - } - else while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon && - (it->mSmoothGroups & pSG || !it->mSmoothGroups)) - { - poResults.push_back( it->mIndex); - } - ++it; - if( end == it)break; - } - } -} - - diff --git a/thirdparty/assimp/code/Common/SceneCombiner.cpp b/thirdparty/assimp/code/Common/SceneCombiner.cpp deleted file mode 100644 index f7b13cc95128..000000000000 --- a/thirdparty/assimp/code/Common/SceneCombiner.cpp +++ /dev/null @@ -1,1350 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -// TODO: refactor entire file to get rid of the "flat-copy" first approach -// to copying structures. This easily breaks in the most unintuitive way -// possible as new fields are added to assimp structures. - -// ---------------------------------------------------------------------------- -/** - * @file Implements Assimp::SceneCombiner. This is a smart utility - * class that combines multiple scenes, meshes, ... into one. Currently - * these utilities are used by the IRR and LWS loaders and the - * OptimizeGraph step. - */ -// ---------------------------------------------------------------------------- -#include -#include -#include -#include -#include -#include "time.h" -#include -#include -#include -#include -#include "ScenePrivate.h" - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -// Add a prefix to a string -inline -void PrefixString(aiString& string,const char* prefix, unsigned int len) { - // If the string is already prefixed, we won't prefix it a second time - if (string.length >= 1 && string.data[0] == '$') - return; - - if (len+string.length>=MAXLEN-1) { - ASSIMP_LOG_DEBUG("Can't add an unique prefix because the string is too long"); - ai_assert(false); - return; - } - - // Add the prefix - ::memmove(string.data+len,string.data,string.length+1); - ::memcpy (string.data, prefix, len); - - // And update the string's length - string.length += len; -} - -// ------------------------------------------------------------------------------------------------ -// Add node identifiers to a hashing set -void SceneCombiner::AddNodeHashes(aiNode* node, std::set& hashes) { - // Add node name to hashing set if it is non-empty - empty nodes are allowed - // and they can't have any anims assigned so its absolutely safe to duplicate them. - if (node->mName.length) { - hashes.insert( SuperFastHash(node->mName.data, static_cast(node->mName.length)) ); - } - - // Process all children recursively - for (unsigned int i = 0; i < node->mNumChildren;++i) - AddNodeHashes(node->mChildren[i],hashes); -} - -// ------------------------------------------------------------------------------------------------ -// Add a name prefix to all nodes in a hierarchy -void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len) { - ai_assert(NULL != prefix); - PrefixString(node->mName,prefix,len); - - // Process all children recursively - for ( unsigned int i = 0; i < node->mNumChildren; ++i ) { - AddNodePrefixes( node->mChildren[ i ], prefix, len ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Search for matching names -bool SceneCombiner::FindNameMatch(const aiString& name, std::vector& input, unsigned int cur) { - const unsigned int hash = SuperFastHash(name.data, static_cast(name.length)); - - // Check whether we find a positive match in one of the given sets - for (unsigned int i = 0; i < input.size(); ++i) { - if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { - return true; - } - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Add a name prefix to all nodes in a hierarchy if a hash match is found -void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len, - std::vector& input, unsigned int cur) { - ai_assert(NULL != prefix); - const unsigned int hash = SuperFastHash(node->mName.data, static_cast(node->mName.length)); - - // Check whether we find a positive match in one of the given sets - for (unsigned int i = 0; i < input.size(); ++i) { - if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { - PrefixString(node->mName,prefix,len); - break; - } - } - - // Process all children recursively - for (unsigned int i = 0; i < node->mNumChildren;++i) - AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur); -} - -// ------------------------------------------------------------------------------------------------ -// Add an offset to all mesh indices in a node graph -void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset) { - for (unsigned int i = 0; i < node->mNumMeshes;++i) - node->mMeshes[i] += offset; - - for ( unsigned int i = 0; i < node->mNumChildren; ++i ) { - OffsetNodeMeshIndices( node->mChildren[ i ], offset ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Merges two scenes. Currently only used by the LWS loader. -void SceneCombiner::MergeScenes(aiScene** _dest,std::vector& src, unsigned int flags) { - if ( nullptr == _dest ) { - return; - } - - // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it - if (src.empty()) { - if (*_dest) { - (*_dest)->~aiScene(); - SceneCombiner::CopySceneFlat(_dest,src[0]); - } - else *_dest = src[0]; - return; - } - if (*_dest)(*_dest)->~aiScene(); - else *_dest = new aiScene(); - - // Create a dummy scene to serve as master for the others - aiScene* master = new aiScene(); - master->mRootNode = new aiNode(); - master->mRootNode->mName.Set(""); - - std::vector srcList (src.size()); - for (unsigned int i = 0; i < srcList.size();++i) { - srcList[i] = AttachmentInfo(src[i],master->mRootNode); - } - - // 'master' will be deleted afterwards - MergeScenes (_dest, master, srcList, flags); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::AttachToGraph (aiNode* attach, std::vector& srcList) { - unsigned int cnt; - for ( cnt = 0; cnt < attach->mNumChildren; ++cnt ) { - AttachToGraph( attach->mChildren[ cnt ], srcList ); - } - - cnt = 0; - for (std::vector::iterator it = srcList.begin(); - it != srcList.end(); ++it) - { - if ((*it).attachToNode == attach && !(*it).resolved) - ++cnt; - } - - if (cnt) { - aiNode** n = new aiNode*[cnt+attach->mNumChildren]; - if (attach->mNumChildren) { - ::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren); - delete[] attach->mChildren; - } - attach->mChildren = n; - - n += attach->mNumChildren; - attach->mNumChildren += cnt; - - for (unsigned int i = 0; i < srcList.size();++i) { - NodeAttachmentInfo& att = srcList[i]; - if (att.attachToNode == attach && !att.resolved) { - *n = att.node; - (**n).mParent = attach; - ++n; - - // mark this attachment as resolved - att.resolved = true; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::AttachToGraph ( aiScene* master, std::vector& src) { - ai_assert(NULL != master); - AttachToGraph(master->mRootNode,src); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, std::vector& srcList, unsigned int flags) { - if ( nullptr == _dest ) { - return; - } - - // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it - if (srcList.empty()) { - if (*_dest) { - SceneCombiner::CopySceneFlat(_dest,master); - } - else *_dest = master; - return; - } - if (*_dest) { - (*_dest)->~aiScene(); - new (*_dest) aiScene(); - } - else *_dest = new aiScene(); - - aiScene* dest = *_dest; - - std::vector src (srcList.size()+1); - src[0].scene = master; - for (unsigned int i = 0; i < srcList.size();++i) { - src[i+1] = SceneHelper( srcList[i].scene ); - } - - // this helper array specifies which scenes are duplicates of others - std::vector duplicates(src.size(),UINT_MAX); - - // this helper array is used as lookup table several times - std::vector offset(src.size()); - - // Find duplicate scenes - for (unsigned int i = 0; i < src.size();++i) { - if (duplicates[i] != i && duplicates[i] != UINT_MAX) { - continue; - } - - duplicates[i] = i; - for ( unsigned int a = i+1; a < src.size(); ++a) { - if (src[i].scene == src[a].scene) { - duplicates[a] = i; - } - } - } - - // Generate unique names for all named stuff? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) - { -#if 0 - // Construct a proper random number generator - boost::mt19937 rng( ); - boost::uniform_int<> dist(1u,1 << 24u); - boost::variate_generator > rndGen(rng, dist); -#endif - for (unsigned int i = 1; i < src.size();++i) - { - //if (i != duplicates[i]) - //{ - // // duplicate scenes share the same UID - // ::strcpy( src[i].id, src[duplicates[i]].id ); - // src[i].idlen = src[duplicates[i]].idlen; - - // continue; - //} - - src[i].idlen = ai_snprintf(src[i].id, 32, "$%.6X$_",i); - - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - - // Compute hashes for all identifiers in this scene and store them - // in a sorted table (for convenience I'm using std::set). We hash - // just the node and animation channel names, all identifiers except - // the material names should be caught by doing this. - AddNodeHashes(src[i]->mRootNode,src[i].hashes); - - for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) { - aiAnimation* anim = src[i]->mAnimations[a]; - src[i].hashes.insert(SuperFastHash(anim->mName.data,static_cast(anim->mName.length))); - } - } - } - } - - unsigned int cnt; - - // First find out how large the respective output arrays must be - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - - if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { - dest->mNumTextures += (*cur)->mNumTextures; - dest->mNumMaterials += (*cur)->mNumMaterials; - dest->mNumMeshes += (*cur)->mNumMeshes; - } - - dest->mNumLights += (*cur)->mNumLights; - dest->mNumCameras += (*cur)->mNumCameras; - dest->mNumAnimations += (*cur)->mNumAnimations; - - // Combine the flags of all scenes - // We need to process them flag-by-flag here to get correct results - // dest->mFlags ; //|= (*cur)->mFlags; - if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - } - } - - // generate the output texture list + an offset table for all texture indices - if (dest->mNumTextures) - { - aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumTextures;++i) - { - if (n != duplicates[n]) - { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip,(*cur)->mTextures[i]); - - else continue; - } - else *pip = (*cur)->mTextures[i]; - ++pip; - } - - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mTextures); - } - } - - // generate the output material list + an offset table for all material indices - if (dest->mNumMaterials) - { - aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i) - { - if (n != duplicates[n]) - { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip,(*cur)->mMaterials[i]); - - else continue; - } - else *pip = (*cur)->mMaterials[i]; - - if ((*cur)->mNumTextures != dest->mNumTextures) { - // We need to update all texture indices of the mesh. So we need to search for - // a material property called '$tex.file' - - for (unsigned int a = 0; a < (*pip)->mNumProperties;++a) - { - aiMaterialProperty* prop = (*pip)->mProperties[a]; - if (!strncmp(prop->mKey.data,"$tex.file",9)) - { - // Check whether this texture is an embedded texture. - // In this case the property looks like this: *, - // where n is the index of the texture. - aiString& s = *((aiString*)prop->mData); - if ('*' == s.data[0]) { - // Offset the index and write it back .. - const unsigned int idx = strtoul10(&s.data[1]) + offset[n]; - ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx); - } - } - - // Need to generate new, unique material names? - else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) - { - aiString* pcSrc = (aiString*) prop->mData; - PrefixString(*pcSrc, (*cur).id, (*cur).idlen); - } - } - } - ++pip; - } - - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mMaterials); - } - } - - // generate the output mesh list + again an offset table for all mesh indices - if (dest->mNumMeshes) - { - aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) - { - if (n != duplicates[n]) { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip, (*cur)->mMeshes[i]); - - else continue; - } - else *pip = (*cur)->mMeshes[i]; - - // update the material index of the mesh - (*pip)->mMaterialIndex += offset[n]; - ++pip; - } - - // reuse the offset array - store now the mesh offset in it - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mMeshes); - } - } - - std::vector nodes; - nodes.reserve(srcList.size()); - - // ---------------------------------------------------------------------------- - // Now generate the output node graph. We need to make those - // names in the graph that are referenced by anims or lights - // or cameras unique. So we add a prefix to them ... $_ - // We could also use a counter, but using a random value allows us to - // use just one prefix if we are joining multiple scene hierarchies recursively. - // Chances are quite good we don't collide, so we try that ... - // ---------------------------------------------------------------------------- - - // Allocate space for light sources, cameras and animations - aiLight** ppLights = dest->mLights = (dest->mNumLights - ? new aiLight*[dest->mNumLights] : NULL); - - aiCamera** ppCameras = dest->mCameras = (dest->mNumCameras - ? new aiCamera*[dest->mNumCameras] : NULL); - - aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations - ? new aiAnimation*[dest->mNumAnimations] : NULL); - - for ( int n = static_cast(src.size()-1); n >= 0 ;--n ) /* !!! important !!! */ - { - SceneHelper* cur = &src[n]; - aiNode* node; - - // To offset or not to offset, this is the question - if (n != (int)duplicates[n]) - { - // Get full scene-graph copy - Copy( &node, (*cur)->mRootNode ); - OffsetNodeMeshIndices(node,offset[duplicates[n]]); - - if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { - // (note:) they are already 'offseted' by offset[duplicates[n]] - OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]); - } - } - else // if (n == duplicates[n]) - { - node = (*cur)->mRootNode; - OffsetNodeMeshIndices(node,offset[n]); - } - if (n) // src[0] is the master node - nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n )); - - // add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - - // or the whole scenegraph - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n); - } - else AddNodePrefixes(node,(*cur).id,(*cur).idlen); - - // meshes - for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) { - aiMesh* mesh = (*cur)->mMeshes[i]; - - // rename all bones - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch(mesh->mBones[a]->mName,src,n)) - continue; - } - PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen); - } - } - } - - // -------------------------------------------------------------------- - // Copy light sources - for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights) - { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppLights, (*cur)->mLights[i]); - } - else *ppLights = (*cur)->mLights[i]; - - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppLights)->mName,src,n)) - continue; - } - - PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen); - } - } - - // -------------------------------------------------------------------- - // Copy cameras - for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras) { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppCameras, (*cur)->mCameras[i]); - } - else *ppCameras = (*cur)->mCameras[i]; - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppCameras)->mName,src,n)) - continue; - } - - PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen); - } - } - - // -------------------------------------------------------------------- - // Copy animations - for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims) { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppAnims, (*cur)->mAnimations[i]); - } - else *ppAnims = (*cur)->mAnimations[i]; - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppAnims)->mName,src,n)) - continue; - } - - PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen); - - // don't forget to update all node animation channels - for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n)) - continue; - } - - PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen); - } - } - } - } - - // Now build the output graph - AttachToGraph ( master, nodes); - dest->mRootNode = master->mRootNode; - - // Check whether we succeeded at building the output graph - for (std::vector ::iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(*it).resolved) { - if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) { - // search for this attachment point in all other imported scenes, too. - for ( unsigned int n = 0; n < src.size();++n ) { - if (n != (*it).src_idx) { - AttachToGraph(src[n].scene,nodes); - if ((*it).resolved) - break; - } - } - } - if (!(*it).resolved) { - ASSIMP_LOG_ERROR_F( "SceneCombiner: Failed to resolve attachment ", (*it).node->mName.data, - " ", (*it).attachToNode->mName.data ); - } - } - } - - // now delete all input scenes. Make sure duplicate scenes aren't - // deleted more than one time - for ( unsigned int n = 0; n < src.size();++n ) { - if (n != duplicates[n]) // duplicate scene? - continue; - - aiScene* deleteMe = src[n].scene; - - // We need to delete the arrays before the destructor is called - - // we are reusing the array members - delete[] deleteMe->mMeshes; deleteMe->mMeshes = NULL; - delete[] deleteMe->mCameras; deleteMe->mCameras = NULL; - delete[] deleteMe->mLights; deleteMe->mLights = NULL; - delete[] deleteMe->mMaterials; deleteMe->mMaterials = NULL; - delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL; - - deleteMe->mRootNode = NULL; - - // Now we can safely delete the scene - delete deleteMe; - } - - // Check flags - if (!dest->mNumMeshes || !dest->mNumMaterials) { - dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - - // We're finished -} - -// ------------------------------------------------------------------------------------------------ -// Build a list of unique bones -void SceneCombiner::BuildUniqueBoneList(std::list& asBones, - std::vector::const_iterator it, - std::vector::const_iterator end) -{ - unsigned int iOffset = 0; - for (; it != end;++it) { - for (unsigned int l = 0; l < (*it)->mNumBones;++l) { - aiBone* p = (*it)->mBones[l]; - uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length); - - std::list::iterator it2 = asBones.begin(); - std::list::iterator end2 = asBones.end(); - - for (;it2 != end2;++it2) { - if ((*it2).first == itml) { - (*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset)); - break; - } - } - if (end2 == it2) { - // need to begin a new bone entry - asBones.push_back(BoneWithHash()); - BoneWithHash& btz = asBones.back(); - - // setup members - btz.first = itml; - btz.second = &p->mName; - btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset)); - } - } - iOffset += (*it)->mNumVertices; - } -} - -// ------------------------------------------------------------------------------------------------ -// Merge a list of bones -void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator it, - std::vector::const_iterator end) -{ - if ( nullptr == out || out->mNumBones == 0 ) { - return; - } - - // find we need to build an unique list of all bones. - // we work with hashes to make the comparisons MUCH faster, - // at least if we have many bones. - std::list asBones; - BuildUniqueBoneList( asBones, it, end ); - - // now create the output bones - out->mNumBones = 0; - out->mBones = new aiBone*[asBones.size()]; - - for (std::list::const_iterator boneIt = asBones.begin(),boneEnd = asBones.end(); boneIt != boneEnd; ++boneIt ) { - // Allocate a bone and setup it's name - aiBone* pc = out->mBones[out->mNumBones++] = new aiBone(); - pc->mName = aiString( *( boneIt->second )); - - std::vector< BoneSrcIndex >::const_iterator wend = boneIt->pSrcBones.end(); - - // Loop through all bones to be joined for this bone - for (std::vector< BoneSrcIndex >::const_iterator wmit = boneIt->pSrcBones.begin(); wmit != wend; ++wmit) { - pc->mNumWeights += (*wmit).first->mNumWeights; - - // NOTE: different offset matrices for bones with equal names - // are - at the moment - not handled correctly. - if (wmit != boneIt->pSrcBones.begin() && pc->mOffsetMatrix != wmit->first->mOffsetMatrix) { - ASSIMP_LOG_WARN("Bones with equal names but different offset matrices can't be joined at the moment"); - continue; - } - pc->mOffsetMatrix = wmit->first->mOffsetMatrix; - } - - // Allocate the vertex weight array - aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - - // And copy the final weights - adjust the vertex IDs by the - // face index offset of the corresponding mesh. - for (std::vector< BoneSrcIndex >::const_iterator wmit = (*boneIt).pSrcBones.begin(); wmit != (*boneIt).pSrcBones.end(); ++wmit) { - if (wmit == wend) { - break; - } - - aiBone* pip = (*wmit).first; - for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) { - const aiVertexWeight& vfi = pip->mWeights[mp]; - avw->mWeight = vfi.mWeight; - avw->mVertexId = vfi.mVertexId + (*wmit).second; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Merge a list of meshes -void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/, - std::vector::const_iterator begin, - std::vector::const_iterator end) -{ - if ( nullptr == _out ) { - return; - } - - if (begin == end) { - *_out = NULL; // no meshes ... - return; - } - - // Allocate the output mesh - aiMesh* out = *_out = new aiMesh(); - out->mMaterialIndex = (*begin)->mMaterialIndex; - - std::string name; - // Find out how much output storage we'll need - for (std::vector::const_iterator it = begin; it != end; ++it) { - const char *meshName( (*it)->mName.C_Str() ); - name += std::string( meshName ); - if ( it != end - 1 ) { - name += "."; - } - out->mNumVertices += (*it)->mNumVertices; - out->mNumFaces += (*it)->mNumFaces; - out->mNumBones += (*it)->mNumBones; - - // combine primitive type flags - out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; - } - out->mName.Set( name.c_str() ); - - if (out->mNumVertices) { - aiVector3D* pv2; - - // copy vertex positions - if ((**begin).HasPositions()) { - - pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end; ++it) { - if ((*it)->mVertices) { - ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D)); - } - else ASSIMP_LOG_WARN("JoinMeshes: Positions expected but input mesh contains no positions"); - pv2 += (*it)->mNumVertices; - } - } - // copy normals - if ((**begin).HasNormals()) { - - pv2 = out->mNormals = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) { - if ((*it)->mNormals) { - ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: Normals expected but input mesh contains no normals" ); - } - pv2 += (*it)->mNumVertices; - } - } - // copy tangents and bi-tangents - if ((**begin).HasTangentsAndBitangents()) { - - pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; - aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices]; - - for (std::vector::const_iterator it = begin; it != end;++it) { - if ((*it)->mTangents) { - ::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D)); - ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: Tangents expected but input mesh contains no tangents" ); - } - pv2 += (*it)->mNumVertices; - pv2b += (*it)->mNumVertices; - } - } - // copy texture coordinates - unsigned int n = 0; - while ((**begin).HasTextureCoords(n)) { - out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n]; - - pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) { - if ((*it)->mTextureCoords[n]) { - ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: UVs expected but input mesh contains no UVs" ); - } - pv2 += (*it)->mNumVertices; - } - ++n; - } - // copy vertex colors - n = 0; - while ((**begin).HasVertexColors(n)) { - aiColor4D *pVec2 = out->mColors[n] = new aiColor4D[out->mNumVertices]; - for ( std::vector::const_iterator it = begin; it != end; ++it ) { - if ((*it)->mColors[n]) { - ::memcpy( pVec2, (*it)->mColors[ n ], (*it)->mNumVertices * sizeof( aiColor4D ) ) ; - } else { - ASSIMP_LOG_WARN( "JoinMeshes: VCs expected but input mesh contains no VCs" ); - } - pVec2 += (*it)->mNumVertices; - } - ++n; - } - } - - if (out->mNumFaces) // just for safety - { - // copy faces - out->mFaces = new aiFace[out->mNumFaces]; - aiFace* pf2 = out->mFaces; - - unsigned int ofs = 0; - for (std::vector::const_iterator it = begin; it != end;++it) { - for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) { - aiFace& face = (*it)->mFaces[m]; - pf2->mNumIndices = face.mNumIndices; - pf2->mIndices = face.mIndices; - - if (ofs) { - // add the offset to the vertex - for (unsigned int q = 0; q < face.mNumIndices; ++q) - face.mIndices[q] += ofs; - } - face.mIndices = NULL; - } - ofs += (*it)->mNumVertices; - } - } - - // bones - as this is quite lengthy, I moved the code to a separate function - if (out->mNumBones) - MergeBones(out,begin,end); - - // delete all source meshes - for (std::vector::const_iterator it = begin; it != end;++it) - delete *it; -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::MergeMaterials(aiMaterial** dest, - std::vector::const_iterator begin, - std::vector::const_iterator end) -{ - if ( nullptr == dest ) { - return; - } - - if (begin == end) { - *dest = NULL; // no materials ... - return; - } - - // Allocate the output material - aiMaterial* out = *dest = new aiMaterial(); - - // Get the maximal number of properties - unsigned int size = 0; - for (std::vector::const_iterator it = begin; it != end; ++it) { - size += (*it)->mNumProperties; - } - - out->Clear(); - delete[] out->mProperties; - - out->mNumAllocated = size; - out->mNumProperties = 0; - out->mProperties = new aiMaterialProperty*[out->mNumAllocated]; - - for (std::vector::const_iterator it = begin; it != end; ++it) { - for(unsigned int i = 0; i < (*it)->mNumProperties; ++i) { - aiMaterialProperty* sprop = (*it)->mProperties[i]; - - // Test if we already have a matching property - const aiMaterialProperty* prop_exist; - if(aiGetMaterialProperty(out, sprop->mKey.C_Str(), sprop->mSemantic, sprop->mIndex, &prop_exist) != AI_SUCCESS) { - // If not, we add it to the new material - aiMaterialProperty* prop = out->mProperties[out->mNumProperties] = new aiMaterialProperty(); - - prop->mDataLength = sprop->mDataLength; - prop->mData = new char[prop->mDataLength]; - ::memcpy(prop->mData, sprop->mData, prop->mDataLength); - - prop->mIndex = sprop->mIndex; - prop->mSemantic = sprop->mSemantic; - prop->mKey = sprop->mKey; - prop->mType = sprop->mType; - - out->mNumProperties++; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline -void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num) { - if (!num) { - dest = NULL; - return; - } - dest = new Type*[num]; - for (ai_uint i = 0; i < num;++i) { - SceneCombiner::Copy(&dest[i],src[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline -void GetArrayCopy(Type*& dest, ai_uint num ) { - if ( !dest ) { - return; - } - Type* old = dest; - - dest = new Type[num]; - ::memcpy(dest, old, sizeof(Type) * num); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - // reuse the old scene or allocate a new? - if (*_dest) { - (*_dest)->~aiScene(); - new (*_dest) aiScene(); - } else { - *_dest = new aiScene(); - } - - ::memcpy(*_dest,src,sizeof(aiScene)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - if (allocate) { - *_dest = new aiScene(); - } - aiScene* dest = *_dest; - ai_assert(nullptr != dest); - - // copy metadata - if ( nullptr != src->mMetaData ) { - dest->mMetaData = new aiMetadata( *src->mMetaData ); - } - - // copy animations - dest->mNumAnimations = src->mNumAnimations; - CopyPtrArray(dest->mAnimations,src->mAnimations, - dest->mNumAnimations); - - // copy textures - dest->mNumTextures = src->mNumTextures; - CopyPtrArray(dest->mTextures,src->mTextures, - dest->mNumTextures); - - // copy materials - dest->mNumMaterials = src->mNumMaterials; - CopyPtrArray(dest->mMaterials,src->mMaterials, - dest->mNumMaterials); - - // copy lights - dest->mNumLights = src->mNumLights; - CopyPtrArray(dest->mLights,src->mLights, - dest->mNumLights); - - // copy cameras - dest->mNumCameras = src->mNumCameras; - CopyPtrArray(dest->mCameras,src->mCameras, - dest->mNumCameras); - - // copy meshes - dest->mNumMeshes = src->mNumMeshes; - CopyPtrArray(dest->mMeshes,src->mMeshes, - dest->mNumMeshes); - - // now - copy the root node of the scene (deep copy, too) - Copy( &dest->mRootNode, src->mRootNode); - - // and keep the flags ... - dest->mFlags = src->mFlags; - - // source private data might be NULL if the scene is user-allocated (i.e. for use with the export API) - if (dest->mPrivate != NULL) { - ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMesh* dest = *_dest = new aiMesh(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiMesh)); - - // and reallocate all arrays - GetArrayCopy( dest->mVertices, dest->mNumVertices ); - GetArrayCopy( dest->mNormals , dest->mNumVertices ); - GetArrayCopy( dest->mTangents, dest->mNumVertices ); - GetArrayCopy( dest->mBitangents, dest->mNumVertices ); - - unsigned int n = 0; - while (dest->HasTextureCoords(n)) - GetArrayCopy( dest->mTextureCoords[n++], dest->mNumVertices ); - - n = 0; - while (dest->HasVertexColors(n)) - GetArrayCopy( dest->mColors[n++], dest->mNumVertices ); - - // make a deep copy of all bones - CopyPtrArray(dest->mBones,dest->mBones,dest->mNumBones); - - // make a deep copy of all faces - GetArrayCopy(dest->mFaces,dest->mNumFaces); - for (unsigned int i = 0; i < dest->mNumFaces;++i) { - aiFace& f = dest->mFaces[i]; - GetArrayCopy(f.mIndices,f.mNumIndices); - } - - // make a deep copy of all blend shapes - CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiAnimMesh** _dest, const aiAnimMesh* src) { - if (nullptr == _dest || nullptr == src) { - return; - } - - aiAnimMesh* dest = *_dest = new aiAnimMesh(); - - // get a flat copy - ::memcpy(dest, src, sizeof(aiAnimMesh)); - - // and reallocate all arrays - GetArrayCopy(dest->mVertices, dest->mNumVertices); - GetArrayCopy(dest->mNormals, dest->mNumVertices); - GetArrayCopy(dest->mTangents, dest->mNumVertices); - GetArrayCopy(dest->mBitangents, dest->mNumVertices); - - unsigned int n = 0; - while (dest->HasTextureCoords(n)) - GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices); - - n = 0; - while (dest->HasVertexColors(n)) - GetArrayCopy(dest->mColors[n++], dest->mNumVertices); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() ); - - dest->Clear(); - delete[] dest->mProperties; - - dest->mNumAllocated = src->mNumAllocated; - dest->mNumProperties = src->mNumProperties; - dest->mProperties = new aiMaterialProperty* [dest->mNumAllocated]; - - for (unsigned int i = 0; i < dest->mNumProperties;++i) - { - aiMaterialProperty* prop = dest->mProperties[i] = new aiMaterialProperty(); - aiMaterialProperty* sprop = src->mProperties[i]; - - prop->mDataLength = sprop->mDataLength; - prop->mData = new char[prop->mDataLength]; - ::memcpy(prop->mData,sprop->mData,prop->mDataLength); - - prop->mIndex = sprop->mIndex; - prop->mSemantic = sprop->mSemantic; - prop->mKey = sprop->mKey; - prop->mType = sprop->mType; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiTexture** _dest, const aiTexture* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiTexture* dest = *_dest = new aiTexture(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiTexture)); - - // and reallocate all arrays. We must do it manually here - const char* old = (const char*)dest->pcData; - if (old) - { - unsigned int cpy; - if (!dest->mHeight)cpy = dest->mWidth; - else cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel); - - if (!cpy) - { - dest->pcData = NULL; - return; - } - // the cast is legal, the aiTexel c'tor does nothing important - dest->pcData = (aiTexel*) new char[cpy]; - ::memcpy(dest->pcData, old, cpy); - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiAnimation* dest = *_dest = new aiAnimation(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiAnimation)); - - // and reallocate all arrays - CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); - CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels ); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiNodeAnim* dest = *_dest = new aiNodeAnim(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiNodeAnim)); - - // and reallocate all arrays - GetArrayCopy( dest->mPositionKeys, dest->mNumPositionKeys ); - GetArrayCopy( dest->mScalingKeys, dest->mNumScalingKeys ); - GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys ); -} - -void SceneCombiner::Copy(aiMeshMorphAnim** _dest, const aiMeshMorphAnim* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMeshMorphAnim* dest = *_dest = new aiMeshMorphAnim(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiMeshMorphAnim)); - - // and reallocate all arrays - GetArrayCopy( dest->mKeys, dest->mNumKeys ); - for (ai_uint i = 0; i < dest->mNumKeys;++i) { - dest->mKeys[i].mValues = new unsigned int[dest->mKeys[i].mNumValuesAndWeights]; - dest->mKeys[i].mWeights = new double[dest->mKeys[i].mNumValuesAndWeights]; - ::memcpy(dest->mKeys[i].mValues, src->mKeys[i].mValues, dest->mKeys[i].mNumValuesAndWeights * sizeof(unsigned int)); - ::memcpy(dest->mKeys[i].mWeights, src->mKeys[i].mWeights, dest->mKeys[i].mNumValuesAndWeights * sizeof(double)); - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiCamera* dest = *_dest = new aiCamera(); - - // get a flat copy, that's already OK - ::memcpy(dest,src,sizeof(aiCamera)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiLight** _dest, const aiLight* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiLight* dest = *_dest = new aiLight(); - - // get a flat copy, that's already OK - ::memcpy(dest,src,sizeof(aiLight)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiBone** _dest, const aiBone* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiBone* dest = *_dest = new aiBone(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiBone)); - - // and reallocate all arrays - GetArrayCopy( dest->mWeights, dest->mNumWeights ); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy (aiNode** _dest, const aiNode* src) -{ - ai_assert(NULL != _dest && NULL != src); - - aiNode* dest = *_dest = new aiNode(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiNode)); - - if (src->mMetaData) { - Copy(&dest->mMetaData, src->mMetaData); - } - - // and reallocate all arrays - GetArrayCopy( dest->mMeshes, dest->mNumMeshes ); - CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren); - - // need to set the mParent fields to the created aiNode. - for( unsigned int i = 0; i < dest->mNumChildren; i ++ ) { - dest->mChildren[i]->mParent = dest; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - if ( 0 == src->mNumProperties ) { - return; - } - - aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties ); - std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys); - - dest->mValues = new aiMetadataEntry[src->mNumProperties]; - for (unsigned int i = 0; i < src->mNumProperties; ++i) { - aiMetadataEntry& in = src->mValues[i]; - aiMetadataEntry& out = dest->mValues[i]; - out.mType = in.mType; - switch (dest->mValues[i].mType) { - case AI_BOOL: - out.mData = new bool(*static_cast(in.mData)); - break; - case AI_INT32: - out.mData = new int32_t(*static_cast(in.mData)); - break; - case AI_UINT64: - out.mData = new uint64_t(*static_cast(in.mData)); - break; - case AI_FLOAT: - out.mData = new float(*static_cast(in.mData)); - break; - case AI_DOUBLE: - out.mData = new double(*static_cast(in.mData)); - break; - case AI_AISTRING: - out.mData = new aiString(*static_cast(in.mData)); - break; - case AI_AIVECTOR3D: - out.mData = new aiVector3D(*static_cast(in.mData)); - break; - default: - ai_assert(false); - break; - } - } -} - -} // Namespace Assimp - diff --git a/thirdparty/assimp/code/Common/ScenePreprocessor.cpp b/thirdparty/assimp/code/Common/ScenePreprocessor.cpp deleted file mode 100644 index 432a3d766602..000000000000 --- a/thirdparty/assimp/code/Common/ScenePreprocessor.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#include "ScenePreprocessor.h" -#include -#include -#include - - -using namespace Assimp; - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessScene () -{ - ai_assert(scene != NULL); - - // Process all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) - ProcessMesh(scene->mMeshes[i]); - - // - nothing to do for nodes for the moment - // - nothing to do for textures for the moment - // - nothing to do for lights for the moment - // - nothing to do for cameras for the moment - - // Process all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) - ProcessAnimation(scene->mAnimations[i]); - - // Generate a default material if none was specified - if (!scene->mNumMaterials && scene->mNumMeshes) { - scene->mMaterials = new aiMaterial*[2]; - aiMaterial* helper; - - aiString name; - - scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial(); - aiColor3D clr(0.6f,0.6f,0.6f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); - - // setup the default name to make this material identifiable - name.Set(AI_DEFAULT_MATERIAL_NAME); - helper->AddProperty(&name,AI_MATKEY_NAME); - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); - - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials; - } - - scene->mNumMaterials++; - } -} - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessMesh (aiMesh* mesh) -{ - // If aiMesh::mNumUVComponents is *not* set assign the default value of 2 - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (!mesh->mTextureCoords[i]) { - mesh->mNumUVComponents[i] = 0; - } else { - if (!mesh->mNumUVComponents[i]) - mesh->mNumUVComponents[i] = 2; - - aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices; - - // Ensure unused components are zeroed. This will make 1D texture channels work - // as if they were 2D channels .. just in case an application doesn't handle - // this case - if (2 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) - p->z = 0.f; - } - else if (1 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) - p->z = p->y = 0.f; - } - else if (3 == mesh->mNumUVComponents[i]) { - // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element - for (; p != end; ++p) { - if (p->z != 0) - break; - } - if (p == end) { - ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D."); - mesh->mNumUVComponents[i] = 2; - } - } - } - } - - // If the information which primitive types are there in the - // mesh is currently not available, compute it. - if (!mesh->mPrimitiveTypes) { - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { - aiFace& face = mesh->mFaces[a]; - switch (face.mNumIndices) - { - case 3u: - mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - - case 2u: - mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - - case 1u: - mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - - default: - mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - } - } - - // If tangents and normals are given but no bitangents compute them - if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { - - mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; - for (unsigned int i = 0; i < mesh->mNumVertices;++i) { - mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; - } - } -} - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) -{ - double first = 10e10, last = -10e10; - for (unsigned int i = 0; i < anim->mNumChannels;++i) { - aiNodeAnim* channel = anim->mChannels[i]; - - /* If the exact duration of the animation is not given - * compute it now. - */ - if (anim->mDuration == -1.) { - - // Position keys - for (unsigned int j = 0; j < channel->mNumPositionKeys;++j) { - aiVectorKey& key = channel->mPositionKeys[j]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - - // Scaling keys - for (unsigned int j = 0; j < channel->mNumScalingKeys;++j ) { - aiVectorKey& key = channel->mScalingKeys[j]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - - // Rotation keys - for (unsigned int j = 0; j < channel->mNumRotationKeys;++j ) { - aiQuatKey& key = channel->mRotationKeys[ j ]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - } - - /* Check whether the animation channel has no rotation - * or position tracks. In this case we generate a dummy - * track from the information we have in the transformation - * matrix of the corresponding node. - */ - if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { - // Find the node that belongs to this animation - aiNode* node = scene->mRootNode->FindNode(channel->mNodeName); - if (node) // ValidateDS will complain later if 'node' is NULL - { - // Decompose the transformation matrix of the node - aiVector3D scaling, position; - aiQuaternion rotation; - - node->mTransformation.Decompose(scaling, rotation,position); - - // No rotation keys? Generate a dummy track - if (!channel->mNumRotationKeys) { - channel->mNumRotationKeys = 1; - channel->mRotationKeys = new aiQuatKey[1]; - aiQuatKey& q = channel->mRotationKeys[0]; - - q.mTime = 0.; - q.mValue = rotation; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy rotation track has been generated"); - } - - // No scaling keys? Generate a dummy track - if (!channel->mNumScalingKeys) { - channel->mNumScalingKeys = 1; - channel->mScalingKeys = new aiVectorKey[1]; - aiVectorKey& q = channel->mScalingKeys[0]; - - q.mTime = 0.; - q.mValue = scaling; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy scaling track has been generated"); - } - - // No position keys? Generate a dummy track - if (!channel->mNumPositionKeys) { - channel->mNumPositionKeys = 1; - channel->mPositionKeys = new aiVectorKey[1]; - aiVectorKey& q = channel->mPositionKeys[0]; - - q.mTime = 0.; - q.mValue = position; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy position track has been generated"); - } - } - } - } - - if (anim->mDuration == -1.) { - ASSIMP_LOG_DEBUG("ScenePreprocessor: Setting animation duration"); - anim->mDuration = last - std::min( first, 0. ); - } -} diff --git a/thirdparty/assimp/code/Common/ScenePreprocessor.h b/thirdparty/assimp/code/Common/ScenePreprocessor.h deleted file mode 100644 index 3f4c8d7c3f6f..000000000000 --- a/thirdparty/assimp/code/Common/ScenePreprocessor.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -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 Defines a post processing step to search all meshes for - degenerated faces */ -#ifndef AI_SCENE_PREPROCESSOR_H_INC -#define AI_SCENE_PREPROCESSOR_H_INC - -#include -#include - -struct aiScene; -struct aiAnimation; -struct aiMesh; - -class ScenePreprocessorTest; -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** ScenePreprocessor: Preprocess a scene before any post-processing - * steps are executed. - * - * The step computes data that needn't necessarily be provided by the - * importer, such as aiMesh::mPrimitiveTypes. -*/ -// ---------------------------------------------------------------------------------- -class ASSIMP_API ScenePreprocessor -{ - // Make ourselves a friend of the corresponding test unit. - friend class ::ScenePreprocessorTest; -public: - - // ---------------------------------------------------------------- - /** Default c'tpr. Use SetScene() to assign a scene to the object. - */ - ScenePreprocessor() - : scene (NULL) - {} - - /** Constructs the object and assigns a specific scene to it - */ - ScenePreprocessor(aiScene* _scene) - : scene (_scene) - {} - - // ---------------------------------------------------------------- - /** Assign a (new) scene to the object. - * - * One 'SceneProcessor' can be used for multiple scenes. - * Call ProcessScene to have the scene preprocessed. - * @param sc Scene to be processed. - */ - void SetScene (aiScene* sc) { - scene = sc; - } - - // ---------------------------------------------------------------- - /** Preprocess the current scene - */ - void ProcessScene (); - -protected: - - // ---------------------------------------------------------------- - /** Preprocess an animation in the scene - * @param anim Anim to be preprocessed. - */ - void ProcessAnimation (aiAnimation* anim); - - - // ---------------------------------------------------------------- - /** Preprocess a mesh in the scene - * @param mesh Mesh to be preprocessed. - */ - void ProcessMesh (aiMesh* mesh); - -protected: - - //! Scene we're currently working on - aiScene* scene; -}; - - -} // ! end namespace Assimp - -#endif // include guard diff --git a/thirdparty/assimp/code/Common/ScenePrivate.h b/thirdparty/assimp/code/Common/ScenePrivate.h deleted file mode 100644 index f336aafc9a53..000000000000 --- a/thirdparty/assimp/code/Common/ScenePrivate.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -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 Stuff to deal with aiScene::mPrivate - */ -#pragma once -#ifndef AI_SCENEPRIVATE_H_INCLUDED -#define AI_SCENEPRIVATE_H_INCLUDED - -#include -#include - -namespace Assimp { - -// Forward declarations -class Importer; - -struct ScenePrivateData { - // The struct constructor. - ScenePrivateData() AI_NO_EXCEPT; - - // Importer that originally loaded the scene though the C-API - // If set, this object is owned by this private data instance. - Assimp::Importer* mOrigImporter; - - // List of post-processing steps already applied to the scene. - unsigned int mPPStepsApplied; - - // true if the scene is a copy made with aiCopyScene() - // or the corresponding C++ API. This means that user code - // may have made modifications to it, so mPPStepsApplied - // and mOrigImporter are no longer safe to rely on and only - // serve informative purposes. - bool mIsCopy; -}; - -inline -ScenePrivateData::ScenePrivateData() AI_NO_EXCEPT -: mOrigImporter( nullptr ) -, mPPStepsApplied( 0 ) -, mIsCopy( false ) { - // empty -} - -// Access private data stored in the scene -inline -ScenePrivateData* ScenePriv(aiScene* in) { - ai_assert( nullptr != in ); - if ( nullptr == in ) { - return nullptr; - } - return static_cast(in->mPrivate); -} - -inline -const ScenePrivateData* ScenePriv(const aiScene* in) { - ai_assert( nullptr != in ); - if ( nullptr == in ) { - return nullptr; - } - return static_cast(in->mPrivate); -} - -} // Namespace Assimp - -#endif // AI_SCENEPRIVATE_H_INCLUDED diff --git a/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp b/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp deleted file mode 100644 index 06cfe034e965..000000000000 --- a/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* -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 SkeletonMeshBuilder.cpp - * @brief Implementation of a little class to construct a dummy mesh for a skeleton - */ - -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// The constructor processes the given scene and adds a mesh there. -SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly) -{ - // nothing to do if there's mesh data already present at the scene - if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL) - return; - - if (!root) - root = pScene->mRootNode; - - mKnobsOnly = bKnobsOnly; - - // build some faces around each node - CreateGeometry( root ); - - // create a mesh to hold all the generated faces - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh*[1]; - pScene->mMeshes[0] = CreateMesh(); - // and install it at the root node - root->mNumMeshes = 1; - root->mMeshes = new unsigned int[1]; - root->mMeshes[0] = 0; - - // create a dummy material for the mesh - if(pScene->mNumMaterials==0){ - pScene->mNumMaterials = 1; - pScene->mMaterials = new aiMaterial*[1]; - pScene->mMaterials[0] = CreateMaterial(); - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively builds a simple mesh representation for the given node -void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) -{ - // add a joint entry for the node. - const unsigned int vertexStartIndex = static_cast(mVertices.size()); - - // now build the geometry. - if( pNode->mNumChildren > 0 && !mKnobsOnly) - { - // If the node has children, we build little pointers to each of them - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - { - // find a suitable coordinate system - const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation; - aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4); - ai_real distanceToChild = childpos.Length(); - if( distanceToChild < 0.0001) - continue; - aiVector3D up = aiVector3D( childpos).Normalize(); - - aiVector3D orth( 1.0, 0.0, 0.0); - if( std::fabs( orth * up) > 0.99) - orth.Set( 0.0, 1.0, 0.0); - - aiVector3D front = (up ^ orth).Normalize(); - aiVector3D side = (front ^ up).Normalize(); - - unsigned int localVertexStart = static_cast(mVertices.size()); - mVertices.push_back( -front * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( -side * distanceToChild * (ai_real)0.1); - mVertices.push_back( -side * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( front * distanceToChild * (ai_real)0.1); - mVertices.push_back( front * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( side * distanceToChild * (ai_real)0.1); - mVertices.push_back( side * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( -front * distanceToChild * (ai_real)0.1); - - mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2)); - mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5)); - mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8)); - mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11)); - } - } - else - { - // if the node has no children, it's an end node. Put a little knob there instead - aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4); - ai_real sizeEstimate = ownpos.Length() * ai_real( 0.18 ); - - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - - mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2)); - mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5)); - mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8)); - mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11)); - mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14)); - mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17)); - mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20)); - mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23)); - } - - unsigned int numVertices = static_cast(mVertices.size() - vertexStartIndex); - if( numVertices > 0) - { - // create a bone affecting all the newly created vertices - aiBone* bone = new aiBone; - mBones.push_back( bone); - bone->mName = pNode->mName; - - // calculate the bone offset matrix by concatenating the inverse transformations of all parents - bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse(); - for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent) - bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix; - - // add all the vertices to the bone's influences - bone->mNumWeights = numVertices; - bone->mWeights = new aiVertexWeight[numVertices]; - for( unsigned int a = 0; a < numVertices; a++) - bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0); - - // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding - // them to the array, but I'm tired now and I'm annoyed. - aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse(); - for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++) - mVertices[a] = boneToMeshTransform * mVertices[a]; - } - - // and finally recurse into the children list - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - CreateGeometry( pNode->mChildren[a]); -} - -// ------------------------------------------------------------------------------------------------ -// Creates the mesh from the internally accumulated stuff and returns it. -aiMesh* SkeletonMeshBuilder::CreateMesh() -{ - aiMesh* mesh = new aiMesh(); - - // add points - mesh->mNumVertices = static_cast(mVertices.size()); - mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices); - - mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - - // add faces - mesh->mNumFaces = static_cast(mFaces.size()); - mesh->mFaces = new aiFace[mesh->mNumFaces]; - for( unsigned int a = 0; a < mesh->mNumFaces; a++) - { - const Face& inface = mFaces[a]; - aiFace& outface = mesh->mFaces[a]; - outface.mNumIndices = 3; - outface.mIndices = new unsigned int[3]; - outface.mIndices[0] = inface.mIndices[0]; - outface.mIndices[1] = inface.mIndices[1]; - outface.mIndices[2] = inface.mIndices[2]; - - // Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize - // the skeleton, so it's good if there's a visual difference to the rest of the geometry - aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^ - (mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]])); - - if (nor.Length() < 1e-5) /* ensure that FindInvalidData won't remove us ...*/ - nor = aiVector3D(1.0,0.0,0.0); - - for (unsigned int n = 0; n < 3; ++n) - mesh->mNormals[inface.mIndices[n]] = nor; - } - - // add the bones - mesh->mNumBones = static_cast(mBones.size()); - mesh->mBones = new aiBone*[mesh->mNumBones]; - std::copy( mBones.begin(), mBones.end(), mesh->mBones); - - // default - mesh->mMaterialIndex = 0; - - return mesh; -} - -// ------------------------------------------------------------------------------------------------ -// Creates a dummy material and returns it. -aiMaterial* SkeletonMeshBuilder::CreateMaterial() -{ - aiMaterial* matHelper = new aiMaterial; - - // Name - aiString matName( std::string( "SkeletonMaterial")); - matHelper->AddProperty( &matName, AI_MATKEY_NAME); - - // Prevent backface culling - const int no_cull = 1; - matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED); - - return matHelper; -} diff --git a/thirdparty/assimp/code/Common/SpatialSort.cpp b/thirdparty/assimp/code/Common/SpatialSort.cpp deleted file mode 100644 index a4f3a4e4b851..000000000000 --- a/thirdparty/assimp/code/Common/SpatialSort.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the helper class to quickly find vertices close to a given position */ - -#include -#include - -using namespace Assimp; - -// CHAR_BIT seems to be defined under MVSC, but not under GCC. Pray that the correct value is 8. -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -// ------------------------------------------------------------------------------------------------ -// Constructs a spatially sorted representation from the given position array. -SpatialSort::SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset) - - // define the reference plane. We choose some arbitrary vector away from all basic axises - // in the hope that no model spreads all its vertices along this plane. - : mPlaneNormal(0.8523f, 0.34321f, 0.5736f) -{ - mPlaneNormal.Normalize(); - Fill(pPositions,pNumPositions,pElementOffset); -} - -// ------------------------------------------------------------------------------------------------ -SpatialSort :: SpatialSort() -: mPlaneNormal(0.8523f, 0.34321f, 0.5736f) -{ - mPlaneNormal.Normalize(); -} - -// ------------------------------------------------------------------------------------------------ -// Destructor -SpatialSort::~SpatialSort() -{ - // nothing to do here, everything destructs automatically -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize /*= true */) -{ - mPositions.clear(); - Append(pPositions,pNumPositions,pElementOffset,pFinalize); -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort :: Finalize() -{ - std::sort( mPositions.begin(), mPositions.end()); -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort::Append( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize /*= true */) -{ - // store references to all given positions along with their distance to the reference plane - const size_t initial = mPositions.size(); - mPositions.reserve(initial + (pFinalize?pNumPositions:pNumPositions*2)); - for( unsigned int a = 0; a < pNumPositions; a++) - { - const char* tempPointer = reinterpret_cast (pPositions); - const aiVector3D* vec = reinterpret_cast (tempPointer + a * pElementOffset); - - // store position by index and distance - ai_real distance = *vec * mPlaneNormal; - mPositions.push_back( Entry( static_cast(a+initial), *vec, distance)); - } - - if (pFinalize) { - // now sort the array ascending by distance. - Finalize(); - } -} - -// ------------------------------------------------------------------------------------------------ -// Returns an iterator for all positions close to the given position. -void SpatialSort::FindPositions( const aiVector3D& pPosition, - ai_real pRadius, std::vector& poResults) const -{ - const ai_real dist = pPosition * mPlaneNormal; - const ai_real minDist = dist - pRadius, maxDist = dist + pRadius; - - // clear the array - poResults.clear(); - - // quick check for positions outside the range - if( mPositions.size() == 0) - return; - if( maxDist < mPositions.front().mDistance) - return; - if( minDist > mPositions.back().mDistance) - return; - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - if( mPositions[index].mDistance < minDist) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && mPositions[index].mDistance > minDist) - index--; - while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist) - index++; - - // Mow start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the given radius to the result aray - std::vector::const_iterator it = mPositions.begin() + index; - const ai_real pSquared = pRadius*pRadius; - while( it->mDistance < maxDist) - { - if( (it->mPosition - pPosition).SquareLength() < pSquared) - poResults.push_back( it->mIndex); - ++it; - if( it == mPositions.end()) - break; - } - - // that's it -} - -namespace { - - // Binary, signed-integer representation of a single-precision floating-point value. - // IEEE 754 says: "If two floating-point numbers in the same format are ordered then they are - // ordered the same way when their bits are reinterpreted as sign-magnitude integers." - // This allows us to convert all floating-point numbers to signed integers of arbitrary size - // and then use them to work with ULPs (Units in the Last Place, for high-precision - // computations) or to compare them (integer comparisons are faster than floating-point - // comparisons on many platforms). - typedef ai_int BinFloat; - - // -------------------------------------------------------------------------------------------- - // Converts the bit pattern of a floating-point number to its signed integer representation. - BinFloat ToBinary( const ai_real & pValue) { - - // If this assertion fails, signed int is not big enough to store a float on your platform. - // Please correct the declaration of BinFloat a few lines above - but do it in a portable, - // #ifdef'd manner! - static_assert( sizeof(BinFloat) >= sizeof(ai_real), "sizeof(BinFloat) >= sizeof(ai_real)"); - - #if defined( _MSC_VER) - // If this assertion fails, Visual C++ has finally moved to ILP64. This means that this - // code has just become legacy code! Find out the current value of _MSC_VER and modify - // the #if above so it evaluates false on the current and all upcoming VC versions (or - // on the current platform, if LP64 or LLP64 are still used on other platforms). - static_assert( sizeof(BinFloat) == sizeof(ai_real), "sizeof(BinFloat) == sizeof(ai_real)"); - - // This works best on Visual C++, but other compilers have their problems with it. - const BinFloat binValue = reinterpret_cast(pValue); - #else - // On many compilers, reinterpreting a float address as an integer causes aliasing - // problems. This is an ugly but more or less safe way of doing it. - union { - ai_real asFloat; - BinFloat asBin; - } conversion; - conversion.asBin = 0; // zero empty space in case sizeof(BinFloat) > sizeof(float) - conversion.asFloat = pValue; - const BinFloat binValue = conversion.asBin; - #endif - - // floating-point numbers are of sign-magnitude format, so find out what signed number - // representation we must convert negative values to. - // See http://en.wikipedia.org/wiki/Signed_number_representations. - - // Two's complement? - if( (-42 == (~42 + 1)) && (binValue & 0x80000000)) - return BinFloat(1 << (CHAR_BIT * sizeof(BinFloat) - 1)) - binValue; - // One's complement? - else if ( (-42 == ~42) && (binValue & 0x80000000)) - return BinFloat(-0) - binValue; - // Sign-magnitude? - else if( (-42 == (42 | (-0))) && (binValue & 0x80000000)) // -0 = 1000... binary - return binValue; - else - return binValue; - } - -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Fills an array with indices of all positions identical to the given position. In opposite to -// FindPositions(), not an epsilon is used but a (very low) tolerance of four floating-point units. -void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition, - std::vector& poResults) const -{ - // Epsilons have a huge disadvantage: they are of constant precision, while floating-point - // values are of log2 precision. If you apply e=0.01 to 100, the epsilon is rather small, but - // if you apply it to 0.001, it is enormous. - - // The best way to overcome this is the unit in the last place (ULP). A precision of 2 ULPs - // tells us that a float does not differ more than 2 bits from the "real" value. ULPs are of - // logarithmic precision - around 1, they are 1*(2^24) and around 10000, they are 0.00125. - - // For standard C math, we can assume a precision of 0.5 ULPs according to IEEE 754. The - // incoming vertex positions might have already been transformed, probably using rather - // inaccurate SSE instructions, so we assume a tolerance of 4 ULPs to safely identify - // identical vertex positions. - static const int toleranceInULPs = 4; - // An interesting point is that the inaccuracy grows linear with the number of operations: - // multiplying to numbers, each inaccurate to four ULPs, results in an inaccuracy of four ULPs - // plus 0.5 ULPs for the multiplication. - // To compute the distance to the plane, a dot product is needed - that is a multiplication and - // an addition on each number. - static const int distanceToleranceInULPs = toleranceInULPs + 1; - // The squared distance between two 3D vectors is computed the same way, but with an additional - // subtraction. - static const int distance3DToleranceInULPs = distanceToleranceInULPs + 1; - - // Convert the plane distance to its signed integer representation so the ULPs tolerance can be - // applied. For some reason, VC won't optimize two calls of the bit pattern conversion. - const BinFloat minDistBinary = ToBinary( pPosition * mPlaneNormal) - distanceToleranceInULPs; - const BinFloat maxDistBinary = minDistBinary + 2 * distanceToleranceInULPs; - - // clear the array in this strange fashion because a simple clear() would also deallocate - // the array which we want to avoid - poResults.resize( 0 ); - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - // Ugly, but conditional jumps are faster with integers than with floats - if( minDistBinary > ToBinary(mPositions[index].mDistance)) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && minDistBinary < ToBinary(mPositions[index].mDistance) ) - index--; - while( index < (mPositions.size() - 1) && minDistBinary > ToBinary(mPositions[index].mDistance)) - index++; - - // Now start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the tolerance to the result array - std::vector::const_iterator it = mPositions.begin() + index; - while( ToBinary(it->mDistance) < maxDistBinary) - { - if( distance3DToleranceInULPs >= ToBinary((it->mPosition - pPosition).SquareLength())) - poResults.push_back(it->mIndex); - ++it; - if( it == mPositions.end()) - break; - } - - // that's it -} - -// ------------------------------------------------------------------------------------------------ -unsigned int SpatialSort::GenerateMappingTable(std::vector& fill, ai_real pRadius) const -{ - fill.resize(mPositions.size(),UINT_MAX); - ai_real dist, maxDist; - - unsigned int t=0; - const ai_real pSquared = pRadius*pRadius; - for (size_t i = 0; i < mPositions.size();) { - dist = mPositions[i].mPosition * mPlaneNormal; - maxDist = dist + pRadius; - - fill[mPositions[i].mIndex] = t; - const aiVector3D& oldpos = mPositions[i].mPosition; - for (++i; i < fill.size() && mPositions[i].mDistance < maxDist - && (mPositions[i].mPosition - oldpos).SquareLength() < pSquared; ++i) - { - fill[mPositions[i].mIndex] = t; - } - ++t; - } - -#ifdef ASSIMP_BUILD_DEBUG - - // debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1 - for (size_t i = 0; i < fill.size(); ++i) { - ai_assert(fill[i] -#include - -#include -#include - -using namespace Assimp; -using namespace Assimp::Formatter; - -// ------------------------------------------------------------------------------------------------ -// Constructor -SplitByBoneCountProcess::SplitByBoneCountProcess() -{ - // set default, might be overridden by importer config - mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor -SplitByBoneCountProcess::~SplitByBoneCountProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag. -bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const -{ - return !!(pFlags & aiProcess_SplitByBoneCount); -} - -// ------------------------------------------------------------------------------------------------ -// Updates internal properties -void SplitByBoneCountProcess::SetupProperties(const Importer* pImp) -{ - mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitByBoneCountProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin"); - - // early out - bool isNecessary = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) - isNecessary = true; - - if( !isNecessary ) - { - ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess early-out: no meshes with more than " << mMaxBoneCount << " bones." ); - return; - } - - // we need to do something. Let's go. - mSubMeshIndices.clear(); - mSubMeshIndices.resize( pScene->mNumMeshes); - - // build a new array of meshes for the scene - std::vector meshes; - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - { - aiMesh* srcMesh = pScene->mMeshes[a]; - - std::vector newMeshes; - SplitMesh( pScene->mMeshes[a], newMeshes); - - // mesh was split - if( !newMeshes.empty() ) - { - // store new meshes and indices of the new meshes - for( unsigned int b = 0; b < newMeshes.size(); ++b) - { - mSubMeshIndices[a].push_back( static_cast(meshes.size())); - meshes.push_back( newMeshes[b]); - } - - // and destroy the source mesh. It should be completely contained inside the new submeshes - delete srcMesh; - } - else - { - // Mesh is kept unchanged - store it's new place in the mesh array - mSubMeshIndices[a].push_back( static_cast(meshes.size())); - meshes.push_back( srcMesh); - } - } - - // rebuild the scene's mesh array - pScene->mNumMeshes = static_cast(meshes.size()); - delete [] pScene->mMeshes; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - std::copy( meshes.begin(), meshes.end(), pScene->mMeshes); - - // recurse through all nodes and translate the node's mesh indices to fit the new mesh array - UpdateNode( pScene->mRootNode); - - ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess end: split " << mSubMeshIndices.size() << " meshes into " << meshes.size() << " submeshes." ); -} - -// ------------------------------------------------------------------------------------------------ -// Splits the given mesh by bone count. -void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector& poNewMeshes) const -{ - // skip if not necessary - if( pMesh->mNumBones <= mMaxBoneCount ) - return; - - // necessary optimisation: build a list of all affecting bones for each vertex - // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays - typedef std::pair BoneWeight; - std::vector< std::vector > vertexBones( pMesh->mNumVertices); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a) - { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; ++b) - vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight)); - } - - unsigned int numFacesHandled = 0; - std::vector isFaceHandled( pMesh->mNumFaces, false); - while( numFacesHandled < pMesh->mNumFaces ) - { - // which bones are used in the current submesh - unsigned int numBones = 0; - std::vector isBoneUsed( pMesh->mNumBones, false); - // indices of the faces which are going to go into this submesh - std::vector subMeshFaces; - subMeshFaces.reserve( pMesh->mNumFaces); - // accumulated vertex count of all the faces in this submesh - unsigned int numSubMeshVertices = 0; - // a small local array of new bones for the current face. State of all used bones for that face - // can only be updated AFTER the face is completely analysed. Thanks to imre for the fix. - std::vector newBonesAtCurrentFace; - - // add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit - for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) - { - // skip if the face is already stored in a submesh - if( isFaceHandled[a] ) - continue; - - const aiFace& face = pMesh->mFaces[a]; - // check every vertex if its bones would still fit into the current submesh - for( unsigned int b = 0; b < face.mNumIndices; ++b ) - { - const std::vector& vb = vertexBones[face.mIndices[b]]; - for( unsigned int c = 0; c < vb.size(); ++c) - { - unsigned int boneIndex = vb[c].first; - // if the bone is already used in this submesh, it's ok - if( isBoneUsed[boneIndex] ) - continue; - - // if it's not used, yet, we would need to add it. Store its bone index - if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() ) - newBonesAtCurrentFace.push_back( boneIndex); - } - } - - // leave out the face if the new bones required for this face don't fit the bone count limit anymore - if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) - continue; - - // mark all new bones as necessary - while( !newBonesAtCurrentFace.empty() ) - { - unsigned int newIndex = newBonesAtCurrentFace.back(); - newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear() - if( isBoneUsed[newIndex] ) - continue; - - isBoneUsed[newIndex] = true; - numBones++; - } - - // store the face index and the vertex count - subMeshFaces.push_back( a); - numSubMeshVertices += face.mNumIndices; - - // remember that this face is handled - isFaceHandled[a] = true; - numFacesHandled++; - } - - // create a new mesh to hold this subset of the source mesh - aiMesh* newMesh = new aiMesh; - if( pMesh->mName.length > 0 ) - newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size()); - newMesh->mMaterialIndex = pMesh->mMaterialIndex; - newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; - poNewMeshes.push_back( newMesh); - - // create all the arrays for this mesh if the old mesh contained them - newMesh->mNumVertices = numSubMeshVertices; - newMesh->mNumFaces = static_cast(subMeshFaces.size()); - newMesh->mVertices = new aiVector3D[newMesh->mNumVertices]; - if( pMesh->HasNormals() ) - newMesh->mNormals = new aiVector3D[newMesh->mNumVertices]; - if( pMesh->HasTangentsAndBitangents() ) - { - newMesh->mTangents = new aiVector3D[newMesh->mNumVertices]; - newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices]; - } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( pMesh->HasTextureCoords( a) ) - newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices]; - newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; - } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) - { - if( pMesh->HasVertexColors( a) ) - newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices]; - } - - // and copy over the data, generating faces with linear indices along the way - newMesh->mFaces = new aiFace[subMeshFaces.size()]; - unsigned int nvi = 0; // next vertex index - std::vector previousVertexIndices( numSubMeshVertices, std::numeric_limits::max()); // per new vertex: its index in the source mesh - for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) - { - const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; - aiFace& dstFace = newMesh->mFaces[a]; - dstFace.mNumIndices = srcFace.mNumIndices; - dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; - - // accumulate linearly all the vertices of the source face - for( unsigned int b = 0; b < dstFace.mNumIndices; ++b ) - { - unsigned int srcIndex = srcFace.mIndices[b]; - dstFace.mIndices[b] = nvi; - previousVertexIndices[nvi] = srcIndex; - - newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; - if( pMesh->HasNormals() ) - newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; - if( pMesh->HasTangentsAndBitangents() ) - { - newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; - newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; - } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) - { - if( pMesh->HasTextureCoords( c) ) - newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; - } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) - { - if( pMesh->HasVertexColors( c) ) - newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; - } - - nvi++; - } - } - - ai_assert( nvi == numSubMeshVertices ); - - // Create the bones for the new submesh: first create the bone array - newMesh->mNumBones = 0; - newMesh->mBones = new aiBone*[numBones]; - - std::vector mappedBoneIndex( pMesh->mNumBones, std::numeric_limits::max()); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) - { - if( !isBoneUsed[a] ) - continue; - - // create the new bone - const aiBone* srcBone = pMesh->mBones[a]; - aiBone* dstBone = new aiBone; - mappedBoneIndex[a] = newMesh->mNumBones; - newMesh->mBones[newMesh->mNumBones++] = dstBone; - dstBone->mName = srcBone->mName; - dstBone->mOffsetMatrix = srcBone->mOffsetMatrix; - dstBone->mNumWeights = 0; - } - - ai_assert( newMesh->mNumBones == numBones ); - - // iterate over all new vertices and count which bones affected its old vertex in the source mesh - for( unsigned int a = 0; a < numSubMeshVertices; ++a ) - { - unsigned int oldIndex = previousVertexIndices[a]; - const std::vector& bonesOnThisVertex = vertexBones[oldIndex]; - - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b ) - { - unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; - if( newBoneIndex != std::numeric_limits::max() ) - newMesh->mBones[newBoneIndex]->mNumWeights++; - } - } - - // allocate all bone weight arrays accordingly - for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) - { - aiBone* bone = newMesh->mBones[a]; - ai_assert( bone->mNumWeights > 0 ); - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - bone->mNumWeights = 0; // for counting up in the next step - } - - // now copy all the bone vertex weights for all the vertices which made it into the new submesh - for( unsigned int a = 0; a < numSubMeshVertices; ++a) - { - // find the source vertex for it in the source mesh - unsigned int previousIndex = previousVertexIndices[a]; - // these bones were affecting it - const std::vector& bonesOnThisVertex = vertexBones[previousIndex]; - // all of the bones affecting it should be present in the new submesh, or else - // the face it comprises shouldn't be present - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b) - { - unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; - ai_assert( newBoneIndex != std::numeric_limits::max() ); - aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights; - newMesh->mBones[newBoneIndex]->mNumWeights++; - - dstWeight->mVertexId = a; - dstWeight->mWeight = bonesOnThisVertex[b].second; - } - } - - // I have the strange feeling that this will break apart at some point in time... - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively updates the node's mesh list to account for the changed mesh list -void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const -{ - // rebuild the node's mesh index list - if( pNode->mNumMeshes > 0 ) - { - std::vector newMeshList; - for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) - { - unsigned int srcIndex = pNode->mMeshes[a]; - const std::vector& replaceMeshes = mSubMeshIndices[srcIndex]; - newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); - } - - delete [] pNode->mMeshes; - pNode->mNumMeshes = static_cast(newMeshList.size()); - pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; - std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes); - } - - // do that also recursively for all children - for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) - { - UpdateNode( pNode->mChildren[a]); - } -} diff --git a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h b/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h deleted file mode 100644 index 6c904a9df48a..000000000000 --- a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -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 SplitByBoneCountProcess.h -/// Defines a post processing step to split meshes with many bones into submeshes -#ifndef AI_SPLITBYBONECOUNTPROCESS_H_INC -#define AI_SPLITBYBONECOUNTPROCESS_H_INC - -#include -#include "BaseProcess.h" - -#include -#include - -namespace Assimp -{ - - -/** Postprocessing filter to split meshes with many bones into submeshes - * so that each submesh has a certain max bone count. - * - * Applied BEFORE the JoinVertices-Step occurs. - * Returns NON-UNIQUE vertices, splits by bone count. -*/ -class SplitByBoneCountProcess : public BaseProcess -{ -public: - - SplitByBoneCountProcess(); - ~SplitByBoneCountProcess(); - -public: - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - -protected: - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - /// Splits the given mesh by bone count. - /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. - /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary. - void SplitMesh( const aiMesh* pMesh, std::vector& poNewMeshes) const; - - /// Recursively updates the node's mesh list to account for the changed mesh list - void UpdateNode( aiNode* pNode) const; - -public: - /// Max bone count. Splitting occurs if a mesh has more than that number of bones. - size_t mMaxBoneCount; - - /// Per mesh index: Array of indices of the new submeshes. - std::vector< std::vector > mSubMeshIndices; -}; - -} // end of namespace Assimp - -#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC diff --git a/thirdparty/assimp/code/Common/StandardShapes.cpp b/thirdparty/assimp/code/Common/StandardShapes.cpp deleted file mode 100644 index 2e5100130f0f..000000000000 --- a/thirdparty/assimp/code/Common/StandardShapes.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/* -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 StandardShapes.cpp - * @brief Implementation of the StandardShapes class - * - * The primitive geometry data comes from - * http://geometrictools.com/Documentation/PlatonicSolids.pdf. - */ - -#include -#include -#include -#include -#include - -namespace Assimp { - - -# define ADD_TRIANGLE(n0,n1,n2) \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); - -# define ADD_PENTAGON(n0,n1,n2,n3,n4) \ - if (polygons) \ - { \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); \ - positions.push_back(n3); \ - positions.push_back(n4); \ - } \ - else \ - { \ - ADD_TRIANGLE(n0, n1, n2) \ - ADD_TRIANGLE(n0, n2, n3) \ - ADD_TRIANGLE(n0, n3, n4) \ - } - -# define ADD_QUAD(n0,n1,n2,n3) \ - if (polygons) \ - { \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); \ - positions.push_back(n3); \ - } \ - else \ - { \ - ADD_TRIANGLE(n0, n1, n2) \ - ADD_TRIANGLE(n0, n2, n3) \ - } - - -// ------------------------------------------------------------------------------------------------ -// Fast subdivision for a mesh whose verts have a magnitude of 1 -void Subdivide(std::vector& positions) -{ - // assume this to be constant - (fixme: must be 1.0? I think so) - const ai_real fl1 = positions[0].Length(); - - unsigned int origSize = (unsigned int)positions.size(); - for (unsigned int i = 0 ; i < origSize ; i+=3) - { - aiVector3D& tv0 = positions[i]; - aiVector3D& tv1 = positions[i+1]; - aiVector3D& tv2 = positions[i+2]; - - aiVector3D a = tv0, b = tv1, c = tv2; - aiVector3D v1 = aiVector3D(a.x+b.x, a.y+b.y, a.z+b.z).Normalize()*fl1; - aiVector3D v2 = aiVector3D(a.x+c.x, a.y+c.y, a.z+c.z).Normalize()*fl1; - aiVector3D v3 = aiVector3D(b.x+c.x, b.y+c.y, b.z+c.z).Normalize()*fl1; - - tv0 = v1; tv1 = v3; tv2 = v2; // overwrite the original - ADD_TRIANGLE(v1, v2, a); - ADD_TRIANGLE(v2, v3, c); - ADD_TRIANGLE(v3, v1, b); - } -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh from given vertex positions -aiMesh* StandardShapes::MakeMesh(const std::vector& positions, - unsigned int numIndices) -{ - if (positions.empty() || !numIndices) return NULL; - - // Determine which kinds of primitives the mesh consists of - aiMesh* out = new aiMesh(); - switch (numIndices) { - case 1: - out->mPrimitiveTypes = aiPrimitiveType_POINT; - break; - case 2: - out->mPrimitiveTypes = aiPrimitiveType_LINE; - break; - case 3: - out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - break; - default: - out->mPrimitiveTypes = aiPrimitiveType_POLYGON; - break; - }; - - out->mNumFaces = (unsigned int)positions.size() / numIndices; - out->mFaces = new aiFace[out->mNumFaces]; - for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) { - aiFace& f = out->mFaces[i]; - f.mNumIndices = numIndices; - f.mIndices = new unsigned int[numIndices]; - for (unsigned int j = 0; i < numIndices; ++i, ++a) { - f.mIndices[j] = a; - } - } - out->mNumVertices = (unsigned int)positions.size(); - out->mVertices = new aiVector3D[out->mNumVertices]; - ::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D)); - - return out; -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( - std::vector&)) -{ - std::vector temp; - unsigned num = (*GenerateFunc)(temp); - return MakeMesh(temp,num); -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( - std::vector&, bool)) -{ - std::vector temp; - unsigned num = (*GenerateFunc)(temp,true); - return MakeMesh(temp,num); -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)( - unsigned int,std::vector&)) -{ - std::vector temp; - (*GenerateFunc)(num,temp); - return MakeMesh(temp,3); -} - -// ------------------------------------------------------------------------------------------------ -// Build an incosahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeIcosahedron(std::vector& positions) -{ - positions.reserve(positions.size()+60); - - const ai_real t = ( ai_real( 1.0 )+ ai_real( 2.236067977 ) ) / ai_real( 2.0 ); - const ai_real s = std::sqrt(ai_real(1.0) + t*t); - - const aiVector3D v0 = aiVector3D(t,1.0, 0.0)/s; - const aiVector3D v1 = aiVector3D(-t,1.0, 0.0)/s; - const aiVector3D v2 = aiVector3D(t,-1.0, 0.0)/s; - const aiVector3D v3 = aiVector3D(-t,-1.0, 0.0)/s; - const aiVector3D v4 = aiVector3D(1.0, 0.0, t)/s; - const aiVector3D v5 = aiVector3D(1.0, 0.0,-t)/s; - const aiVector3D v6 = aiVector3D(-1.0, 0.0,t)/s; - const aiVector3D v7 = aiVector3D(-1.0, 0.0,-t)/s; - const aiVector3D v8 = aiVector3D(0.0, t, 1.0)/s; - const aiVector3D v9 = aiVector3D(0.0,-t, 1.0)/s; - const aiVector3D v10 = aiVector3D(0.0, t,-1.0)/s; - const aiVector3D v11 = aiVector3D(0.0,-t,-1.0)/s; - - ADD_TRIANGLE(v0,v8,v4); - ADD_TRIANGLE(v0,v5,v10); - ADD_TRIANGLE(v2,v4,v9); - ADD_TRIANGLE(v2,v11,v5); - - ADD_TRIANGLE(v1,v6,v8); - ADD_TRIANGLE(v1,v10,v7); - ADD_TRIANGLE(v3,v9,v6); - ADD_TRIANGLE(v3,v7,v11); - - ADD_TRIANGLE(v0,v10,v8); - ADD_TRIANGLE(v1,v8,v10); - ADD_TRIANGLE(v2,v9,v11); - ADD_TRIANGLE(v3,v11,v9); - - ADD_TRIANGLE(v4,v2,v0); - ADD_TRIANGLE(v5,v0,v2); - ADD_TRIANGLE(v6,v1,v3); - ADD_TRIANGLE(v7,v3,v1); - - ADD_TRIANGLE(v8,v6,v4); - ADD_TRIANGLE(v9,v4,v6); - ADD_TRIANGLE(v10,v5,v7); - ADD_TRIANGLE(v11,v7,v5); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a dodecahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeDodecahedron(std::vector& positions, - bool polygons /*= false*/) -{ - positions.reserve(positions.size()+108); - - const ai_real a = ai_real( 1.0 ) / ai_real(1.7320508); - const ai_real b = std::sqrt(( ai_real( 3.0 )- ai_real( 2.23606797))/ ai_real( 6.0) ); - const ai_real c = std::sqrt(( ai_real( 3.0 )+ ai_real( 2.23606797f))/ ai_real( 6.0) ); - - const aiVector3D v0 = aiVector3D(a,a,a); - const aiVector3D v1 = aiVector3D(a,a,-a); - const aiVector3D v2 = aiVector3D(a,-a,a); - const aiVector3D v3 = aiVector3D(a,-a,-a); - const aiVector3D v4 = aiVector3D(-a,a,a); - const aiVector3D v5 = aiVector3D(-a,a,-a); - const aiVector3D v6 = aiVector3D(-a,-a,a); - const aiVector3D v7 = aiVector3D(-a,-a,-a); - const aiVector3D v8 = aiVector3D(b,c,0.0); - const aiVector3D v9 = aiVector3D(-b,c,0.0); - const aiVector3D v10 = aiVector3D(b,-c,0.0); - const aiVector3D v11 = aiVector3D(-b,-c,0.0); - const aiVector3D v12 = aiVector3D(c, 0.0, b); - const aiVector3D v13 = aiVector3D(c, 0.0, -b); - const aiVector3D v14 = aiVector3D(-c, 0.0, b); - const aiVector3D v15 = aiVector3D(-c, 0.0, -b); - const aiVector3D v16 = aiVector3D(0.0, b, c); - const aiVector3D v17 = aiVector3D(0.0, -b, c); - const aiVector3D v18 = aiVector3D(0.0, b, -c); - const aiVector3D v19 = aiVector3D(0.0, -b, -c); - - ADD_PENTAGON(v0, v8, v9, v4, v16); - ADD_PENTAGON(v0, v12, v13, v1, v8); - ADD_PENTAGON(v0, v16, v17, v2, v12); - ADD_PENTAGON(v8, v1, v18, v5, v9); - ADD_PENTAGON(v12, v2, v10, v3, v13); - ADD_PENTAGON(v16, v4, v14, v6, v17); - ADD_PENTAGON(v9, v5, v15, v14, v4); - - ADD_PENTAGON(v6, v11, v10, v2, v17); - ADD_PENTAGON(v3, v19, v18, v1, v13); - ADD_PENTAGON(v7, v15, v5, v18, v19); - ADD_PENTAGON(v7, v11, v6, v14, v15); - ADD_PENTAGON(v7, v19, v3, v10, v11); - return (polygons ? 5 : 3); -} - -// ------------------------------------------------------------------------------------------------ -// Build an octahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeOctahedron(std::vector& positions) -{ - positions.reserve(positions.size()+24); - - const aiVector3D v0 = aiVector3D(1.0, 0.0, 0.0) ; - const aiVector3D v1 = aiVector3D(-1.0, 0.0, 0.0); - const aiVector3D v2 = aiVector3D(0.0, 1.0, 0.0); - const aiVector3D v3 = aiVector3D(0.0, -1.0, 0.0); - const aiVector3D v4 = aiVector3D(0.0, 0.0, 1.0); - const aiVector3D v5 = aiVector3D(0.0, 0.0, -1.0); - - ADD_TRIANGLE(v4,v0,v2); - ADD_TRIANGLE(v4,v2,v1); - ADD_TRIANGLE(v4,v1,v3); - ADD_TRIANGLE(v4,v3,v0); - - ADD_TRIANGLE(v5,v2,v0); - ADD_TRIANGLE(v5,v1,v2); - ADD_TRIANGLE(v5,v3,v1); - ADD_TRIANGLE(v5,v0,v3); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a tetrahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeTetrahedron(std::vector& positions) -{ - positions.reserve(positions.size()+9); - - const ai_real invThree = ai_real( 1.0 ) / ai_real( 3.0 ); - const ai_real a = ai_real( 1.41421 ) * invThree; - const ai_real b = ai_real( 2.4494 ) * invThree; - - const aiVector3D v0 = aiVector3D(0.0,0.0,1.0); - const aiVector3D v1 = aiVector3D(2*a,0,-invThree ); - const aiVector3D v2 = aiVector3D(-a,b,-invThree ); - const aiVector3D v3 = aiVector3D(-a,-b,-invThree ); - - ADD_TRIANGLE(v0,v1,v2); - ADD_TRIANGLE(v0,v2,v3); - ADD_TRIANGLE(v0,v3,v1); - ADD_TRIANGLE(v1,v3,v2); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a hexahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeHexahedron(std::vector& positions, - bool polygons /*= false*/) -{ - positions.reserve(positions.size()+36); - const ai_real length = ai_real(1.0)/ai_real(1.73205080); - - const aiVector3D v0 = aiVector3D(-1.0,-1.0,-1.0)*length; - const aiVector3D v1 = aiVector3D(1.0,-1.0,-1.0)*length; - const aiVector3D v2 = aiVector3D(1.0,1.0,-1.0)*length; - const aiVector3D v3 = aiVector3D(-1.0,1.0,-1.0)*length; - const aiVector3D v4 = aiVector3D(-1.0,-1.0,1.0)*length; - const aiVector3D v5 = aiVector3D(1.0,-1.0,1.0)*length; - const aiVector3D v6 = aiVector3D(1.0,1.0,1.0)*length; - const aiVector3D v7 = aiVector3D(-1.0,1.0,1.0)*length; - - ADD_QUAD(v0,v3,v2,v1); - ADD_QUAD(v0,v1,v5,v4); - ADD_QUAD(v0,v4,v7,v3); - ADD_QUAD(v6,v5,v1,v2); - ADD_QUAD(v6,v2,v3,v7); - ADD_QUAD(v6,v7,v4,v5); - return (polygons ? 4 : 3); -} - -// Cleanup ... -#undef ADD_TRIANGLE -#undef ADD_QUAD -#undef ADD_PENTAGON - -// ------------------------------------------------------------------------------------------------ -// Create a subdivision sphere -void StandardShapes::MakeSphere(unsigned int tess, - std::vector& positions) -{ - // Reserve enough storage. Every subdivision - // splits each triangle in 4, the icosahedron consists of 60 verts - positions.reserve(positions.size()+60 * integer_pow(4, tess)); - - // Construct an icosahedron to start with - MakeIcosahedron(positions); - - // ... and subdivide it until the requested output - // tessellation is reached - for (unsigned int i = 0; i& positions,bool bOpen /*= false */) -{ - // Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE - if (tess < 3 || !height) - return; - - size_t old = positions.size(); - - // No negative radii - radius1 = std::fabs(radius1); - radius2 = std::fabs(radius2); - - ai_real halfHeight = height / ai_real(2.0); - - // radius1 is always the smaller one - if (radius2 > radius1) - { - std::swap(radius2,radius1); - halfHeight = -halfHeight; - } - else old = SIZE_MAX; - - // Use a large epsilon to check whether the cone is pointy - if (radius1 < (radius2-radius1)*10e-3)radius1 = 0.0; - - // We will need 3*2 verts per segment + 3*2 verts per segment - // if the cone is closed - const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0); - positions.reserve(positions.size () + mem); - - // Now construct all segments - const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; - const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; - - ai_real s = 1.0; // std::cos(angle == 0); - ai_real t = 0.0; // std::sin(angle == 0); - - for (ai_real angle = 0.0; angle < angle_max; ) - { - const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 ); - const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 ); - - const ai_real next = angle + angle_delta; - ai_real s2 = std::cos(next); - ai_real t2 = std::sin(next); - - const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 ); - const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 ); - - positions.push_back(v1); - positions.push_back(v2); - positions.push_back(v3); - positions.push_back(v4); - positions.push_back(v1); - positions.push_back(v3); - - if (!bOpen) - { - // generate the end 'cap' - positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 )); - positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 )); - positions.push_back(aiVector3D(0.0, halfHeight, 0.0)); - - - if (radius1) - { - // generate the other end 'cap' - positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 )); - positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 )); - positions.push_back(aiVector3D(0.0, -halfHeight, 0.0)); - - } - } - s = s2; - t = t2; - angle = next; - } - - // Need to flip face order? - if ( SIZE_MAX != old ) { - for (size_t p = old; p < positions.size();p += 3) { - std::swap(positions[p],positions[p+1]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Build a circle -void StandardShapes::MakeCircle(ai_real radius, unsigned int tess, - std::vector& positions) -{ - // Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE - if (tess < 3 || !radius) - return; - - radius = std::fabs(radius); - - // We will need 3 vertices per segment - positions.reserve(positions.size()+tess*3); - - const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; - const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; - - ai_real s = 1.0; // std::cos(angle == 0); - ai_real t = 0.0; // std::sin(angle == 0); - - for (ai_real angle = 0.0; angle < angle_max; ) - { - positions.push_back(aiVector3D(s * radius,0.0,t * radius)); - angle += angle_delta; - s = std::cos(angle); - t = std::sin(angle); - positions.push_back(aiVector3D(s * radius,0.0,t * radius)); - - positions.push_back(aiVector3D(0.0,0.0,0.0)); - } -} - -} // ! Assimp diff --git a/thirdparty/assimp/code/Common/StdOStreamLogStream.h b/thirdparty/assimp/code/Common/StdOStreamLogStream.h deleted file mode 100644 index 893e261a2b20..000000000000 --- a/thirdparty/assimp/code/Common/StdOStreamLogStream.h +++ /dev/null @@ -1,101 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 StdOStreamLogStream.h -* @brief Implementation of StdOStreamLogStream -*/ - -#ifndef AI_STROSTREAMLOGSTREAM_H_INC -#define AI_STROSTREAMLOGSTREAM_H_INC - -#include -#include - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @class StdOStreamLogStream - * @brief Logs into a std::ostream - */ -class StdOStreamLogStream : public LogStream { -public: - /** @brief Construction from an existing std::ostream - * @param _ostream Output stream to be used - */ - explicit StdOStreamLogStream(std::ostream& _ostream); - - /** @brief Destructor */ - ~StdOStreamLogStream(); - - /** @brief Writer */ - void write(const char* message); - -private: - std::ostream& mOstream; -}; - -// --------------------------------------------------------------------------- -// Default constructor -inline StdOStreamLogStream::StdOStreamLogStream(std::ostream& _ostream) -: mOstream (_ostream){ - // empty -} - -// --------------------------------------------------------------------------- -// Default constructor -inline StdOStreamLogStream::~StdOStreamLogStream() { - // empty -} - -// --------------------------------------------------------------------------- -// Write method -inline void StdOStreamLogStream::write(const char* message) { - mOstream << message; - mOstream.flush(); -} - -// --------------------------------------------------------------------------- - -} // Namespace Assimp - -#endif // guard diff --git a/thirdparty/assimp/code/Common/Subdivision.cpp b/thirdparty/assimp/code/Common/Subdivision.cpp deleted file mode 100644 index 60c54939f591..000000000000 --- a/thirdparty/assimp/code/Common/Subdivision.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#include -#include -#include -#include -#include - -#include "PostProcessing/ProcessHelper.h" - -#include - -using namespace Assimp; -void mydummy() {} - -// ------------------------------------------------------------------------------------------------ -/** Subdivider stub class to implement the Catmull-Clarke subdivision algorithm. The - * implementation is basing on recursive refinement. Directly evaluating the result is also - * possible and much quicker, but it depends on lengthy matrix lookup tables. */ -// ------------------------------------------------------------------------------------------------ -class CatmullClarkSubdivider : public Subdivider { -public: - void Subdivide (aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input); - void Subdivide (aiMesh** smesh, size_t nmesh, - aiMesh** out, unsigned int num, bool discard_input); - - // --------------------------------------------------------------------------- - /** Intermediate description of an edge between two corners of a polygon*/ - // --------------------------------------------------------------------------- - struct Edge - { - Edge() - : ref(0) - {} - Vertex edge_point, midpoint; - unsigned int ref; - }; - - typedef std::vector UIntVector; - typedef std::map EdgeMap; - - // --------------------------------------------------------------------------- - // Hashing function to derive an index into an #EdgeMap from two given - // 'unsigned int' vertex coordinates (!!distinct coordinates - same - // vertex position == same index!!). - // NOTE - this leads to rare hash collisions if a) sizeof(unsigned int)>4 - // and (id[0]>2^32-1 or id[0]>2^32-1). - // MAKE_EDGE_HASH() uses temporaries, so INIT_EDGE_HASH() needs to be put - // at the head of every function which is about to use MAKE_EDGE_HASH(). - // Reason is that the hash is that hash construction needs to hold the - // invariant id0out+nmesh); - if (!num) { - // No subdivision at all. Need to copy all the meshes .. argh. - if (discard_input) { - for (size_t s = 0; s < nmesh; ++s) { - out[s] = smesh[s]; - smesh[s] = NULL; - } - } - else { - for (size_t s = 0; s < nmesh; ++s) { - SceneCombiner::Copy(out+s,smesh[s]); - } - } - return; - } - - std::vector inmeshes; - std::vector outmeshes; - std::vector maptbl; - - inmeshes.reserve(nmesh); - outmeshes.reserve(nmesh); - maptbl.reserve(nmesh); - - // Remove pure line and point meshes from the working set to reduce the - // number of edge cases the subdivider is forced to deal with. Line and - // point meshes are simply passed through. - for (size_t s = 0; s < nmesh; ++s) { - aiMesh* i = smesh[s]; - // FIX - mPrimitiveTypes might not yet be initialized - if (i->mPrimitiveTypes && (i->mPrimitiveTypes & (aiPrimitiveType_LINE|aiPrimitiveType_POINT))==i->mPrimitiveTypes) { - ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Skipping pure line/point mesh"); - - if (discard_input) { - out[s] = i; - smesh[s] = NULL; - } - else { - SceneCombiner::Copy(out+s,i); - } - continue; - } - - outmeshes.push_back(NULL);inmeshes.push_back(i); - maptbl.push_back(static_cast(s)); - } - - // Do the actual subdivision on the preallocated storage. InternSubdivide - // *always* assumes that enough storage is available, it does not bother - // checking any ranges. - ai_assert(inmeshes.size()==outmeshes.size()&&inmeshes.size()==maptbl.size()); - if (inmeshes.empty()) { - ASSIMP_LOG_WARN("Catmull-Clark Subdivider: Pure point/line scene, I can't do anything"); - return; - } - InternSubdivide(&inmeshes.front(),inmeshes.size(),&outmeshes.front(),num); - for (unsigned int i = 0; i < maptbl.size(); ++i) { - ai_assert(nullptr != outmeshes[i]); - out[maptbl[i]] = outmeshes[i]; - } - - if (discard_input) { - for (size_t s = 0; s < nmesh; ++s) { - delete smesh[s]; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Note - this is an implementation of the standard (recursive) Cm-Cl algorithm without further -// optimizations (except we're using some nice LUTs). A description of the algorithm can be found -// here: http://en.wikipedia.org/wiki/Catmull-Clark_subdivision_surface -// -// The code is mostly O(n), however parts are O(nlogn) which is therefore the algorithm's -// expected total runtime complexity. The implementation is able to work in-place on the same -// mesh arrays. Calling #InternSubdivide() directly is not encouraged. The code can operate -// in-place unless 'smesh' and 'out' are equal (no strange overlaps or reorderings). -// Previous data is replaced/deleted then. -// ------------------------------------------------------------------------------------------------ -void CatmullClarkSubdivider::InternSubdivide ( - const aiMesh* const * smesh, - size_t nmesh, - aiMesh** out, - unsigned int num - ) -{ - ai_assert(NULL != smesh && NULL != out); - INIT_EDGE_HASH_TEMPORARIES(); - - // no subdivision requested or end of recursive refinement - if (!num) { - return; - } - - UIntVector maptbl; - SpatialSort spatial; - - // --------------------------------------------------------------------- - // 0. Offset table to index all meshes continuously, generate a spatially - // sorted representation of all vertices in all meshes. - // --------------------------------------------------------------------- - typedef std::pair IntPair; - std::vector moffsets(nmesh); - unsigned int totfaces = 0, totvert = 0; - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - - spatial.Append(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D),false); - moffsets[t] = IntPair(totfaces,totvert); - - totfaces += mesh->mNumFaces; - totvert += mesh->mNumVertices; - } - - spatial.Finalize(); - const unsigned int num_unique = spatial.GenerateMappingTable(maptbl,ComputePositionEpsilon(smesh,nmesh)); - - -#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second+vert_idx) -#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first+face_idx) - - // --------------------------------------------------------------------- - // 1. Compute the centroid point for all faces - // --------------------------------------------------------------------- - std::vector centroids(totfaces); - unsigned int nfacesout = 0; - for (size_t t = 0, n = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - for (unsigned int i = 0; i < mesh->mNumFaces;++i,++n) - { - const aiFace& face = mesh->mFaces[i]; - Vertex& c = centroids[n]; - - for (unsigned int a = 0; a < face.mNumIndices;++a) { - c += Vertex(mesh,face.mIndices[a]); - } - - c /= static_cast(face.mNumIndices); - nfacesout += face.mNumIndices; - } - } - - { - // we want edges to go away before the recursive calls so begin a new scope - EdgeMap edges; - - // --------------------------------------------------------------------- - // 2. Set each edge point to be the average of all neighbouring - // face points and original points. Every edge exists twice - // if there is a neighboring face. - // --------------------------------------------------------------------- - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& face = mesh->mFaces[i]; - - for (unsigned int p =0; p< face.mNumIndices; ++p) { - const unsigned int id[] = { - face.mIndices[p], - face.mIndices[p==face.mNumIndices-1?0:p+1] - }; - const unsigned int mp[] = { - maptbl[FLATTEN_VERTEX_IDX(t,id[0])], - maptbl[FLATTEN_VERTEX_IDX(t,id[1])] - }; - - Edge& e = edges[MAKE_EDGE_HASH(mp[0],mp[1])]; - e.ref++; - if (e.ref<=2) { - if (e.ref==1) { // original points (end points) - add only once - e.edge_point = e.midpoint = Vertex(mesh,id[0])+Vertex(mesh,id[1]); - e.midpoint *= 0.5f; - } - e.edge_point += centroids[FLATTEN_FACE_IDX(t,i)]; - } - } - } - } - - // --------------------------------------------------------------------- - // 3. Normalize edge points - // --------------------------------------------------------------------- - {unsigned int bad_cnt = 0; - for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) { - if ((*it).second.ref < 2) { - ai_assert((*it).second.ref); - ++bad_cnt; - } - (*it).second.edge_point *= 1.f/((*it).second.ref+2.f); - } - - if (bad_cnt) { - // Report the number of bad edges. bad edges are referenced by less than two - // faces in the mesh. They occur at outer model boundaries in non-closed - // shapes. - ASSIMP_LOG_DEBUG_F("Catmull-Clark Subdivider: got ", bad_cnt, " bad edges touching only one face (totally ", - static_cast(edges.size()), " edges). "); - }} - - // --------------------------------------------------------------------- - // 4. Compute a vertex-face adjacency table. We can't reuse the code - // from VertexTriangleAdjacency because we need the table for multiple - // meshes and out vertex indices need to be mapped to distinct values - // first. - // --------------------------------------------------------------------- - UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(),0), ofsadjvec(maptbl.size()+1,0); { - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - for (unsigned int i = 0; i < minp->mNumFaces; ++i) { - - const aiFace& f = minp->mFaces[i]; - for (unsigned int n = 0; n < f.mNumIndices; ++n) { - ++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]; - } - } - } - unsigned int cur = 0; - for (size_t i = 0; i < cntadjfac.size(); ++i) { - ofsadjvec[i+1] = cur; - cur += cntadjfac[i]; - } - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - for (unsigned int i = 0; i < minp->mNumFaces; ++i) { - - const aiFace& f = minp->mFaces[i]; - for (unsigned int n = 0; n < f.mNumIndices; ++n) { - faceadjac[ofsadjvec[1+maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t,i); - } - } - } - - // check the other way round for consistency -#ifdef ASSIMP_BUILD_DEBUG - - for (size_t t = 0; t < ofsadjvec.size()-1; ++t) { - for (unsigned int m = 0; m < cntadjfac[t]; ++m) { - const unsigned int fidx = faceadjac[ofsadjvec[t]+m]; - ai_assert(fidx < totfaces); - for (size_t n = 1; n < nmesh; ++n) { - - if (moffsets[n].first > fidx) { - const aiMesh* msh = smesh[--n]; - const aiFace& f = msh->mFaces[fidx-moffsets[n].first]; - - bool haveit = false; - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) { - haveit = true; - break; - } - } - ai_assert(haveit); - if (!haveit) { - ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Index not used"); - } - break; - } - } - } - } - -#endif - } - -#define GET_ADJACENT_FACES_AND_CNT(vidx,fstartout,numout) \ - fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx] - - typedef std::pair TouchedOVertex; - std::vector new_points(num_unique,TouchedOVertex(false,Vertex())); - // --------------------------------------------------------------------- - // 5. Spawn a quad from each face point to the corresponding edge points - // the original points being the fourth quad points. - // --------------------------------------------------------------------- - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - aiMesh* const mout = out[t] = new aiMesh(); - - for (unsigned int a = 0; a < minp->mNumFaces; ++a) { - mout->mNumFaces += minp->mFaces[a].mNumIndices; - } - - // We need random access to the old face buffer, so reuse is not possible. - mout->mFaces = new aiFace[mout->mNumFaces]; - - mout->mNumVertices = mout->mNumFaces*4; - mout->mVertices = new aiVector3D[mout->mNumVertices]; - - // quads only, keep material index - mout->mPrimitiveTypes = aiPrimitiveType_POLYGON; - mout->mMaterialIndex = minp->mMaterialIndex; - - if (minp->HasNormals()) { - mout->mNormals = new aiVector3D[mout->mNumVertices]; - } - - if (minp->HasTangentsAndBitangents()) { - mout->mTangents = new aiVector3D[mout->mNumVertices]; - mout->mBitangents = new aiVector3D[mout->mNumVertices]; - } - - for(unsigned int i = 0; minp->HasTextureCoords(i); ++i) { - mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices]; - mout->mNumUVComponents[i] = minp->mNumUVComponents[i]; - } - - for(unsigned int i = 0; minp->HasVertexColors(i); ++i) { - mout->mColors[i] = new aiColor4D[mout->mNumVertices]; - } - - mout->mNumVertices = mout->mNumFaces<<2u; - for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces;++i) { - - const aiFace& face = minp->mFaces[i]; - for (unsigned int a = 0; a < face.mNumIndices;++a) { - - // Get a clean new face. - aiFace& faceOut = mout->mFaces[n++]; - faceOut.mIndices = new unsigned int [faceOut.mNumIndices = 4]; - - // Spawn a new quadrilateral (ccw winding) for this original point between: - // a) face centroid - centroids[FLATTEN_FACE_IDX(t,i)].SortBack(mout,faceOut.mIndices[0]=v++); - - // b) adjacent edge on the left, seen from the centroid - const Edge& e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], - maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a==face.mNumIndices-1?0:a+1]) - ])]; // fixme: replace with mod face.mNumIndices? - - // c) adjacent edge on the right, seen from the centroid - const Edge& e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], - maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[!a?face.mNumIndices-1:a-1]) - ])]; // fixme: replace with mod face.mNumIndices? - - e0.edge_point.SortBack(mout,faceOut.mIndices[3]=v++); - e1.edge_point.SortBack(mout,faceOut.mIndices[1]=v++); - - // d= original point P with distinct index i - // F := 0 - // R := 0 - // n := 0 - // for each face f containing i - // F := F+ centroid of f - // R := R+ midpoint of edge of f from i to i+1 - // n := n+1 - // - // (F+2R+(n-3)P)/n - const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])]; - TouchedOVertex& ov = new_points[org]; - - if (!ov.first) { - ov.first = true; - - const unsigned int* adj; unsigned int cnt; - GET_ADJACENT_FACES_AND_CNT(org,adj,cnt); - - if (cnt < 3) { - ov.second = Vertex(minp,face.mIndices[a]); - } - else { - - Vertex F,R; - for (unsigned int o = 0; o < cnt; ++o) { - ai_assert(adj[o] < totfaces); - F += centroids[adj[o]]; - - // adj[0] is a global face index - search the face in the mesh list - const aiMesh* mp = NULL; - size_t nidx; - - if (adj[o] < moffsets[0].first) { - mp = smesh[nidx=0]; - } - else { - for (nidx = 1; nidx<= nmesh; ++nidx) { - if (nidx == nmesh ||moffsets[nidx].first > adj[o]) { - mp = smesh[--nidx]; - break; - } - } - } - - ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces); - const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first]; - bool haveit = false; - - // find our original point in the face - for (unsigned int m = 0; m < f.mNumIndices; ++m) { - if (maptbl[FLATTEN_VERTEX_IDX(nidx,f.mIndices[m])] == org) { - - // add *both* edges. this way, we can be sure that we add - // *all* adjacent edges to R. In a closed shape, every - // edge is added twice - so we simply leave out the - // factor 2.f in the amove formula and get the right - // result. - - const Edge& c0 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( - nidx,f.mIndices[!m?f.mNumIndices-1:m-1])])]; - // fixme: replace with mod face.mNumIndices? - - const Edge& c1 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( - nidx,f.mIndices[m==f.mNumIndices-1?0:m+1])])]; - // fixme: replace with mod face.mNumIndices? - R += c0.midpoint+c1.midpoint; - - haveit = true; - break; - } - } - - // this invariant *must* hold if the vertex-to-face adjacency table is valid - ai_assert(haveit); - if ( !haveit ) { - ASSIMP_LOG_WARN( "OBJ: no name for material library specified." ); - } - } - - const float div = static_cast(cnt), divsq = 1.f/(div*div); - ov.second = Vertex(minp,face.mIndices[a])*((div-3.f) / div) + R*divsq + F*divsq; - } - } - ov.second.SortBack(mout,faceOut.mIndices[2]=v++); - } - } - } - } // end of scope for edges, freeing its memory - - // --------------------------------------------------------------------- - // 7. Apply the next subdivision step. - // --------------------------------------------------------------------- - if (num != 1) { - std::vector tmp(nmesh); - InternSubdivide (out,nmesh,&tmp.front(),num-1); - for (size_t i = 0; i < nmesh; ++i) { - delete out[i]; - out[i] = tmp[i]; - } - } -} diff --git a/thirdparty/assimp/code/Common/TargetAnimation.cpp b/thirdparty/assimp/code/Common/TargetAnimation.cpp deleted file mode 100644 index b8062499ff80..000000000000 --- a/thirdparty/assimp/code/Common/TargetAnimation.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#include "TargetAnimation.h" -#include -#include - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -KeyIterator::KeyIterator(const std::vector* _objPos, - const std::vector* _targetObjPos, - const aiVector3D* defaultObjectPos /*= NULL*/, - const aiVector3D* defaultTargetPos /*= NULL*/) - - : reachedEnd (false) - , curTime (-1.) - , objPos (_objPos) - , targetObjPos (_targetObjPos) - , nextObjPos (0) - , nextTargetObjPos(0) -{ - // Generate default transformation tracks if necessary - if (!objPos || objPos->empty()) - { - defaultObjPos.resize(1); - defaultObjPos.front().mTime = 10e10; - - if (defaultObjectPos) - defaultObjPos.front().mValue = *defaultObjectPos; - - objPos = & defaultObjPos; - } - if (!targetObjPos || targetObjPos->empty()) - { - defaultTargetObjPos.resize(1); - defaultTargetObjPos.front().mTime = 10e10; - - if (defaultTargetPos) - defaultTargetObjPos.front().mValue = *defaultTargetPos; - - targetObjPos = & defaultTargetObjPos; - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline T Interpolate(const T& one, const T& two, ai_real val) -{ - return one + (two-one)*val; -} - -// ------------------------------------------------------------------------------------------------ -void KeyIterator::operator ++() -{ - // If we are already at the end of all keyframes, return - if (reachedEnd) { - return; - } - - // Now search in all arrays for the time value closest - // to our current position on the time line - double d0,d1; - - d0 = objPos->at ( std::min ( nextObjPos, static_cast(objPos->size()-1)) ).mTime; - d1 = targetObjPos->at( std::min ( nextTargetObjPos, static_cast(targetObjPos->size()-1)) ).mTime; - - // Easiest case - all are identical. In this - // case we don't need to interpolate so we can - // return earlier - if ( d0 == d1 ) - { - curTime = d0; - curPosition = objPos->at(nextObjPos).mValue; - curTargetPosition = targetObjPos->at(nextTargetObjPos).mValue; - - // increment counters - if (objPos->size() != nextObjPos-1) - ++nextObjPos; - - if (targetObjPos->size() != nextTargetObjPos-1) - ++nextTargetObjPos; - } - - // An object position key is closest to us - else if (d0 < d1) - { - curTime = d0; - - // interpolate the other - if (1 == targetObjPos->size() || !nextTargetObjPos) { - curTargetPosition = targetObjPos->at(0).mValue; - } - else - { - const aiVectorKey& last = targetObjPos->at(nextTargetObjPos); - const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1); - - curTargetPosition = Interpolate(first.mValue, last.mValue, (ai_real) ( - (curTime-first.mTime) / (last.mTime-first.mTime) )); - } - - if (objPos->size() != nextObjPos-1) - ++nextObjPos; - } - // A target position key is closest to us - else - { - curTime = d1; - - // interpolate the other - if (1 == objPos->size() || !nextObjPos) { - curPosition = objPos->at(0).mValue; - } - else - { - const aiVectorKey& last = objPos->at(nextObjPos); - const aiVectorKey& first = objPos->at(nextObjPos-1); - - curPosition = Interpolate(first.mValue, last.mValue, (ai_real) ( - (curTime-first.mTime) / (last.mTime-first.mTime))); - } - - if (targetObjPos->size() != nextTargetObjPos-1) - ++nextTargetObjPos; - } - - if (nextObjPos >= objPos->size()-1 && - nextTargetObjPos >= targetObjPos->size()-1) - { - // We reached the very last keyframe - reachedEnd = true; - } -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetTargetAnimationChannel ( - const std::vector* _targetPositions) -{ - ai_assert(NULL != _targetPositions); - targetPositions = _targetPositions; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetMainAnimationChannel ( - const std::vector* _objectPositions) -{ - ai_assert(NULL != _objectPositions); - objectPositions = _objectPositions; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetFixedMainAnimationChannel( - const aiVector3D& fixed) -{ - objectPositions = NULL; // just to avoid confusion - fixedMain = fixed; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::Process(std::vector* distanceTrack) -{ - ai_assert(NULL != targetPositions && NULL != distanceTrack); - - // TODO: in most cases we won't need the extra array - std::vector real; - - std::vector* fill = (distanceTrack == objectPositions ? &real : distanceTrack); - fill->reserve(std::max( objectPositions->size(), targetPositions->size() )); - - // Iterate through all object keys and interpolate their values if necessary. - // Then get the corresponding target position, compute the difference - // vector between object and target position. Then compute a rotation matrix - // that rotates the base vector of the object coordinate system at that time - // to match the diff vector. - - KeyIterator iter(objectPositions,targetPositions,&fixedMain); - for (;!iter.Finished();++iter) - { - const aiVector3D& position = iter.GetCurPosition(); - const aiVector3D& tposition = iter.GetCurTargetPosition(); - - // diff vector - aiVector3D diff = tposition - position; - ai_real f = diff.Length(); - - // output distance vector - if (f) - { - fill->push_back(aiVectorKey()); - aiVectorKey& v = fill->back(); - v.mTime = iter.GetCurTime(); - v.mValue = diff; - - diff /= f; - } - else - { - // FIXME: handle this - } - - // diff is now the vector in which our camera is pointing - } - - if (real.size()) { - *distanceTrack = real; - } -} diff --git a/thirdparty/assimp/code/Common/TargetAnimation.h b/thirdparty/assimp/code/Common/TargetAnimation.h deleted file mode 100644 index 91634ab5aa24..000000000000 --- a/thirdparty/assimp/code/Common/TargetAnimation.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -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 Defines a helper class for the ASE and 3DS loaders to - help them compute camera and spot light animation channels */ -#ifndef AI_TARGET_ANIMATION_H_INC -#define AI_TARGET_ANIMATION_H_INC - -#include -#include - -namespace Assimp { - - - -// --------------------------------------------------------------------------- -/** Helper class to iterate through all keys in an animation channel. - * - * Missing tracks are interpolated. This is a helper class for - * TargetAnimationHelper, but it can be freely used for other purposes. -*/ -class KeyIterator -{ -public: - - - // ------------------------------------------------------------------ - /** Constructs a new key iterator - * - * @param _objPos Object position track. May be NULL. - * @param _targetObjPos Target object position track. May be NULL. - * @param defaultObjectPos Default object position to be used if - * no animated track is available. May be NULL. - * @param defaultTargetPos Default target position to be used if - * no animated track is available. May be NULL. - */ - KeyIterator(const std::vector* _objPos, - const std::vector* _targetObjPos, - const aiVector3D* defaultObjectPos = NULL, - const aiVector3D* defaultTargetPos = NULL); - - // ------------------------------------------------------------------ - /** Returns true if all keys have been processed - */ - bool Finished() const - {return reachedEnd;} - - // ------------------------------------------------------------------ - /** Increment the iterator - */ - void operator++(); - inline void operator++(int) - {return ++(*this);} - - - - // ------------------------------------------------------------------ - /** Getters to retrieve the current state of the iterator - */ - inline const aiVector3D& GetCurPosition() const - {return curPosition;} - - inline const aiVector3D& GetCurTargetPosition() const - {return curTargetPosition;} - - inline double GetCurTime() const - {return curTime;} - -private: - - //! Did we reach the end? - bool reachedEnd; - - //! Represents the current position of the iterator - aiVector3D curPosition, curTargetPosition; - - double curTime; - - //! Input tracks and the next key to process - const std::vector* objPos,*targetObjPos; - - unsigned int nextObjPos, nextTargetObjPos; - std::vector defaultObjPos,defaultTargetObjPos; -}; - -// --------------------------------------------------------------------------- -/** Helper class for the 3DS and ASE loaders to compute camera and spot light - * animations. - * - * 3DS and ASE store the differently to Assimp - there is an animation - * channel for the camera/spot light itself and a separate position - * animation channels specifying the position of the camera/spot light - * look-at target */ -class TargetAnimationHelper -{ -public: - - TargetAnimationHelper() - : targetPositions (NULL) - , objectPositions (NULL) - {} - - - // ------------------------------------------------------------------ - /** Sets the target animation channel - * - * This channel specifies the position of the camera/spot light - * target at a specific position. - * - * @param targetPositions Translation channel*/ - void SetTargetAnimationChannel (const - std::vector* targetPositions); - - - // ------------------------------------------------------------------ - /** Sets the main animation channel - * - * @param objectPositions Translation channel */ - void SetMainAnimationChannel ( const - std::vector* objectPositions); - - // ------------------------------------------------------------------ - /** Sets the main animation channel to a fixed value - * - * @param fixed Fixed value for the main animation channel*/ - void SetFixedMainAnimationChannel(const aiVector3D& fixed); - - - // ------------------------------------------------------------------ - /** Computes final animation channels - * @param distanceTrack Receive camera translation keys ... != NULL. */ - void Process( std::vector* distanceTrack ); - - -private: - - const std::vector* targetPositions,*objectPositions; - aiVector3D fixedMain; -}; - - -} // ! end namespace Assimp - -#endif // include guard diff --git a/thirdparty/assimp/code/Common/Version.cpp b/thirdparty/assimp/code/Common/Version.cpp deleted file mode 100644 index cf1da7d5ba9e..000000000000 --- a/thirdparty/assimp/code/Common/Version.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* ---------------------------------------------------------------------------- -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. ---------------------------------------------------------------------------- -*/ - -// Actually just a dummy, used by the compiler to build the precompiled header. - -#include -#include -#include "ScenePrivate.h" - -#include "revision.h" - -// -------------------------------------------------------------------------------- -// Legal information string - don't remove this. -static const char* LEGAL_INFORMATION = - -"Open Asset Import Library (Assimp).\n" -"A free C/C++ library to import various 3D file formats into applications\n\n" - -"(c) 2006-2019, assimp team\n" -"License under the terms and conditions of the 3-clause BSD license\n" -"http://assimp.org\n" -; - -// ------------------------------------------------------------------------------------------------ -// Get legal string -ASSIMP_API const char* aiGetLegalString () { - return LEGAL_INFORMATION; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp minor version -ASSIMP_API unsigned int aiGetVersionMinor () { - return VER_MINOR; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp major version -ASSIMP_API unsigned int aiGetVersionMajor () { - return VER_MAJOR; -} - -// ------------------------------------------------------------------------------------------------ -// Get flags used for compilation -ASSIMP_API unsigned int aiGetCompileFlags () { - - unsigned int flags = 0; - -#ifdef ASSIMP_BUILD_BOOST_WORKAROUND - flags |= ASSIMP_CFLAGS_NOBOOST; -#endif -#ifdef ASSIMP_BUILD_SINGLETHREADED - flags |= ASSIMP_CFLAGS_SINGLETHREADED; -#endif -#ifdef ASSIMP_BUILD_DEBUG - flags |= ASSIMP_CFLAGS_DEBUG; -#endif -#ifdef ASSIMP_BUILD_DLL_EXPORT - flags |= ASSIMP_CFLAGS_SHARED; -#endif -#ifdef _STLPORT_VERSION - flags |= ASSIMP_CFLAGS_STLPORT; -#endif - - return flags; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API unsigned int aiGetVersionRevision() { - return GitVersion; -} - -ASSIMP_API const char *aiGetBranchName() { - return GitBranch; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::aiScene() -: mFlags(0) -, mRootNode(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mNumMaterials(0) -, mMaterials(nullptr) -, mNumAnimations(0) -, mAnimations(nullptr) -, mNumTextures(0) -, mTextures(nullptr) -, mNumLights(0) -, mLights(nullptr) -, mNumCameras(0) -, mCameras(nullptr) -, mMetaData(nullptr) -, mPrivate(new Assimp::ScenePrivateData()) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::~aiScene() { - // delete all sub-objects recursively - delete mRootNode; - - // To make sure we won't crash if the data is invalid it's - // much better to check whether both mNumXXX and mXXX are - // valid instead of relying on just one of them. - if (mNumMeshes && mMeshes) - for( unsigned int a = 0; a < mNumMeshes; a++) - delete mMeshes[a]; - delete [] mMeshes; - - if (mNumMaterials && mMaterials) { - for (unsigned int a = 0; a < mNumMaterials; ++a ) { - delete mMaterials[ a ]; - } - } - delete [] mMaterials; - - if (mNumAnimations && mAnimations) - for( unsigned int a = 0; a < mNumAnimations; a++) - delete mAnimations[a]; - delete [] mAnimations; - - if (mNumTextures && mTextures) - for( unsigned int a = 0; a < mNumTextures; a++) - delete mTextures[a]; - delete [] mTextures; - - if (mNumLights && mLights) - for( unsigned int a = 0; a < mNumLights; a++) - delete mLights[a]; - delete [] mLights; - - if (mNumCameras && mCameras) - for( unsigned int a = 0; a < mNumCameras; a++) - delete mCameras[a]; - delete [] mCameras; - - aiMetadata::Dealloc(mMetaData); - mMetaData = nullptr; - - delete static_cast( mPrivate ); -} - diff --git a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp b/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp deleted file mode 100644 index 7cfd1a3505ef..000000000000 --- a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the VertexTriangleAdjacency helper class - */ - -// internal headers -#include "VertexTriangleAdjacency.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, - unsigned int iNumFaces, - unsigned int iNumVertices /*= 0*/, - bool bComputeNumTriangles /*= false*/) -{ - // compute the number of referenced vertices if it wasn't specified by the caller - const aiFace* const pcFaceEnd = pcFaces + iNumFaces; - if (!iNumVertices) { - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { - ai_assert( nullptr != pcFace ); - ai_assert(3 == pcFace->mNumIndices); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]); - } - } - - mNumVertices = iNumVertices; - - unsigned int* pi; - - // allocate storage - if (bComputeNumTriangles) { - pi = mLiveTriangles = new unsigned int[iNumVertices+1]; - ::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1)); - mOffsetTable = new unsigned int[iNumVertices+2]+1; - } else { - pi = mOffsetTable = new unsigned int[iNumVertices+2]+1; - ::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1)); - mLiveTriangles = NULL; // important, otherwise the d'tor would crash - } - - // get a pointer to the end of the buffer - unsigned int* piEnd = pi+iNumVertices; - *piEnd++ = 0u; - - // first pass: compute the number of faces referencing each vertex - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) - { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - if (nind > 0) pi[ind[0]]++; - if (nind > 1) pi[ind[1]]++; - if (nind > 2) pi[ind[2]]++; - } - - // second pass: compute the final offset table - unsigned int iSum = 0; - unsigned int* piCurOut = this->mOffsetTable; - for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) { - - unsigned int iLastSum = iSum; - iSum += *piCur; - *piCurOut = iLastSum; - } - pi = this->mOffsetTable; - - // third pass: compute the final table - this->mAdjacencyTable = new unsigned int[iSum]; - iSum = 0; - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - - if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum; - if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum; - if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum; - } - // fourth pass: undo the offset computations made during the third pass - // We could do this in a separate buffer, but this would be TIMES slower. - --mOffsetTable; - *mOffsetTable = 0u; -} -// ------------------------------------------------------------------------------------------------ -VertexTriangleAdjacency::~VertexTriangleAdjacency() -{ - // delete allocated storage - delete[] mOffsetTable; - delete[] mAdjacencyTable; - delete[] mLiveTriangles; -} diff --git a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h b/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h deleted file mode 100644 index f3be47612da9..000000000000 --- a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -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 Defines a helper class to compute a vertex-triangle adjacency map */ -#ifndef AI_VTADJACENCY_H_INC -#define AI_VTADJACENCY_H_INC - -#include "BaseProcess.h" -#include -#include - -struct aiMesh; -struct aiFace; - -namespace Assimp { - -// -------------------------------------------------------------------------------------------- -/** @brief The VertexTriangleAdjacency class computes a vertex-triangle - * adjacency map from a given index buffer. - * - * @note Although it is called #VertexTriangleAdjacency, the current version does also - * support arbitrary polygons. */ -// -------------------------------------------------------------------------------------------- -class ASSIMP_API VertexTriangleAdjacency { -public: - // ---------------------------------------------------------------------------- - /** @brief Construction from an existing index buffer - * @param pcFaces Index buffer - * @param iNumFaces Number of faces in the buffer - * @param iNumVertices Number of referenced vertices. This value - * is computed automatically if 0 is specified. - * @param bComputeNumTriangles If you want the class to compute - * a list containing the number of referenced triangles per vertex - * per vertex - pass true. */ - VertexTriangleAdjacency(aiFace* pcFaces,unsigned int iNumFaces, - unsigned int iNumVertices = 0, - bool bComputeNumTriangles = true); - - // ---------------------------------------------------------------------------- - /** @brief Destructor */ - ~VertexTriangleAdjacency(); - - // ---------------------------------------------------------------------------- - /** @brief Get all triangles adjacent to a vertex - * @param iVertIndex Index of the vertex - * @return A pointer to the adjacency list. */ - unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const { - ai_assert(iVertIndex < mNumVertices); - return &mAdjacencyTable[ mOffsetTable[iVertIndex]]; - } - - // ---------------------------------------------------------------------------- - /** @brief Get the number of triangles that are referenced by - * a vertex. This function returns a reference that can be modified - * @param iVertIndex Index of the vertex - * @return Number of referenced triangles */ - unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) { - ai_assert( iVertIndex < mNumVertices ); - ai_assert( nullptr != mLiveTriangles ); - return mLiveTriangles[iVertIndex]; - } - - //! Offset table - unsigned int* mOffsetTable; - - //! Adjacency table - unsigned int* mAdjacencyTable; - - //! Table containing the number of referenced triangles per vertex - unsigned int* mLiveTriangles; - - //! Debug: Number of referenced vertices - unsigned int mNumVertices; -}; - -} //! ns Assimp - -#endif // !! AI_VTADJACENCY_H_INC diff --git a/thirdparty/assimp/code/Common/Win32DebugLogStream.h b/thirdparty/assimp/code/Common/Win32DebugLogStream.h deleted file mode 100644 index a6063a261ef3..000000000000 --- a/thirdparty/assimp/code/Common/Win32DebugLogStream.h +++ /dev/null @@ -1,95 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Win32DebugLogStream.h -* @brief Implementation of Win32DebugLogStream -*/ -#ifndef AI_WIN32DEBUGLOGSTREAM_H_INC -#define AI_WIN32DEBUGLOGSTREAM_H_INC - -#ifdef _WIN32 - -#include -#include "windows.h" - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @class Win32DebugLogStream - * @brief Logs into the debug stream from win32. - */ -class Win32DebugLogStream : public LogStream { -public: - /** @brief Default constructor */ - Win32DebugLogStream(); - - /** @brief Destructor */ - ~Win32DebugLogStream(); - - /** @brief Writer */ - void write(const char* messgae); -}; - -// --------------------------------------------------------------------------- -inline -Win32DebugLogStream::Win32DebugLogStream(){ - // empty -} - -// --------------------------------------------------------------------------- -inline -Win32DebugLogStream::~Win32DebugLogStream(){ - // empty -} - -// --------------------------------------------------------------------------- -inline -void Win32DebugLogStream::write(const char* message) { - ::OutputDebugStringA( message); -} - -// --------------------------------------------------------------------------- -} // Namespace Assimp - -#endif // ! _WIN32 -#endif // guard diff --git a/thirdparty/assimp/code/Common/assbin_chunks.h b/thirdparty/assimp/code/Common/assbin_chunks.h deleted file mode 100644 index 15e4af5e7dd5..000000000000 --- a/thirdparty/assimp/code/Common/assbin_chunks.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef INCLUDED_ASSBIN_CHUNKS_H -#define INCLUDED_ASSBIN_CHUNKS_H - -#define ASSBIN_VERSION_MAJOR 1 -#define ASSBIN_VERSION_MINOR 0 - -/** -@page assfile .ASS File formats - -@section over Overview -Assimp provides its own interchange format, which is intended to applications which need -to serialize 3D-models and to reload them quickly. Assimp's file formats are designed to -be read by Assimp itself. They encode additional information needed by Assimp to optimize -its postprocessing pipeline. If you once apply specific steps to a scene, then save it -and reread it from an ASS format using the same post processing settings, they won't -be executed again. - -The format comes in two flavours: XML and binary - both of them hold a complete dump of -the 'aiScene' data structure returned by the APIs. The focus for the binary format -(.assbin) is fast loading. Optional deflate compression helps reduce file size. The XML -flavour, .assxml or simply .xml, is just a plain-to-xml conversion of aiScene. - -ASSBIN is Assimp's binary interchange format. assimp_cmd (<root>/tools/assimp_cmd) is able to -write it and the core library provides a loader for it. - -@section assxml XML File format - -The format is pretty much self-explanatory due to its similarity to the in-memory aiScene structure. -With few exceptions, C structures are wrapped in XML elements. - -The DTD for ASSXML can be found in <root>/doc/AssXML_Scheme.xml. Or have look -at the output files generated by assimp_cmd. - -@section assbin Binary file format - -The ASSBIN file format is composed of chunks to represent the hierarchical aiScene data structure. -This makes the format extensible and allows backward-compatibility with future data structure -versions. The <root>/code/assbin_chunks.h header contains some magic constants -for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found -in <root>/tools/assimp_cmd/WriteDumb.cpp (yes, the 'b' is no typo ...). - -@verbatim - -------------------------------------------------------------------------------- -1. File structure: -------------------------------------------------------------------------------- - ----------------------- -| Header (512 bytes) | ----------------------- -| Variable chunks | ----------------------- - -------------------------------------------------------------------------------- -2. Definitions: -------------------------------------------------------------------------------- - -integer is four bytes wide, stored in little-endian byte order. -short is two bytes wide, stored in little-endian byte order. -byte is a single byte. -string is an integer n followed by n UTF-8 characters, not terminated by zero -float is an IEEE 754 single-precision floating-point value -double is an IEEE 754 double-precision floating-point value -t[n] is an array of n elements of type t - -------------------------------------------------------------------------------- -2. Header: -------------------------------------------------------------------------------- - -byte[44] Magic identification string for ASSBIN files. - 'ASSIMP.binary' - -integer Major version of the Assimp library which wrote the file -integer Minor version of the Assimp library which wrote the file - match these against ASSBIN_VERSION_MAJOR and ASSBIN_VERSION_MINOR - -integer SVN revision of the Assimp library (intended for our internal - debugging - if you write Ass files from your own APPs, set this value to 0. -integer Assimp compile flags - -short 0 for normal files, 1 for shortened dumps for regression tests - these should have the file extension assbin.regress - -short 1 if the data after the header is compressed with the DEFLATE algorithm, - 0 for uncompressed files. - For compressed files, the first integer after the header is - always the uncompressed data size - -byte[256] Zero-terminated source file name, UTF-8 -byte[128] Zero-terminated command line parameters passed to assimp_cmd, UTF-8 - -byte[64] Reserved for future use ----> Total length: 512 bytes - -------------------------------------------------------------------------------- -3. Chunks: -------------------------------------------------------------------------------- - -integer Magic chunk ID (ASSBIN_CHUNK_XXX) -integer Chunk data length, in bytes - (unknown chunks are possible, a good reader skips over them) - (chunk-data-length does not include the first two integers) - -byte[n] chunk-data-length bytes of data, depending on the chunk type - -Chunks can contain nested chunks. Nested chunks are ALWAYS at the end of the chunk, -their size is included in chunk-data-length. - -The chunk layout for all ASSIMP data structures is derived from their C declarations. -The general 'rule' to get from Assimp headers to the serialized layout is: - - 1. POD members (i.e. aiMesh::mPrimitiveTypes, aiMesh::mNumVertices), - in order of declaration. - - 2. Array-members (aiMesh::mFaces, aiMesh::mVertices, aiBone::mWeights), - in order of declaration. - - 2. Object array members (i.e aiMesh::mBones, aiScene::mMeshes) are stored in - subchunks directly following the data written in 1.) and 2.) - - - Of course, there are some exceptions to this general order: - -[[aiScene]] - - - The root node holding the scene structure is naturally stored in - a ASSBIN_CHUNK_AINODE subchunk following 1.) and 2.) (which is - empty for aiScene). - -[[aiMesh]] - - - mTextureCoords and mNumUVComponents are serialized as follows: - - [number of used uv channels times] - integer mNumUVComponents[n] - float mTextureCoords[n][3] - - -> more than AI_MAX_TEXCOORD_CHANNELS can be stored. This allows Assimp - builds with different settings for AI_MAX_TEXCOORD_CHANNELS to exchange - data. - -> the on-disk format always uses 3 floats to write UV coordinates. - If mNumUVComponents[0] is 1, the corresponding mTextureCoords array - consists of 3 floats. - - - The array member block of aiMesh is prefixed with an integer that specifies - the kinds of vertex components actually present in the mesh. This is a - bitwise combination of the ASSBIN_MESH_HAS_xxx constants. - -[[aiFace]] - - - mNumIndices is stored as short - - mIndices are written as short, if aiMesh::mNumVertices<65536 - -[[aiNode]] - - - mParent is omitted - -[[aiLight]] - - - mAttenuationXXX not written if aiLight::mType == aiLightSource_DIRECTIONAL - - mAngleXXX not written if aiLight::mType != aiLightSource_SPOT - -[[aiMaterial]] - - - mNumAllocated is omitted, for obvious reasons :-) - - - @endverbatim*/ - - -#define ASSBIN_HEADER_LENGTH 512 - -// these are the magic chunk identifiers for the binary ASS file format -#define ASSBIN_CHUNK_AICAMERA 0x1234 -#define ASSBIN_CHUNK_AILIGHT 0x1235 -#define ASSBIN_CHUNK_AITEXTURE 0x1236 -#define ASSBIN_CHUNK_AIMESH 0x1237 -#define ASSBIN_CHUNK_AINODEANIM 0x1238 -#define ASSBIN_CHUNK_AISCENE 0x1239 -#define ASSBIN_CHUNK_AIBONE 0x123a -#define ASSBIN_CHUNK_AIANIMATION 0x123b -#define ASSBIN_CHUNK_AINODE 0x123c -#define ASSBIN_CHUNK_AIMATERIAL 0x123d -#define ASSBIN_CHUNK_AIMATERIALPROPERTY 0x123e - -#define ASSBIN_MESH_HAS_POSITIONS 0x1 -#define ASSBIN_MESH_HAS_NORMALS 0x2 -#define ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS 0x4 -#define ASSBIN_MESH_HAS_TEXCOORD_BASE 0x100 -#define ASSBIN_MESH_HAS_COLOR_BASE 0x10000 - -#define ASSBIN_MESH_HAS_TEXCOORD(n) (ASSBIN_MESH_HAS_TEXCOORD_BASE << n) -#define ASSBIN_MESH_HAS_COLOR(n) (ASSBIN_MESH_HAS_COLOR_BASE << n) - - -#endif // INCLUDED_ASSBIN_CHUNKS_H diff --git a/thirdparty/assimp/code/Common/scene.cpp b/thirdparty/assimp/code/Common/scene.cpp deleted file mode 100644 index d15619acff8a..000000000000 --- a/thirdparty/assimp/code/Common/scene.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* ---------------------------------------------------------------------------- -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. ---------------------------------------------------------------------------- -*/ -#include - -aiNode::aiNode() -: mName("") -, mParent(nullptr) -, mNumChildren(0) -, mChildren(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mMetaData(nullptr) { - // empty -} - -aiNode::aiNode(const std::string& name) -: mName(name) -, mParent(nullptr) -, mNumChildren(0) -, mChildren(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mMetaData(nullptr) { - // empty -} - -/** Destructor */ -aiNode::~aiNode() { - // delete all children recursively - // to make sure we won't crash if the data is invalid ... - if (mNumChildren && mChildren) - { - for (unsigned int a = 0; a < mNumChildren; a++) - delete mChildren[a]; - } - delete[] mChildren; - delete[] mMeshes; - delete mMetaData; -} - -const aiNode *aiNode::FindNode(const char* name) const { - if (nullptr == name) { - return nullptr; - } - if (!::strcmp(mName.data, name)) { - return this; - } - for (unsigned int i = 0; i < mNumChildren; ++i) { - const aiNode* const p = mChildren[i]->FindNode(name); - if (p) { - return p; - } - } - // there is definitely no sub-node with this name - return nullptr; -} - -aiNode *aiNode::FindNode(const char* name) { - if (!::strcmp(mName.data, name))return this; - for (unsigned int i = 0; i < mNumChildren; ++i) - { - aiNode* const p = mChildren[i]->FindNode(name); - if (p) { - return p; - } - } - // there is definitely no sub-node with this name - return nullptr; -} - -void aiNode::addChildren(unsigned int numChildren, aiNode **children) { - if (nullptr == children || 0 == numChildren) { - return; - } - - for (unsigned int i = 0; i < numChildren; i++) { - aiNode *child = children[i]; - if (nullptr != child) { - child->mParent = this; - } - } - - if (mNumChildren > 0) { - aiNode **tmp = new aiNode*[mNumChildren]; - ::memcpy(tmp, mChildren, sizeof(aiNode*) * mNumChildren); - delete[] mChildren; - mChildren = new aiNode*[mNumChildren + numChildren]; - ::memcpy(mChildren, tmp, sizeof(aiNode*) * mNumChildren); - ::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode*)* numChildren); - mNumChildren += numChildren; - delete[] tmp; - } - else { - mChildren = new aiNode*[numChildren]; - for (unsigned int i = 0; i < numChildren; i++) { - mChildren[i] = children[i]; - } - mNumChildren = numChildren; - } -} diff --git a/thirdparty/assimp/code/Common/simd.cpp b/thirdparty/assimp/code/Common/simd.cpp deleted file mode 100644 index 04615f408eb8..000000000000 --- a/thirdparty/assimp/code/Common/simd.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* ---------------------------------------------------------------------------- -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. ---------------------------------------------------------------------------- -*/ -#include "simd.h" - -namespace Assimp { - -bool CPUSupportsSSE2() { -#if defined(__x86_64__) || defined(_M_X64) - //* x86_64 always has SSE2 instructions */ - return true; -#elif defined(__GNUC__) && defined(i386) - // for GCC x86 we check cpuid - unsigned int d; - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - : "=d" ( d ) - :"a" ( 1 ) ); - return ( d & 0x04000000 ) != 0; -#elif (defined(_MSC_VER) && defined(_M_IX86)) - // also check cpuid for MSVC x86 - unsigned int d; - __asm { - xor eax, eax - inc eax - push ebx - cpuid - pop ebx - mov d, edx - } - return ( d & 0x04000000 ) != 0; -#else - return false; -#endif -} - - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/Common/simd.h b/thirdparty/assimp/code/Common/simd.h deleted file mode 100644 index 3eecdd458139..000000000000 --- a/thirdparty/assimp/code/Common/simd.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ---------------------------------------------------------------------------- -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. ---------------------------------------------------------------------------- -*/ -#pragma once - -#include - -namespace Assimp { - -/// @brief Checks if the platform supports SSE2 optimization -/// @return true, if SSE2 is supported. false if SSE2 is not supported. -bool ASSIMP_API CPUSupportsSSE2(); - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/FBX/FBXAnimation.cpp b/thirdparty/assimp/code/FBX/FBXAnimation.cpp deleted file mode 100644 index 874914431b91..000000000000 --- a/thirdparty/assimp/code/FBX/FBXAnimation.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/) -: Object(id, element, name) -{ - const Scope& sc = GetRequiredScope(element); - const Element& KeyTime = GetRequiredElement(sc,"KeyTime"); - const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat"); - - 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); - } - - // check if the key times are well-ordered - if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less())) { - DOMError("the keyframes are not in ascending order",&KeyTime); - } - - const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"]; - if(KeyAttrDataFloat) { - ParseVectorDataArray(attributes, *KeyAttrDataFloat); - } - - const Element* KeyAttrFlags = sc["KeyAttrFlags"]; - if(KeyAttrFlags) { - ParseVectorDataArray(flags, *KeyAttrFlags); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::~AnimationCurve() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& 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 Scope& sc = GetRequiredScope(element); - - // find target node - const char* whitelist[] = {"Model","NodeAttribute","Deformer"}; - const std::vector& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3); - - for(const Connection* con : conns) { - - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } - - if(target_prop_whitelist) { - const char* const s = con->PropertyName().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) { - throw std::range_error("AnimationCurveNode target property is not in whitelist"); - } - } - - const Object* const ob = con->DestinationObject(); - if(!ob) { - DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element); - continue; - } - - // XXX support constraints as DOM class - //ai_assert(dynamic_cast(ob) || dynamic_cast(ob)); - target = ob; - if(!target) { - continue; - } - - prop = con->PropertyName(); - break; - } - - if(!target) { - DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element); - } - - props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false); -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::~AnimationCurveNode() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const AnimationCurveMap& AnimationCurveNode::Curves() const -{ - if ( curves.empty() ) { - // resolve attached animation curves - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve"); - - for(const Connection* con : conns) { - - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element); - continue; - } - - const AnimationCurve* const anim = dynamic_cast(ob); - if(!anim) { - DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element); - continue; - } - - curves[con->PropertyName()] = anim; - } - } - - return curves; -} - -// ------------------------------------------------------------------------------------------------ -AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Object(id, element, name) -, doc(doc) -{ - const Scope& 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 -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/, - size_t whitelist_size /*= 0*/) const -{ - AnimationCurveNodeList nodes; - - // resolve attached animation nodes - const std::vector& 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; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element); - continue; - } - - const AnimationCurveNode* const anim = dynamic_cast(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; // pray for NRVO -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Object(id, element, name) -{ - const Scope& 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& 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; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element); - continue; - } - - const AnimationLayer* const anim = dynamic_cast(ob); - if(!anim) { - DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element); - continue; - } - layers.push_back(anim); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::~AnimationStack() -{ - // empty -} - -} //!FBX -} //!Assimp - -#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp deleted file mode 100644 index a4a2bc8e7976..000000000000 --- a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* -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. - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXTokenizer.h" -#include "FBXUtil.h" -#include -#include -#include -#include - -namespace Assimp { -namespace FBX { - -//enum Flag -//{ -// e_unknown_0 = 1 << 0, -// e_unknown_1 = 1 << 1, -// e_unknown_2 = 1 << 2, -// e_unknown_3 = 1 << 3, -// e_unknown_4 = 1 << 4, -// e_unknown_5 = 1 << 5, -// e_unknown_6 = 1 << 6, -// e_unknown_7 = 1 << 7, -// e_unknown_8 = 1 << 8, -// e_unknown_9 = 1 << 9, -// e_unknown_10 = 1 << 10, -// e_unknown_11 = 1 << 11, -// e_unknown_12 = 1 << 12, -// e_unknown_13 = 1 << 13, -// e_unknown_14 = 1 << 14, -// e_unknown_15 = 1 << 15, -// e_unknown_16 = 1 << 16, -// e_unknown_17 = 1 << 17, -// e_unknown_18 = 1 << 18, -// e_unknown_19 = 1 << 19, -// e_unknown_20 = 1 << 20, -// e_unknown_21 = 1 << 21, -// e_unknown_22 = 1 << 22, -// e_unknown_23 = 1 << 23, -// e_flag_field_size_64_bit = 1 << 24, // Not sure what is -// e_unknown_25 = 1 << 25, -// e_unknown_26 = 1 << 26, -// e_unknown_27 = 1 << 27, -// e_unknown_28 = 1 << 28, -// e_unknown_29 = 1 << 29, -// e_unknown_30 = 1 << 30, -// e_unknown_31 = 1 << 31 -//}; -// -//bool check_flag(uint32_t flags, Flag to_check) -//{ -// return (flags & to_check) != 0; -//} -// ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) - : - #ifdef DEBUG - contents(sbegin, static_cast(send-sbegin)), - #endif - sbegin(sbegin) - , send(send) - , type(type) - , line(offset) - , column(BINARY_MARKER) -{ - ai_assert(sbegin); - ai_assert(send); - - // binary tokens may have zero length because they are sometimes dummies - // inserted by TokenizeBinary() - ai_assert(send >= sbegin); -} - - -namespace { - -// ------------------------------------------------------------------------------------------------ -// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. -AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) -{ - throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,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(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: - ai_assert(false); - }; - 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) -{ - ai_assert(input); - - if(length < 0x1b) { - TokenizeError("file is too short",0); - } - - //uint32_t offset = 0x15; -/* const char* cursor = input + 0x15; - - const uint32_t flags = ReadWord(input, cursor, input + length); - - const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused - const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/ - - 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); - const bool is64bits = version >= 7500; - const char *end = input + length; - while (cursor < end ) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { - break; - } - } -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXCompileConfig.h b/thirdparty/assimp/code/FBX/FBXCompileConfig.h deleted file mode 100644 index 03536a182344..000000000000 --- a/thirdparty/assimp/code/FBX/FBXCompileConfig.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -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 FBXCompileConfig.h - * @brief FBX importer compile-time switches - */ -#ifndef INCLUDED_AI_FBX_COMPILECONFIG_H -#define INCLUDED_AI_FBX_COMPILECONFIG_H - -#include -#include - -// -#if _MSC_VER > 1500 || (defined __GNUC___) -# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP -# else -# define fbx_unordered_map map -# define fbx_unordered_multimap multimap -# define fbx_unordered_set set -# define fbx_unordered_multiset multiset -#endif - -#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP -# include -# include -# if _MSC_VER > 1600 -# define fbx_unordered_map unordered_map -# define fbx_unordered_multimap unordered_multimap -# define fbx_unordered_set unordered_set -# define fbx_unordered_multiset unordered_multiset -# else -# define fbx_unordered_map tr1::unordered_map -# define fbx_unordered_multimap tr1::unordered_multimap -# define fbx_unordered_set tr1::unordered_set -# define fbx_unordered_multiset tr1::unordered_multiset -# endif -#endif - -#endif // INCLUDED_AI_FBX_COMPILECONFIG_H diff --git a/thirdparty/assimp/code/FBX/FBXConverter.cpp b/thirdparty/assimp/code/FBX/FBXConverter.cpp deleted file mode 100644 index d8a22d9f741a..000000000000 --- a/thirdparty/assimp/code/FBX/FBXConverter.cpp +++ /dev/null @@ -1,3727 +0,0 @@ -/* -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 FBXConverter.cpp - * @brief Implementation of the FBX DOM -> aiScene converter - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXConverter.h" -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" -#include "FBXImporter.h" - -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Assimp { - namespace FBX { - - using namespace Util; - -#define MAGIC_NODE_TAG "_$AssimpFbx$" - -#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL - - FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones ) - : defaultMaterialIndex() - , lights() - , cameras() - , textures() - , materials_converted() - , textures_converted() - , meshes_converted() - , node_anim_chain_bits() - , mNodeNames() - , anim_fps() - , out(out) - , doc(doc) { - // animations need to be converted first since this will - // populate the node_anim_chain_bits map, which is needed - // to determine which nodes need to be generated. - ConvertAnimations(); - // Embedded textures in FBX could be connected to nothing but to itself, - // for instance Texture -> Video connection only but not to the main graph, - // The idea here is to traverse all objects to find these Textures and convert them, - // so later during material conversion it will find converted texture in the textures_converted array. - if (doc.Settings().readTextures) - { - ConvertOrphantEmbeddedTextures(); - } - ConvertRootNode(); - - if (doc.Settings().readAllMaterials) { - // unfortunately this means we have to evaluate all objects - for (const ObjectMap::value_type& v : doc.Objects()) { - - const Object* ob = v.second->Get(); - if (!ob) { - continue; - } - - const Material* mat = dynamic_cast(ob); - if (mat) { - - if (materials_converted.find(mat) == materials_converted.end()) { - ConvertMaterial(*mat, 0); - } - } - } - } - - ConvertGlobalSettings(); - TransferDataToScene(); - - // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE - // to make sure the scene passes assimp's validation. FBX files - // need not contain geometry (i.e. camera animations, raw armatures). - if (out->mNumMeshes == 0) { - out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - } - - - FBXConverter::~FBXConverter() { - std::for_each(meshes.begin(), meshes.end(), Util::delete_fun()); - std::for_each(materials.begin(), materials.end(), Util::delete_fun()); - std::for_each(animations.begin(), animations.end(), Util::delete_fun()); - std::for_each(lights.begin(), lights.end(), Util::delete_fun()); - std::for_each(cameras.begin(), cameras.end(), Util::delete_fun()); - std::for_each(textures.begin(), textures.end(), Util::delete_fun()); - } - - void FBXConverter::ConvertRootNode() { - out->mRootNode = new aiNode(); - std::string unique_name; - GetUniqueName("RootNode", unique_name); - out->mRootNode->mName.Set(unique_name); - - // root has ID 0 - ConvertNodes(0L, out->mRootNode, out->mRootNode); - } - - static std::string getAncestorBaseName(const aiNode* node) - { - const char* nodeName = nullptr; - size_t length = 0; - while (node && (!nodeName || length == 0)) - { - nodeName = node->mName.C_Str(); - length = node->mName.length; - node = node->mParent; - } - - if (!nodeName || length == 0) - { - return {}; - } - // could be std::string_view if c++17 available - return std::string(nodeName, length); - } - - // Make unique name - std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent) - { - std::string original_name = FixNodeName(model->Name()); - if (original_name.empty()) - { - original_name = getAncestorBaseName(&parent); - } - std::string unique_name; - GetUniqueName(original_name, unique_name); - return unique_name; - } - /// todo: pre-build node hierarchy - /// todo: get bone from stack - /// todo: make map of aiBone* to aiNode* - /// then update convert clusters to the new format - void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); - - std::vector nodes; - nodes.reserve(conns.size()); - - std::vector nodes_chain; - std::vector post_nodes_chain; - - try { - for (const Connection* con : conns) { - // ignore object-property links - if (con->PropertyName().length()) { - // really important we document why this is ignored. - FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); - continue; //? - } - - // convert connection source object into Object base class - const Object* const object = con->SourceObject(); - if (nullptr == object) { - FBXImporter::LogError("failed to convert source object for Model link"); - continue; - } - - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const Model* const model = dynamic_cast(object); - - if (nullptr != model) { - nodes_chain.clear(); - post_nodes_chain.clear(); - - aiMatrix4x4 new_abs_transform = parent->mTransformation; - std::string node_name = FixNodeName(model->Name()); - // even though there is only a single input node, the design of - // assimp (or rather: the complicated transformation chain that - // is employed by fbx) means that we may need multiple aiNode's - // to represent a fbx node's transformation. - - - // generate node transforms - this includes pivot data - // if need_additional_node is true then you t - const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); - - // assert that for the current node we must have at least a single transform - ai_assert(nodes_chain.size()); - - if (need_additional_node) { - nodes_chain.push_back(new aiNode(node_name)); - } - - //setup metadata on newest node - SetupNodeMetadata(*model, *nodes_chain.back()); - - // link all nodes in a row - aiNode* last_parent = parent; - for (aiNode* child : nodes_chain) { - ai_assert(child); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = child; - } - - child->mParent = last_parent; - last_parent = child; - - new_abs_transform *= child->mTransformation; - } - - // attach geometry - ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); - - // check if there will be any child nodes - const std::vector& child_conns - = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); - - // if so, link the geometric transform inverse nodes - // before we attach any child nodes - if (child_conns.size()) { - for (aiNode* postnode : post_nodes_chain) { - ai_assert(postnode); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = postnode; - } - - postnode->mParent = last_parent; - last_parent = postnode; - - new_abs_transform *= postnode->mTransformation; - } - } - else { - // free the nodes we allocated as we don't need them - Util::delete_fun deleter; - std::for_each( - post_nodes_chain.begin(), - post_nodes_chain.end(), - deleter - ); - } - - // recursion call - child nodes - ConvertNodes(model->ID(), last_parent, root_node); - - if (doc.Settings().readLights) { - ConvertLights(*model, node_name); - } - - if (doc.Settings().readCameras) { - ConvertCameras(*model, node_name); - } - - nodes.push_back(nodes_chain.front()); - nodes_chain.clear(); - } - } - - if (nodes.size()) { - parent->mChildren = new aiNode*[nodes.size()](); - parent->mNumChildren = static_cast(nodes.size()); - - std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); - } - else - { - parent->mNumChildren = 0; - parent->mChildren = nullptr; - } - - } - catch (std::exception&) { - Util::delete_fun deleter; - std::for_each(nodes.begin(), nodes.end(), deleter); - std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); - std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); - } - } - - - void FBXConverter::ConvertLights(const Model& model, const std::string &orig_name) { - const std::vector& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Light* const light = dynamic_cast(attr); - if (light) { - ConvertLight(*light, orig_name); - } - } - } - - void FBXConverter::ConvertCameras(const Model& model, const std::string &orig_name) { - const std::vector& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Camera* const cam = dynamic_cast(attr); - if (cam) { - ConvertCamera(*cam, orig_name); - } - } - } - - void FBXConverter::ConvertLight(const Light& light, const std::string &orig_name) { - lights.push_back(new aiLight()); - aiLight* const out_light = lights.back(); - - out_light->mName.Set(orig_name); - - const float intensity = light.Intensity() / 100.0f; - const aiVector3D& col = light.Color(); - - out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z); - out_light->mColorDiffuse.r *= intensity; - out_light->mColorDiffuse.g *= intensity; - out_light->mColorDiffuse.b *= intensity; - - out_light->mColorSpecular = out_light->mColorDiffuse; - - //lights are defined along negative y direction - out_light->mPosition = aiVector3D(0.0f); - out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); - out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); - - switch (light.LightType()) - { - case Light::Type_Point: - out_light->mType = aiLightSource_POINT; - break; - - case Light::Type_Directional: - out_light->mType = aiLightSource_DIRECTIONAL; - break; - - case Light::Type_Spot: - out_light->mType = aiLightSource_SPOT; - out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); - out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); - break; - - case Light::Type_Area: - FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - - case Light::Type_Volume: - FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - default: - ai_assert(false); - } - - float decay = light.DecayStart(); - switch (light.DecayType()) - { - case Light::Decay_None: - out_light->mAttenuationConstant = decay; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Linear: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 2.0f / decay; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Quadratic: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 2.0f / (decay * decay); - break; - case Light::Decay_Cubic: - FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); - out_light->mAttenuationQuadratic = 1.0f; - break; - default: - ai_assert(false); - break; - } - } - - void FBXConverter::ConvertCamera(const Camera& cam, const std::string &orig_name) - { - cameras.push_back(new aiCamera()); - aiCamera* const out_camera = cameras.back(); - - out_camera->mName.Set(orig_name); - - out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); - - out_camera->mPosition = aiVector3D(0.0f); - out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); - out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - } - - void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) - { - uniqueName = name; - auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count - unsigned int& i = it_pair.first->second; - while (!it_pair.second) - { - i++; - std::ostringstream ext; - ext << name << std::setfill('0') << std::setw(3) << i; - uniqueName = ext.str(); - it_pair = mNodeNames.insert({ uniqueName, 0 }); - } - } - - const char* FBXConverter::NameTransformationComp(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - default: - break; - } - - ai_assert(false); - - return nullptr; - } - - const char* FBXConverter::NameTransformationCompProperty(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Lcl Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Lcl Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Lcl Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - break; - } - - ai_assert(false); - - return nullptr; - } - - aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp) - { - // XXX a neat way to solve the never-ending special cases for scaling - // would be to do everything in log space! - return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D(); - } - - void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out) - { - if (mode == Model::RotOrder_SphericXYZ) { - FBXImporter::LogError("Unsupported RotationMode: SphericXYZ"); - out = aiMatrix4x4(); - return; - } - - const float angle_epsilon = Math::getEpsilon(); - - out = aiMatrix4x4(); - - bool is_id[3] = { true, true, true }; - - aiMatrix4x4 temp[3]; - if (std::fabs(rotation.z) > angle_epsilon) { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); - is_id[2] = false; - } - if (std::fabs(rotation.y) > angle_epsilon) { - aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); - is_id[1] = false; - } - if (std::fabs(rotation.x) > angle_epsilon) { - aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); - is_id[0] = false; - } - - int order[3] = { -1, -1, -1 }; - - // note: rotation order is inverted since we're left multiplying as is usual in assimp - switch (mode) - { - case Model::RotOrder_EulerXYZ: - order[0] = 2; - order[1] = 1; - order[2] = 0; - break; - - case Model::RotOrder_EulerXZY: - order[0] = 1; - order[1] = 2; - order[2] = 0; - break; - - case Model::RotOrder_EulerYZX: - order[0] = 0; - order[1] = 2; - order[2] = 1; - break; - - case Model::RotOrder_EulerYXZ: - order[0] = 2; - order[1] = 0; - order[2] = 1; - break; - - case Model::RotOrder_EulerZXY: - order[0] = 1; - order[1] = 0; - order[2] = 2; - break; - - case Model::RotOrder_EulerZYX: - order[0] = 0; - order[1] = 1; - order[2] = 2; - break; - - default: - ai_assert(false); - break; - } - - ai_assert(order[0] >= 0); - ai_assert(order[0] <= 2); - ai_assert(order[1] >= 0); - ai_assert(order[1] <= 2); - ai_assert(order[2] >= 0); - ai_assert(order[2] <= 2); - - if (!is_id[order[0]]) { - out = temp[order[0]]; - } - - if (!is_id[order[1]]) { - out = out * temp[order[1]]; - } - - if (!is_id[order[2]]) { - out = out * temp[order[2]]; - } - } - - bool FBXConverter::NeedsComplexTransformationChain(const Model& model) - { - const PropertyTable& props = model.Props(); - bool ok; - - const float zero_epsilon = 1e-6f; - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { - const TransformationComp comp = static_cast(i); - - if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { - continue; - } - - bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); - - const aiVector3D& v = PropertyGet(props, NameTransformationCompProperty(comp), ok); - if (ok && scale_compare) { - if ((v - all_ones).SquareLength() > zero_epsilon) { - return true; - } - } else if (ok) { - if (v.SquareLength() > zero_epsilon) { - return true; - } - } - } - - return false; - } - - std::string FBXConverter::NameTransformationChainNode(const std::string& name, TransformationComp comp) - { - return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); - } - - bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, - std::vector& post_output_nodes) { - const PropertyTable& props = model.Props(); - const Model::RotOrder rot = model.RotationOrder(); - - bool ok; - - aiMatrix4x4 chain[TransformationComp_MAXIMUM]; - - ai_assert(TransformationComp_MAXIMUM < 32); - std::uint32_t chainBits = 0; - // A node won't need a node chain if it only has these. - const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation); - // A node will need a node chain if it has any of these. - const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple; - - std::fill_n(chain, static_cast(TransformationComp_MAXIMUM), aiMatrix4x4()); - - // generate transformation matrices for all the different transformation components - const float zero_epsilon = Math::getEpsilon(); - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - - const aiVector3D& PreRotation = PropertyGet(props, "PreRotation", ok); - if (ok && PreRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PreRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]); - } - - const aiVector3D& PostRotation = PropertyGet(props, "PostRotation", ok); - if (ok && PostRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PostRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]); - } - - const aiVector3D& RotationPivot = PropertyGet(props, "RotationPivot", ok); - if (ok && RotationPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse); - - aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); - aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); - } - - const aiVector3D& RotationOffset = PropertyGet(props, "RotationOffset", ok); - if (ok && RotationOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationOffset); - - aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); - } - - const aiVector3D& ScalingOffset = PropertyGet(props, "ScalingOffset", ok); - if (ok && ScalingOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingOffset); - - aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); - } - - const aiVector3D& ScalingPivot = PropertyGet(props, "ScalingPivot", ok); - if (ok && ScalingPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse); - - aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); - aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); - } - - const aiVector3D& Translation = PropertyGet(props, "Lcl Translation", ok); - if (ok && Translation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Translation); - - aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]); - } - - const aiVector3D& Scaling = PropertyGet(props, "Lcl Scaling", ok); - if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Scaling); - - aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]); - } - - const aiVector3D& Rotation = PropertyGet(props, "Lcl Rotation", ok); - if (ok && Rotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Rotation); - - GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]); - } - - const aiVector3D& GeometricScaling = PropertyGet(props, "GeometricScaling", ok); - if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricScaling); - aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); - aiVector3D GeometricScalingInverse = GeometricScaling; - bool canscale = true; - for (unsigned int i = 0; i < 3; ++i) { - if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) { - GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; - } - else { - FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component"); - canscale = false; - break; - } - } - if (canscale) { - chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse); - aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); - } - } - - const aiVector3D& GeometricRotation = PropertyGet(props, "GeometricRotation", ok); - if (ok && GeometricRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); - chain[TransformationComp_GeometricRotationInverse].Inverse(); - } - - const aiVector3D& GeometricTranslation = PropertyGet(props, "GeometricTranslation", ok); - if (ok && GeometricTranslation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse); - aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); - aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); - } - - // is_complex needs to be consistent with NeedsComplexTransformationChain() - // or the interplay between this code and the animation converter would - // not be guaranteed. - //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0)); - - // now, if we have more than just Translation, Scaling and Rotation, - // we need to generate a full node chain to accommodate for assimp's - // lack to express pivots and offsets. - if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) { - FBXImporter::LogInfo("generating full transformation chain for node: " + name); - - // query the anim_chain_bits dictionary to find out which chain elements - // have associated node animation channels. These can not be dropped - // even if they have identity transform in bind pose. - NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name); - const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second); - - unsigned int bit = 0x1; - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { - const TransformationComp comp = static_cast(i); - - if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) { - continue; - } - - if (comp == TransformationComp_PostRotation) { - chain[i] = chain[i].Inverse(); - } - - aiNode* nd = new aiNode(); - nd->mName.Set(NameTransformationChainNode(name, comp)); - nd->mTransformation = chain[i]; - - // geometric inverses go in a post-node chain - if (comp == TransformationComp_GeometricScalingInverse || - comp == TransformationComp_GeometricRotationInverse || - comp == TransformationComp_GeometricTranslationInverse - ) { - post_output_nodes.push_back(nd); - } - else { - output_nodes.push_back(nd); - } - } - - ai_assert(output_nodes.size()); - return true; - } - - // else, we can just multiply the matrices together - aiNode* nd = new aiNode(); - output_nodes.push_back(nd); - - // name passed to the method is already unique - nd->mName.Set(name); - - for (const auto &transform : chain) { - nd->mTransformation = nd->mTransformation * transform; - } - return false; - } - - void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd) - { - const PropertyTable& props = model.Props(); - DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); - - // create metadata on node - const std::size_t numStaticMetaData = 2; - aiMetadata* data = aiMetadata::Alloc(static_cast(unparsedProperties.size() + numStaticMetaData)); - nd.mMetaData = data; - int index = 0; - - // find user defined properties (3ds Max) - data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); - // preserve the info that a node was marked as Null node in the original file. - data->Set(index++, "IsNull", model.IsNull() ? true : false); - - // add unparsed properties to the node's metadata - for (const DirectPropertyMap::value_type& prop : unparsedProperties) { - // Interpret the property as a concrete type - if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, aiString(interpreted->Value())); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else { - ai_assert(false); - } - } - } - - void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const std::vector& geos = model.GetGeometry(); - - std::vector meshes; - meshes.reserve(geos.size()); - - for (const Geometry* geo : geos) { - - const MeshGeometry* const mesh = dynamic_cast(geo); - const LineGeometry* const line = dynamic_cast(geo); - if (mesh) { - const std::vector& indices = ConvertMesh(*mesh, model, parent, root_node, - absolute_transform); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else if (line) { - const std::vector& indices = ConvertLine(*line, model, parent, root_node); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else { - FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name()); - } - } - - if (meshes.size()) { - parent->mMeshes = new unsigned int[meshes.size()](); - parent->mNumMeshes = static_cast(meshes.size()); - - std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes); - } - } - - std::vector - FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - std::vector temp; - - MeshMap::const_iterator it = meshes_converted.find(&mesh); - if (it != meshes_converted.end()) { - std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp)); - return temp; - } - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - if (vertices.empty() || faces.empty()) { - FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name()); - return temp; - } - - // one material per mesh maps easily to aiMesh. Multiple material - // meshes need to be split. - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - if (doc.Settings().readMaterials && !mindices.empty()) { - const MatIndexArray::value_type base = mindices[0]; - for (MatIndexArray::value_type index : mindices) { - if (index != base) { - return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform); - } - } - } - - // faster code-path, just copy the data - temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node)); - return temp; - } - - std::vector FBXConverter::ConvertLine(const LineGeometry& line, const Model& model, - aiNode *parent, aiNode *root_node) - { - std::vector temp; - - const std::vector& vertices = line.GetVertices(); - const std::vector& indices = line.GetIndices(); - if (vertices.empty() || indices.empty()) { - FBXImporter::LogWarn("ignoring empty line: " + line.Name()); - return temp; - } - - aiMesh* const out_mesh = SetupEmptyMesh(line, root_node); - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - - // copy vertices - out_mesh->mNumVertices = static_cast(vertices.size()); - out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices]; - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - //Number of line segments (faces) is "Number of Points - Number of Endpoints" - //N.B.: Endpoints in FbxLine are denoted by negative indices. - //If such an Index is encountered, add 1 and multiply by -1 to get the real index. - unsigned int epcount = 0; - for (unsigned i = 0; i < indices.size(); i++) - { - if (indices[i] < 0) { - epcount++; - } - } - unsigned int pcount = static_cast( indices.size() ); - unsigned int scount = out_mesh->mNumFaces = pcount - epcount; - - aiFace* fac = out_mesh->mFaces = new aiFace[scount](); - for (unsigned int i = 0; i < pcount; ++i) { - if (indices[i] < 0) continue; - aiFace& f = *fac++; - f.mNumIndices = 2; //2 == aiPrimitiveType_LINE - f.mIndices = new unsigned int[2]; - f.mIndices[0] = indices[i]; - int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around - f.mIndices[1] = (segid < 0 ? (segid + 1)*-1 : segid); //Convert EndPoint Index to normal Index - } - temp.push_back(static_cast(meshes.size() - 1)); - return temp; - } - - aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent) - { - aiMesh* const out_mesh = new aiMesh(); - meshes.push_back(out_mesh); - meshes_converted[&mesh].push_back(static_cast(meshes.size() - 1)); - - // set name - std::string name = mesh.Name(); - if (name.substr(0, 10) == "Geometry::") { - name = name.substr(10); - } - - if (name.length()) { - out_mesh->mName.Set(name); - } - else - { - out_mesh->mName = parent->mName; - } - - return out_mesh; - } - - unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, - const aiMatrix4x4 &absolute_transform, aiNode *parent, - aiNode *root_node) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - // copy vertices - out_mesh->mNumVertices = static_cast(vertices.size()); - out_mesh->mVertices = new aiVector3D[vertices.size()]; - - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - // generate dummy faces - out_mesh->mNumFaces = static_cast(faces.size()); - aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()](); - - unsigned int cursor = 0; - for (unsigned int pcount : faces) { - aiFace& f = *fac++; - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i) { - f.mIndices[i] = cursor++; - } - } - - // copy normals - const std::vector& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - - out_mesh->mNormals = new aiVector3D[vertices.size()]; - std::copy(normals.begin(), normals.end(), out_mesh->mNormals); - } - - // copy tangents - assimp requires both tangents and bitangents (binormals) - // to be present, or neither of them. Compute binormals from normals - // and tangents if needed. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - - if (tangents.size()) { - std::vector tempBinormals; - if (!binormals->size()) { - if (normals.size()) { - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size()); - ai_assert(binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents); - - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents); - } - } - - // copy texture coords - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - const std::vector& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - aiVector3D* out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - for (const aiVector2D& v : uvs) { - *out_uv++ = aiVector3D(v.x, v.y, 0.0f); - } - - out_mesh->mNumUVComponents[i] = 2; - } - - // copy vertex colors - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { - const std::vector& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]); - } - - if (!doc.Settings().readMaterials || mindices.empty()) { - FBXImporter::LogError("no material assigned to mesh, setting default material"); - out_mesh->mMaterialIndex = GetDefaultMaterial(); - } - else { - ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); - } - - if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION, - nullptr); - } - - std::vector animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector& vertices = shapeGeometry->GetVertices(); - const std::vector& normals = shapeGeometry->GetNormals(); - const std::vector& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int index = outIndices[k]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - return static_cast(meshes.size() - 1); - } - - std::vector - FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, - aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - ai_assert(mindices.size()); - - std::set had; - std::vector indices; - - for (MatIndexArray::value_type index : mindices) { - if (had.find(index) == had.end()) { - - indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform)); - had.insert(index); - } - } - - return indices; - } - - unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, - MatIndexArray::value_type index, - aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr; - - unsigned int count_faces = 0; - unsigned int count_vertices = 0; - - // count faces - std::vector::const_iterator itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), - end = mindices.end(); it != end; ++it, ++itf) - { - if ((*it) != index) { - continue; - } - ++count_faces; - count_vertices += *itf; - } - - ai_assert(count_faces); - ai_assert(count_vertices); - - // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes - std::vector reverseMapping; - std::map translateIndexMap; - if (process_weights || mesh.GetBlendShapes().size() > 0) { - reverseMapping.resize(count_vertices); - } - - // allocate output data arrays, but don't fill them yet - out_mesh->mNumVertices = count_vertices; - out_mesh->mVertices = new aiVector3D[count_vertices]; - - out_mesh->mNumFaces = count_faces; - aiFace* fac = out_mesh->mFaces = new aiFace[count_faces](); - - - // allocate normals - const std::vector& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - out_mesh->mNormals = new aiVector3D[vertices.size()]; - } - - // allocate tangents, binormals. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - std::vector tempBinormals; - - if (tangents.size()) { - if (!binormals->size()) { - if (normals.size()) { - // XXX this computes the binormals for the entire mesh, not only - // the part for which we need them. - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - } - } - - // allocate texture coords - unsigned int num_uvs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) { - const std::vector& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - out_mesh->mNumUVComponents[i] = 2; - } - - // allocate vertex colors - unsigned int num_vcs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) { - const std::vector& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - } - - unsigned int cursor = 0, in_cursor = 0; - - itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf) - { - const unsigned int pcount = *itf; - if ((*it) != index) { - in_cursor += pcount; - continue; - } - - aiFace& f = *fac++; - - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) { - f.mIndices[i] = cursor; - - if (reverseMapping.size()) { - reverseMapping[cursor] = in_cursor; - translateIndexMap[in_cursor] = cursor; - } - - out_mesh->mVertices[cursor] = vertices[in_cursor]; - - if (out_mesh->mNormals) { - out_mesh->mNormals[cursor] = normals[in_cursor]; - } - - if (out_mesh->mTangents) { - out_mesh->mTangents[cursor] = tangents[in_cursor]; - out_mesh->mBitangents[cursor] = (*binormals)[in_cursor]; - } - - for (unsigned int j = 0; j < num_uvs; ++j) { - const std::vector& uvs = mesh.GetTextureCoords(j); - out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f); - } - - for (unsigned int j = 0; j < num_vcs; ++j) { - const std::vector& cols = mesh.GetVertexColors(j); - out_mesh->mColors[j][cursor] = cols[in_cursor]; - } - } - } - - ConvertMaterialForMesh(out_mesh, model, mesh, index); - - if (process_weights) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping); - } - - std::vector animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector& vertices = shapeGeometry->GetVertices(); - const std::vector& normals = shapeGeometry->GetNormals(); - const std::vector& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int outIndex = outIndices[k]; - if (translateIndexMap.find(outIndex) == translateIndexMap.end()) - continue; - unsigned int index = translateIndexMap[outIndex]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - - return static_cast(meshes.size() - 1); - } - - void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, - const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node, unsigned int materialIndex, - std::vector *outputVertStartIndices) - { - ai_assert(geo.DeformerSkin()); - - std::vector out_indices; - std::vector index_out_indices; - std::vector count_out_indices; - - const Skin& sk = *geo.DeformerSkin(); - - std::vector bones; - - const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; - ai_assert(no_mat_check || outputVertStartIndices); - - try { - // iterate over the sub deformers - for (const Cluster* cluster : sk.Clusters()) { - ai_assert(cluster); - - const WeightIndexArray& indices = cluster->GetIndices(); - - const MatIndexArray& mats = geo.GetMaterialIndices(); - - const size_t no_index_sentinel = std::numeric_limits::max(); - - count_out_indices.clear(); - index_out_indices.clear(); - out_indices.clear(); - - - // now check if *any* of these weights is contained in the output mesh, - // taking notes so we don't need to do it twice. - for (WeightIndexArray::value_type index : indices) { - - unsigned int count = 0; - const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count); - // ToOutputVertexIndex only returns nullptr if index is out of bounds - // which should never happen - ai_assert(out_idx != nullptr); - - index_out_indices.push_back(no_index_sentinel); - count_out_indices.push_back(0); - - for (unsigned int i = 0; i < count; ++i) { - if (no_mat_check || static_cast(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) { - - if (index_out_indices.back() == no_index_sentinel) { - index_out_indices.back() = out_indices.size(); - } - - if (no_mat_check) { - out_indices.push_back(out_idx[i]); - } else { - // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) - const std::vector::iterator it = std::lower_bound( - outputVertStartIndices->begin(), - outputVertStartIndices->end(), - out_idx[i] - ); - - out_indices.push_back(std::distance(outputVertStartIndices->begin(), it)); - } - - ++count_out_indices.back(); - } - } - } - - // if we found at least one, generate the output bones - // XXX this could be heavily simplified by collecting the bone - // data in a single step. - ConvertCluster(bones, cluster, out_indices, index_out_indices, - count_out_indices, absolute_transform, parent, root_node); - } - - bone_map.clear(); - } - catch (std::exception&e) { - std::for_each(bones.begin(), bones.end(), Util::delete_fun()); - throw; - } - - if (bones.empty()) { - out->mBones = nullptr; - out->mNumBones = 0; - return; - } else { - out->mBones = new aiBone *[bones.size()](); - out->mNumBones = static_cast(bones.size()); - - std::swap_ranges(bones.begin(), bones.end(), out->mBones); - } - } - - const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node ) - { - aiNode * iter = current_node; - //printf("Child count: %d", iter->mNumChildren); - return iter; - } - - void FBXConverter::ConvertCluster(std::vector &local_mesh_bones, const Cluster *cl, - std::vector &out_indices, std::vector &index_out_indices, - std::vector &count_out_indices, const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node) { - ai_assert(cl); // make sure cluster valid - std::string deformer_name = cl->TargetNode()->Name(); - aiString bone_name = aiString(FixNodeName(deformer_name)); - - aiBone *bone = nullptr; - - if (bone_map.count(deformer_name)) { - std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name - << std::endl; - bone = bone_map[deformer_name]; - } else { - std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; - bone = new aiBone(); - bone->mName = bone_name; - - // store local transform link for post processing - bone->mOffsetMatrix = cl->TransformLink(); - bone->mOffsetMatrix.Inverse(); - - aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; - - bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset - - - // - // Now calculate the aiVertexWeights - // - - aiVertexWeight *cursor = nullptr; - - bone->mNumWeights = static_cast(out_indices.size()); - cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; - - const size_t no_index_sentinel = std::numeric_limits::max(); - const WeightArray& weights = cl->GetWeights(); - - const size_t c = index_out_indices.size(); - for (size_t i = 0; i < c; ++i) { - const size_t index_index = index_out_indices[i]; - - if (index_index == no_index_sentinel) { - continue; - } - - const size_t cc = count_out_indices[i]; - for (size_t j = 0; j < cc; ++j) { - // cursor runs from first element relative to the start - // or relative to the start of the next indexes. - aiVertexWeight& out_weight = *cursor++; - - out_weight.mVertexId = static_cast(out_indices[index_index + j]); - out_weight.mWeight = weights[i]; - } - } - - bone_map.insert(std::pair(deformer_name, bone)); - } - - std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; - - // lookup must be populated in case something goes wrong - // this also allocates bones to mesh instance outside - local_mesh_bones.push_back(bone); - } - - void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex) - { - // locate source materials for this mesh - const std::vector& mats = model.GetMaterials(); - if (static_cast(materialIndex) >= mats.size() || materialIndex < 0) { - FBXImporter::LogError("material index out of bounds, setting default material"); - out->mMaterialIndex = GetDefaultMaterial(); - return; - } - - const Material* const mat = mats[materialIndex]; - MaterialMap::const_iterator it = materials_converted.find(mat); - if (it != materials_converted.end()) { - out->mMaterialIndex = (*it).second; - return; - } - - out->mMaterialIndex = ConvertMaterial(*mat, &geo); - materials_converted[mat] = out->mMaterialIndex; - } - - unsigned int FBXConverter::GetDefaultMaterial() - { - if (defaultMaterialIndex) { - return defaultMaterialIndex - 1; - } - - aiMaterial* out_mat = new aiMaterial(); - materials.push_back(out_mat); - - const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f); - out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - - aiString s; - s.Set(AI_DEFAULT_MATERIAL_NAME); - - out_mat->AddProperty(&s, AI_MATKEY_NAME); - - defaultMaterialIndex = static_cast(materials.size()); - return defaultMaterialIndex - 1; - } - - - unsigned int FBXConverter::ConvertMaterial(const Material& material, const MeshGeometry* const mesh) - { - const PropertyTable& props = material.Props(); - - // generate empty output material - aiMaterial* out_mat = new aiMaterial(); - materials_converted[&material] = static_cast(materials.size()); - - materials.push_back(out_mat); - - aiString str; - - // strip Material:: prefix - std::string name = material.Name(); - if (name.substr(0, 10) == "Material::") { - name = name.substr(10); - } - - // set material name if not empty - this could happen - // and there should be no key for it in this case. - if (name.length()) { - str.Set(name); - out_mat->AddProperty(&str, AI_MATKEY_NAME); - } - - // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. - if (material.GetShadingModel() == "phong") - { - aiShadingMode shadingMode = aiShadingMode_Phong; - out_mat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); - } - - // shading stuff and colors - SetShadingPropertiesCommon(out_mat, props); - SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh ); - - // texture assignments - SetTextureProperties(out_mat, material.Textures(), mesh); - SetTextureProperties(out_mat, material.LayeredTextures(), mesh); - - return static_cast(materials.size() - 1); - } - - unsigned int FBXConverter::ConvertVideo(const Video& video) - { - // generate empty output texture - aiTexture* out_tex = new aiTexture(); - textures.push_back(out_tex); - - // assuming the texture is compressed - out_tex->mWidth = static_cast(video.ContentLength()); // total data size - out_tex->mHeight = 0; // fixed to 0 - - // steal the data from the Video to avoid an additional copy - out_tex->pcData = reinterpret_cast(const_cast(video).RelinquishContent()); - - // try to extract a hint from the file extension - const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename(); - std::string ext = BaseImporter::GetExtension(filename); - - if (ext == "jpeg") { - ext = "jpg"; - } - - if (ext.size() <= 3) { - memcpy(out_tex->achFormatHint, ext.c_str(), ext.size()); - } - - out_tex->mFilename.Set(filename.c_str()); - - return static_cast(textures.size() - 1); - } - - aiString FBXConverter::GetTexturePath(const Texture* tex) - { - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr) { - bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(*media); - if (it != textures_converted.end()) { - index = (*it).second; - textureReady = true; - } - else { - if (media->ContentLength() > 0) { - index = ConvertVideo(*media); - textures_converted[*media] = index; - textureReady = true; - } - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready - if (doc.Settings().useLegacyEmbeddedTextureNaming) { - if (textureReady) { - // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - // In FBX files textures are now stored internally by Assimp with their filename included - // Now Assimp can lookup through the loaded textures after all data is processed - // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it - // This may occur on this case too, it has to be studied - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - } - } - - return path; - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - TextureMap::const_iterator it = textures.find(propName); - if (it == textures.end()) { - return; - } - - const Texture* const tex = (*it).second; - if (tex != 0) - { - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0); - } - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - LayeredTextureMap::const_iterator it = layeredTextures.find(propName); - if (it == layeredTextures.end()) { - return; - } - - int texCount = (*it).second->textureCount(); - - // Set the blend mode for layered textures - int blendmode = (*it).second->GetBlendMode(); - out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0); - - for (int texIndex = 0; texIndex < texCount; texIndex++) { - - const Texture* const tex = (*it).second->getTexture(texIndex); - - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex); - } - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, textures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - TrySetTextureProperties( out_mat, textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - //Maya counterparts - TrySetTextureProperties(out_mat, textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh); - - // Maya PBR - TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - - // Maya stingray - TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - } - - aiColor3D FBXConverter::GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate) - { - result = true; - - bool ok; - aiVector3D BaseColor = PropertyGet(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - - // if no factor name, return the colour as is - if (factorName.empty()) { - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - // otherwise it should be multiplied by the factor, if found. - float factor = PropertyGet(props, factorName, ok, useTemplate); - if (ok) { - BaseColor *= factor; - } - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - aiColor3D FBXConverter::GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, - bool& result) - { - return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true); - } - - aiColor3D FBXConverter::GetColorProperty(const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate) - { - result = true; - bool ok; - const aiVector3D& ColorVec = PropertyGet(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z); - } - - void FBXConverter::SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props) - { - // Set shading properties. - // Modern FBX Files have two separate systems for defining these, - // with only the more comprehensive one described in the property template. - // Likely the other values are a legacy system, - // which is still always exported by the official FBX SDK. - // - // Blender's FBX import and export mostly ignore this legacy system, - // and as we only support recent versions of FBX anyway, we can do the same. - bool ok; - - const aiColor3D& Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok); - if (ok) { - out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - } - - const aiColor3D& Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok); - if (ok) { - out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE); - } - - const aiColor3D& Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok); - if (ok) { - out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT); - } - - // we store specular factor as SHININESS_STRENGTH, so just get the color - const aiColor3D& Specular = GetColorProperty(props, "SpecularColor", ok, true); - if (ok) { - out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR); - } - - // and also try to get SHININESS_STRENGTH - const float SpecularFactor = PropertyGet(props, "SpecularFactor", ok, true); - if (ok) { - out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH); - } - - // and the specular exponent - const float ShininessExponent = PropertyGet(props, "ShininessExponent", ok); - if (ok) { - out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS); - } - - // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: - const aiColor3D& Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok); - float CalculatedOpacity = 1.0f; - if (ok) { - out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT); - // as calculated by FBX SDK 2017: - CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f); - } - - // try to get the transparency factor - const float TransparencyFactor = PropertyGet(props, "TransparencyFactor", ok); - if (ok) { - out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR); - } - - // use of TransparencyFactor is inconsistent. - // Maya always stores it as 1.0, - // so we can't use it to set AI_MATKEY_OPACITY. - // Blender is more sensible and stores it as the alpha value. - // However both the FBX SDK and Blender always write an additional - // legacy "Opacity" field, so we can try to use that. - // - // If we can't find it, - // we can fall back to the value which the FBX SDK calculates - // from transparency colour (RGB) and factor (F) as - // 1.0 - F*((R+G+B)/3). - // - // There's no consistent way to interpret this opacity value, - // so it's up to clients to do the correct thing. - const float Opacity = PropertyGet(props, "Opacity", ok); - if (ok) { - out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY); - } - else if (CalculatedOpacity != 1.0) { - out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY); - } - - // reflection color and factor are stored separately - const aiColor3D& Reflection = GetColorProperty(props, "ReflectionColor", ok, true); - if (ok) { - out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE); - } - - float ReflectionFactor = PropertyGet(props, "ReflectionFactor", ok, true); - if (ok) { - out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY); - } - - const float BumpFactor = PropertyGet(props, "BumpFactor", ok); - if (ok) { - out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING); - } - - const float DispFactor = PropertyGet(props, "DisplacementFactor", ok); - if (ok) { - out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0); - } -} - - -void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh) -{ - // Add all the unparsed properties with a "$raw." prefix - - const std::string prefix = "$raw."; - - for (const DirectPropertyMap::value_type& prop : props.GetUnparsedProperties()) { - - std::string name = prefix + prop.first; - - if (const TypedProperty* interpreted = prop.second->As >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - int value = interpreted->Value() ? 1 : 0; - out_mat->AddProperty(&value, 1, name.c_str(), 0, 0); - } - else if (const TypedProperty* interpreted = prop.second->As >()) - { - const aiString value = aiString(interpreted->Value()); - out_mat->AddProperty(&value, name.c_str(), 0, 0); - } - } - - // Add the textures' properties - - for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++) { - - std::string name = prefix + it->first; - - const Texture* const tex = (*it).second; - if (tex != nullptr) - { - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr && media->ContentLength() > 0) { - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(*media); - if (it != textures_converted.end()) { - index = (*it).second; - } - else { - index = ConvertVideo(*media); - textures_converted[*media] = index; - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - - out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0); - - int uvIndex = 0; - - bool uvFound = false; - const std::string& uvSet = PropertyGet(tex->Props(), "UVSet", uvFound); - if (uvFound) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - std::vector::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat); - const unsigned int matIndex = static_cast(std::distance(materials.begin(), materialIt)); - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast(v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0); - } - } - } - - - double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) { - switch (fp) { - case FileGlobalSettings::FrameRate_DEFAULT: - return 1.0; - - case FileGlobalSettings::FrameRate_120: - return 120.0; - - case FileGlobalSettings::FrameRate_100: - return 100.0; - - case FileGlobalSettings::FrameRate_60: - return 60.0; - - case FileGlobalSettings::FrameRate_50: - return 50.0; - - case FileGlobalSettings::FrameRate_48: - return 48.0; - - case FileGlobalSettings::FrameRate_30: - case FileGlobalSettings::FrameRate_30_DROP: - return 30.0; - - case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME: - case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME: - return 29.9700262; - - case FileGlobalSettings::FrameRate_PAL: - return 25.0; - - case FileGlobalSettings::FrameRate_CINEMA: - return 24.0; - - case FileGlobalSettings::FrameRate_1000: - return 1000.0; - - case FileGlobalSettings::FrameRate_CINEMA_ND: - return 23.976; - - case FileGlobalSettings::FrameRate_CUSTOM: - return customFPSVal; - - case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings - break; - } - - ai_assert(false); - - return -1.0f; - } - - - void FBXConverter::ConvertAnimations() - { - // first of all determine framerate - const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode(); - const float custom = doc.GlobalSettings().CustomFrameRate(); - anim_fps = FrameRateToDouble(fps, custom); - - const std::vector& animations = doc.AnimationStacks(); - for (const AnimationStack* stack : animations) { - ConvertAnimationStack(*stack); - } - } - - std::string FBXConverter::FixNodeName(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(). - if (name.substr(0, 7) == "Model::") { - std::string temp = name.substr(7); - return temp; - } - - return name; - } - - std::string FBXConverter::FixAnimMeshName(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"; - } - - void FBXConverter::ConvertAnimationStack(const AnimationStack& st) - { - const AnimationLayerList& layers = st.Layers(); - if (layers.empty()) { - return; - } - - aiAnimation* const anim = new aiAnimation(); - animations.push_back(anim); - - // strip AnimationStack:: prefix - std::string name = st.Name(); - if (name.substr(0, 16) == "AnimationStack::") { - name = name.substr(16); - } - else if (name.substr(0, 11) == "AnimStack::") { - name = name.substr(11); - } - - anim->mName.Set(name); - - // need to find all nodes for which we need to generate node animations - - // it may happen that we need to merge multiple layers, though. - NodeMap node_map; - - // reverse mapping from curves to layers, much faster than querying - // the FBX DOM for it. - LayerMap layer_map; - - const char* prop_whitelist[] = { - "Lcl Scaling", - "Lcl Rotation", - "Lcl Translation", - "DeformPercent" - }; - - std::map morphAnimDatas; - - for (const AnimationLayer* layer : layers) { - ai_assert(layer); - const AnimationCurveNodeList& nodes = layer->Nodes(prop_whitelist, 4); - for (const AnimationCurveNode* node : nodes) { - ai_assert(node); - const Model* const model = dynamic_cast(node->Target()); - if (model) { - const std::string& name = FixNodeName(model->Name()); - node_map[name].push_back(node); - layer_map[node] = layer; - continue; - } - const BlendShapeChannel* const bsc = dynamic_cast(node->Target()); - if (bsc) { - ProcessMorphAnimDatas(&morphAnimDatas, bsc, node); - } - } - } - - // generate node animations - std::vector node_anims; - - double min_time = 1e10; - double max_time = -1e10; - - int64_t start_time = st.LocalStart(); - int64_t stop_time = st.LocalStop(); - bool has_local_startstop = start_time != 0 || stop_time != 0; - if (!has_local_startstop) { - // no time range given, so accept every keyframe and use the actual min/max time - // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = -9223372036854775807ll + 20000; - stop_time = 9223372036854775807ll - 20000; - } - - try { - for (const NodeMap::value_type& kv : node_map) { - GenerateNodeAnimations(node_anims, - kv.first, - kv.second, - layer_map, - start_time, stop_time, - max_time, - min_time); - } - } - catch (std::exception&) { - std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun()); - throw; - } - - if (node_anims.size() || morphAnimDatas.size()) { - if (node_anims.size()) { - anim->mChannels = new aiNodeAnim*[node_anims.size()](); - anim->mNumChannels = static_cast(node_anims.size()); - std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels); - } - if (morphAnimDatas.size()) { - unsigned int numMorphMeshChannels = static_cast(morphAnimDatas.size()); - anim->mMorphMeshChannels = new aiMeshMorphAnim*[numMorphMeshChannels]; - anim->mNumMorphMeshChannels = numMorphMeshChannels; - unsigned int i = 0; - for (auto morphAnimIt : morphAnimDatas) { - morphAnimData* animData = morphAnimIt.second; - unsigned int numKeys = static_cast(animData->size()); - aiMeshMorphAnim* meshMorphAnim = new aiMeshMorphAnim(); - meshMorphAnim->mName.Set(morphAnimIt.first); - meshMorphAnim->mNumKeys = numKeys; - meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys]; - unsigned int j = 0; - for (auto animIt : *animData) { - morphKeyData* keyData = animIt.second; - unsigned int numValuesAndWeights = static_cast(keyData->values.size()); - meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; - meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights]; - meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights]; - meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps; - for (unsigned int k = 0; k < numValuesAndWeights; k++) { - meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k); - meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k); - } - j++; - } - anim->mMorphMeshChannels[i++] = meshMorphAnim; - } - } - } - else { - // empty animations would fail validation, so drop them - delete anim; - animations.pop_back(); - FBXImporter::LogInfo("ignoring empty AnimationStack (using IK?): " + name); - return; - } - - double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; - double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; - - // adjust relative timing for animation - for (unsigned int c = 0; c < anim->mNumChannels; c++) { - aiNodeAnim* channel = anim->mChannels[c]; - for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) { - channel->mPositionKeys[i].mTime -= start_time_fps; - } - for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) { - channel->mRotationKeys[i].mTime -= start_time_fps; - } - for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) { - channel->mScalingKeys[i].mTime -= start_time_fps; - } - } - for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) { - aiMeshMorphAnim* channel = anim->mMorphMeshChannels[c]; - for (uint32_t i = 0; i < channel->mNumKeys; i++) { - channel->mKeys[i].mTime -= start_time_fps; - } - } - - // for some mysterious reason, mDuration is simply the maximum key -- the - // validator always assumes animations to start at zero. - anim->mDuration = stop_time_fps - start_time_fps; - anim->mTicksPerSecond = anim_fps; - } - - // ------------------------------------------------------------------------------------------------ - void FBXConverter::ProcessMorphAnimDatas(std::map* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node) { - std::vector bscConnections = doc.GetConnectionsBySourceSequenced(bsc->ID(), "Deformer"); - for (const Connection* bscConnection : bscConnections) { - auto bs = dynamic_cast(bscConnection->DestinationObject()); - if (bs) { - auto channelIt = std::find(bs->BlendShapeChannels().begin(), bs->BlendShapeChannels().end(), bsc); - if (channelIt != bs->BlendShapeChannels().end()) { - auto channelIndex = static_cast(std::distance(bs->BlendShapeChannels().begin(), channelIt)); - std::vector bsConnections = doc.GetConnectionsBySourceSequenced(bs->ID(), "Geometry"); - for (const Connection* bsConnection : bsConnections) { - auto geo = dynamic_cast(bsConnection->DestinationObject()); - if (geo) { - std::vector geoConnections = doc.GetConnectionsBySourceSequenced(geo->ID(), "Model"); - for (const Connection* geoConnection : geoConnections) { - auto model = dynamic_cast(geoConnection->DestinationObject()); - if (model) { - auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo); - auto geoIndex = static_cast(std::distance(model->GetGeometry().begin(), geoIt)); - auto name = aiString(FixNodeName(model->Name() + "*")); - name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex); - morphAnimData* animData; - auto animIt = morphAnimDatas->find(name.C_Str()); - if (animIt == morphAnimDatas->end()) { - animData = new morphAnimData(); - morphAnimDatas->insert(std::make_pair(name.C_Str(), animData)); - } - else { - animData = animIt->second; - } - for (std::pair curvesIt : node->Curves()) { - if (curvesIt.first == "d|DeformPercent") { - const AnimationCurve* animationCurve = curvesIt.second; - const KeyTimeList& keys = animationCurve->GetKeys(); - const KeyValueList& values = animationCurve->GetValues(); - unsigned int k = 0; - for (auto key : keys) { - morphKeyData* keyData; - auto keyIt = animData->find(key); - if (keyIt == animData->end()) { - keyData = new morphKeyData(); - animData->insert(std::make_pair(key, keyData)); - } - else { - keyData = keyIt->second; - } - keyData->values.push_back(channelIndex); - keyData->weights.push_back(values.at(k) / 100.0f); - k++; - } - } - } - } - } - } - } - } - } - } - } - - // ------------------------------------------------------------------------------------------------ -#ifdef ASSIMP_BUILD_DEBUG - // ------------------------------------------------------------------------------------------------ - // sanity check whether the input is ok - static void validateAnimCurveNodes(const std::vector& curves, - bool strictMode) { - const Object* target(nullptr); - for (const AnimationCurveNode* node : curves) { - if (!target) { - target = node->Target(); - } - if (node->Target() != target) { - FBXImporter::LogWarn("Node target is nullptr type."); - } - if (strictMode) { - ai_assert(node->Target() == target); - } - } - } -#endif // ASSIMP_BUILD_DEBUG - - // ------------------------------------------------------------------------------------------------ - void FBXConverter::GenerateNodeAnimations(std::vector& node_anims, - const std::string& fixed_name, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - - NodeMap node_property_map; - ai_assert(curves.size()); - -#ifdef ASSIMP_BUILD_DEBUG - validateAnimCurveNodes(curves, doc.Settings().strictMode); -#endif - const AnimationCurveNode* curve_node = nullptr; - for (const AnimationCurveNode* node : curves) { - ai_assert(node); - - if (node->TargetProperty().empty()) { - FBXImporter::LogWarn("target property for animation curve not set: " + node->Name()); - continue; - } - - curve_node = node; - if (node->Curves().empty()) { - FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: " + node->Name()); - continue; - } - - node_property_map[node->TargetProperty()].push_back(node); - } - - ai_assert(curve_node); - ai_assert(curve_node->TargetAsModel()); - - const Model& target = *curve_node->TargetAsModel(); - - // check for all possible transformation components - NodeMap::const_iterator chain[TransformationComp_MAXIMUM]; - - bool has_any = false; - bool has_complex = false; - - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { - const TransformationComp comp = static_cast(i); - - // inverse pivots don't exist in the input, we just generate them - if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) { - chain[i] = node_property_map.end(); - continue; - } - - chain[i] = node_property_map.find(NameTransformationCompProperty(comp)); - if (chain[i] != node_property_map.end()) { - - // check if this curves contains redundant information by looking - // up the corresponding node's transformation chain. - if (doc.Settings().optimizeEmptyAnimationCurves && - IsRedundantAnimationData(target, comp, (*chain[i]).second)) { - - FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name()); - continue; - } - - has_any = true; - - if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation) - { - has_complex = true; - } - } - } - - if (!has_any) { - FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames"); - return; - } - - // this needs to play nicely with GenerateTransformationNodeChain() which will - // be invoked _later_ (animations come first). If this node has only rotation, - // scaling and translation _and_ there are no animated other components either, - // we can use a single node and also a single node animation channel. - if (!has_complex && !NeedsComplexTransformationChain(target)) { - - aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain, - node_property_map.end(), - layer_map, - start, stop, - max_time, - min_time, - true // input is TRS order, assimp is SRT - ); - - ai_assert(nd); - if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) { - delete nd; - } - else { - node_anims.push_back(nd); - } - return; - } - - // otherwise, things get gruesome and we need separate animation channels - // for each part of the transformation chain. Remember which channels - // we generated and pass this information to the node conversion - // code to avoid nodes that have identity transform, but non-identity - // animations, being dropped. - unsigned int flags = 0, bit = 0x1; - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { - const TransformationComp comp = static_cast(i); - - if (chain[i] != node_property_map.end()) { - flags |= bit; - - ai_assert(comp != TransformationComp_RotationPivotInverse); - ai_assert(comp != TransformationComp_ScalingPivotInverse); - - const std::string& chain_name = NameTransformationChainNode(fixed_name, comp); - - aiNodeAnim* na = nullptr; - switch (comp) - { - case TransformationComp_Rotation: - case TransformationComp_PreRotation: - case TransformationComp_PostRotation: - case TransformationComp_GeometricRotation: - na = GenerateRotationNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - break; - - case TransformationComp_RotationOffset: - case TransformationComp_RotationPivot: - case TransformationComp_ScalingOffset: - case TransformationComp_ScalingPivot: - case TransformationComp_Translation: - case TransformationComp_GeometricTranslation: - na = GenerateTranslationNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - // pivoting requires us to generate an implicit inverse channel to undo the pivot translation - if (comp == TransformationComp_RotationPivot) { - const std::string& invName = NameTransformationChainNode(fixed_name, - TransformationComp_RotationPivotInverse); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time, - true); - - ai_assert(inv); - if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { - delete inv; - } - else { - node_anims.push_back(inv); - } - - ai_assert(TransformationComp_RotationPivotInverse > i); - flags |= bit << (TransformationComp_RotationPivotInverse - i); - } - else if (comp == TransformationComp_ScalingPivot) { - const std::string& invName = NameTransformationChainNode(fixed_name, - TransformationComp_ScalingPivotInverse); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time, - true); - - ai_assert(inv); - if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { - delete inv; - } - else { - node_anims.push_back(inv); - } - - ai_assert(TransformationComp_RotationPivotInverse > i); - flags |= bit << (TransformationComp_RotationPivotInverse - i); - } - - break; - - case TransformationComp_Scaling: - case TransformationComp_GeometricScaling: - na = GenerateScalingNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - break; - - default: - ai_assert(false); - } - - ai_assert(na); - if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) { - delete na; - } - else { - node_anims.push_back(na); - } - continue; - } - } - - node_anim_chain_bits[fixed_name] = flags; - } - - - bool FBXConverter::IsRedundantAnimationData(const Model& target, - TransformationComp comp, - const std::vector& curves) { - ai_assert(curves.size()); - - // look for animation nodes with - // * sub channels for all relevant components set - // * one key/value pair per component - // * combined values match up the corresponding value in the bind pose node transformation - // only such nodes are 'redundant' for this function. - - if (curves.size() > 1) { - return false; - } - - const AnimationCurveNode& nd = *curves.front(); - const AnimationCurveMap& sub_curves = nd.Curves(); - - const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X"); - const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y"); - const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z"); - - if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) { - return false; - } - - const KeyValueList& vx = (*dx).second->GetValues(); - const KeyValueList& vy = (*dy).second->GetValues(); - const KeyValueList& vz = (*dz).second->GetValues(); - - if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) { - return false; - } - - const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]); - const aiVector3D& static_val = PropertyGet(target.Props(), - NameTransformationCompProperty(comp), - TransformationCompDefaultValue(comp) - ); - - const float epsilon = Math::getEpsilon(); - return (dyn_val - static_val).SquareLength() < epsilon; - } - - - aiNodeAnim* FBXConverter::GenerateRotationNodeAnim(const std::string& name, - const Model& target, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - std::unique_ptr na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder()); - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); - - // dummy position key - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = aiVector3D(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateScalingNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - std::unique_ptr na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = aiQuaternion(); - - // dummy position key - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = aiVector3D(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool inverse) { - std::unique_ptr na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); - - if (inverse) { - for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) { - na->mPositionKeys[i].mValue *= -1.0f; - } - } - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = aiQuaternion(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, - const Model& target, - NodeMap::const_iterator chain[TransformationComp_MAXIMUM], - NodeMap::const_iterator iter_end, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool reverse_order) - - { - std::unique_ptr na(new aiNodeAnim()); - na->mNodeName.Set(name); - - const PropertyTable& props = target.Props(); - - // need to convert from TRS order to SRT? - if (reverse_order) { - - aiVector3D def_scale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f)); - aiVector3D def_translate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f)); - aiVector3D def_rot = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)); - - KeyFrameListList scaling; - KeyFrameListList translation; - KeyFrameListList rotation; - - if (chain[TransformationComp_Scaling] != iter_end) { - scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop); - } - - if (chain[TransformationComp_Translation] != iter_end) { - translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop); - } - - if (chain[TransformationComp_Rotation] != iter_end) { - rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop); - } - - KeyFrameListList joined; - joined.insert(joined.end(), scaling.begin(), scaling.end()); - joined.insert(joined.end(), translation.begin(), translation.end()); - joined.insert(joined.end(), rotation.begin(), rotation.end()); - - const KeyTimeList& times = GetKeyTimeList(joined); - - aiQuatKey* out_quat = new aiQuatKey[times.size()]; - aiVectorKey* out_scale = new aiVectorKey[times.size()]; - aiVectorKey* out_translation = new aiVectorKey[times.size()]; - - if (times.size()) - { - ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation, - scaling, - translation, - rotation, - times, - max_time, - min_time, - target.RotationOrder(), - def_scale, - def_translate, - def_rot); - } - - // XXX remove duplicates / redundant keys which this operation did - // likely produce if not all three channels were equally dense. - - na->mNumScalingKeys = static_cast(times.size()); - na->mNumRotationKeys = na->mNumScalingKeys; - na->mNumPositionKeys = na->mNumScalingKeys; - - na->mScalingKeys = out_scale; - na->mRotationKeys = out_quat; - na->mPositionKeys = out_translation; - } - else { - - // if a particular transformation is not given, grab it from - // the corresponding node to meet the semantics of aiNodeAnim, - // which requires all of rotation, scaling and translation - // to be set. - if (chain[TransformationComp_Scaling] != iter_end) { - ConvertScaleKeys(na.get(), (*chain[TransformationComp_Scaling]).second, - layer_map, - start, stop, - max_time, - min_time); - } - else { - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = PropertyGet(props, "Lcl Scaling", - aiVector3D(1.f, 1.f, 1.f)); - } - - if (chain[TransformationComp_Rotation] != iter_end) { - ConvertRotationKeys(na.get(), (*chain[TransformationComp_Rotation]).second, - layer_map, - start, stop, - max_time, - min_time, - target.RotationOrder()); - } - else { - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = EulerToQuaternion( - PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)), - target.RotationOrder()); - } - - if (chain[TransformationComp_Translation] != iter_end) { - ConvertTranslationKeys(na.get(), (*chain[TransformationComp_Translation]).second, - layer_map, - start, stop, - max_time, - min_time); - } - else { - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = PropertyGet(props, "Lcl Translation", - aiVector3D(0.f, 0.f, 0.f)); - } - - } - return na.release(); - } - - FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector& nodes, int64_t start, int64_t stop) - { - KeyFrameListList inputs; - inputs.reserve(nodes.size() * 3); - - //give some breathing room for rounding errors - int64_t adj_start = start - 10000; - int64_t adj_stop = stop + 10000; - - for (const AnimationCurveNode* node : nodes) { - ai_assert(node); - - const AnimationCurveMap& curves = node->Curves(); - for (const AnimationCurveMap::value_type& kv : curves) { - - unsigned int mapto; - if (kv.first == "d|X") { - mapto = 0; - } - else if (kv.first == "d|Y") { - mapto = 1; - } - else if (kv.first == "d|Z") { - mapto = 2; - } - else { - FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component"); - continue; - } - - const AnimationCurve* const curve = kv.second; - ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size()); - - //get values within the start/stop time window - std::shared_ptr Keys(new KeyTimeList()); - std::shared_ptr Values(new KeyValueList()); - const size_t count = curve->GetKeys().size(); - Keys->reserve(count); - Values->reserve(count); - for (size_t n = 0; n < count; n++) - { - int64_t k = curve->GetKeys().at(n); - if (k >= adj_start && k <= adj_stop) - { - Keys->push_back(k); - Values->push_back(curve->GetValues().at(n)); - } - } - - inputs.push_back(std::make_tuple(Keys, Values, mapto)); - } - } - return inputs; // pray for NRVO :-) - } - - - KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList& inputs) { - ai_assert(!inputs.empty()); - - // reserve some space upfront - it is likely that the key-frame lists - // have matching time values, so max(of all key-frame lists) should - // be a good estimate. - KeyTimeList keys; - - size_t estimate = 0; - for (const KeyFrameList& kfl : inputs) { - estimate = std::max(estimate, std::get<0>(kfl)->size()); - } - - keys.reserve(estimate); - - std::vector next_pos; - next_pos.resize(inputs.size(), 0); - - const size_t count = inputs.size(); - while (true) { - - int64_t min_tick = std::numeric_limits::max(); - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) { - min_tick = std::get<0>(kfl)->at(next_pos[i]); - } - } - - if (min_tick == std::numeric_limits::max()) { - break; - } - keys.push_back(min_tick); - - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - - while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) { - ++next_pos[i]; - } - } - } - - return keys; - } - - void FBXConverter::InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& max_time, - double& min_time) { - ai_assert(!keys.empty()); - ai_assert(nullptr != valOut); - - std::vector next_pos; - const size_t count(inputs.size()); - - next_pos.resize(inputs.size(), 0); - - for (KeyTimeList::value_type time : keys) { - ai_real result[3] = { def_value.x, def_value.y, def_value.z }; - - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - const size_t ksize = std::get<0>(kfl)->size(); - if (ksize == 0) { - continue; - } - if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) { - ++next_pos[i]; - } - - const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0; - const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i]; - - // use lerp for interpolation - const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0); - const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1); - - const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0); - const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1); - - const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast((time - timeA)) / (timeB - timeA); - const ai_real interpValue = static_cast(valueA + (valueB - valueA) * factor); - - result[std::get<2>(kfl)] = interpValue; - } - - // magic value to convert fbx times to seconds - valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps; - - min_time = std::min(min_time, valOut->mTime); - max_time = std::max(max_time, valOut->mTime); - - valOut->mValue.x = result[0]; - valOut->mValue.y = result[1]; - valOut->mValue.z = result[2]; - - ++valOut; - } - } - - void FBXConverter::InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& maxTime, - double& minTime, - Model::RotOrder order) - { - ai_assert(!keys.empty()); - ai_assert(nullptr != valOut); - - std::unique_ptr temp(new aiVectorKey[keys.size()]); - InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime); - - aiMatrix4x4 m; - - aiQuaternion lastq; - - for (size_t i = 0, c = keys.size(); i < c; ++i) { - - valOut[i].mTime = temp[i].mTime; - - GetRotationMatrix(order, temp[i].mValue, m); - aiQuaternion quat = aiQuaternion(aiMatrix3x3(m)); - - // take shortest path by checking the inner product - // http://www.3dkingdoms.com/weekly/weekly.php?a=36 - if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) - { - quat.x = -quat.x; - quat.y = -quat.y; - quat.z = -quat.z; - quat.w = -quat.w; - } - lastq = quat; - - valOut[i].mValue = quat; - } - } - - void FBXConverter::ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, - aiVectorKey* out_translation, - const KeyFrameListList& scaling, - const KeyFrameListList& translation, - const KeyFrameListList& rotation, - const KeyTimeList& times, - double& maxTime, - double& minTime, - Model::RotOrder order, - const aiVector3D& def_scale, - const aiVector3D& def_translate, - const aiVector3D& def_rotation) - { - if (rotation.size()) { - InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_quat[i].mValue = EulerToQuaternion(def_rotation, order); - } - } - - if (scaling.size()) { - InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_scale[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_scale[i].mValue = def_scale; - } - } - - if (translation.size()) { - InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_translation[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_translation[i].mValue = def_translate; - } - } - - const size_t count = times.size(); - for (size_t i = 0; i < count; ++i) { - aiQuaternion& r = out_quat[i].mValue; - aiVector3D& s = out_scale[i].mValue; - aiVector3D& t = out_translation[i].mValue; - - aiMatrix4x4 mat, temp; - aiMatrix4x4::Translation(t, mat); - mat *= aiMatrix4x4(r.GetMatrix()); - mat *= aiMatrix4x4::Scaling(s, temp); - - mat.Decompose(s, r, t); - } - } - - aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order) - { - aiMatrix4x4 m; - GetRotationMatrix(order, rot, m); - - return aiQuaternion(aiMatrix3x3(m)); - } - - void FBXConverter::ConvertScaleKeys(aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime) - { - ai_assert(nodes.size()); - - // XXX for now, assume scale should be blended geometrically (i.e. two - // layers should be multiplied with each other). There is a FBX - // property in the layer to specify the behaviour, though. - - const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumScalingKeys = static_cast(keys.size()); - na->mScalingKeys = new aiVectorKey[keys.size()]; - if (keys.size() > 0) { - InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime); - } - } - - void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime) - { - ai_assert(nodes.size()); - - // XXX see notes in ConvertScaleKeys() - const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumPositionKeys = static_cast(keys.size()); - na->mPositionKeys = new aiVectorKey[keys.size()]; - if (keys.size() > 0) - InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime); - } - - void FBXConverter::ConvertRotationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime, - Model::RotOrder order) - { - ai_assert(nodes.size()); - - // XXX see notes in ConvertScaleKeys() - const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumRotationKeys = static_cast(keys.size()); - na->mRotationKeys = new aiQuatKey[keys.size()]; - if (!keys.empty()) { - InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order); - } - } - - void FBXConverter::ConvertGlobalSettings() { - if (nullptr == out) { - return; - } - - out->mMetaData = aiMetadata::Alloc(15); - out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); - out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); - out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); - out->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign()); - out->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis()); - out->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign()); - out->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis()); - out->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign()); - out->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor()); - out->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor()); - out->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor()); - out->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode()); - out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); - out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); - out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); - } - - void FBXConverter::TransferDataToScene() - { - ai_assert(!out->mMeshes); - ai_assert(!out->mNumMeshes); - - // note: the trailing () ensures initialization with nullptr - not - // many C++ users seem to know this, so pointing it out to avoid - // confusion why this code works. - - if (meshes.size()) { - out->mMeshes = new aiMesh*[meshes.size()](); - out->mNumMeshes = static_cast(meshes.size()); - - std::swap_ranges(meshes.begin(), meshes.end(), out->mMeshes); - } - - if (materials.size()) { - out->mMaterials = new aiMaterial*[materials.size()](); - out->mNumMaterials = static_cast(materials.size()); - - std::swap_ranges(materials.begin(), materials.end(), out->mMaterials); - } - - if (animations.size()) { - out->mAnimations = new aiAnimation*[animations.size()](); - out->mNumAnimations = static_cast(animations.size()); - - std::swap_ranges(animations.begin(), animations.end(), out->mAnimations); - } - - if (lights.size()) { - out->mLights = new aiLight*[lights.size()](); - out->mNumLights = static_cast(lights.size()); - - std::swap_ranges(lights.begin(), lights.end(), out->mLights); - } - - if (cameras.size()) { - out->mCameras = new aiCamera*[cameras.size()](); - out->mNumCameras = static_cast(cameras.size()); - - std::swap_ranges(cameras.begin(), cameras.end(), out->mCameras); - } - - if (textures.size()) { - out->mTextures = new aiTexture*[textures.size()](); - out->mNumTextures = static_cast(textures.size()); - - std::swap_ranges(textures.begin(), textures.end(), out->mTextures); - } - } - - void FBXConverter::ConvertOrphantEmbeddedTextures() - { - // in C++14 it could be: - // for (auto&& [id, object] : objects) - for (auto&& id_and_object : doc.Objects()) - { - auto&& id = std::get<0>(id_and_object); - auto&& object = std::get<1>(id_and_object); - // If an object doesn't have parent - if (doc.ConnectionsBySource().count(id) == 0) - { - const Texture* realTexture = nullptr; - try - { - const auto& element = object->GetElement(); - const Token& key = element.KeyToken(); - const char* obtype = key.begin(); - const size_t length = static_cast(key.end() - key.begin()); - if (strncmp(obtype, "Texture", length) == 0) - { - const Texture* texture = static_cast(object->Get()); - if (texture->Media() && texture->Media()->ContentLength() > 0) - { - realTexture = texture; - } - } - } - catch (...) - { - // do nothing - } - if (realTexture) - { - const Video* media = realTexture->Media(); - unsigned int index = ConvertVideo(*media); - textures_converted[*media] = index; - } - } - } - } - - // ------------------------------------------------------------------------------------------------ - void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones) - { - FBXConverter converter(out, doc, removeEmptyBones); - } - - } // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXConverter.h b/thirdparty/assimp/code/FBX/FBXConverter.h deleted file mode 100644 index 46693bdca6e3..000000000000 --- a/thirdparty/assimp/code/FBX/FBXConverter.h +++ /dev/null @@ -1,491 +0,0 @@ -/* -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 FBXDConverter.h - * @brief FBX DOM to aiScene conversion - */ -#ifndef INCLUDED_AI_FBX_CONVERTER_H -#define INCLUDED_AI_FBX_CONVERTER_H - -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" -#include "FBXImporter.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -struct aiScene; -struct aiNode; -struct aiMaterial; - -struct morphKeyData { - std::vector values; - std::vector weights; -}; -typedef std::map morphAnimData; - -namespace Assimp { -namespace FBX { - -class Document; -/** - * Convert a FBX #Document to #aiScene - * @param out Empty scene to be populated - * @param doc Parsed FBX document - * @param removeEmptyBones Will remove bones, which do not have any references to vertices. - */ -void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones); - -/** Dummy class to encapsulate the conversion process */ -class FBXConverter { -public: - /** - * The different parts that make up the final local transformation of a fbx-node - */ - enum TransformationComp { - TransformationComp_GeometricScalingInverse = 0, - TransformationComp_GeometricRotationInverse, - TransformationComp_GeometricTranslationInverse, - TransformationComp_Translation, - TransformationComp_RotationOffset, - TransformationComp_RotationPivot, - TransformationComp_PreRotation, - TransformationComp_Rotation, - TransformationComp_PostRotation, - TransformationComp_RotationPivotInverse, - TransformationComp_ScalingOffset, - TransformationComp_ScalingPivot, - TransformationComp_Scaling, - TransformationComp_ScalingPivotInverse, - TransformationComp_GeometricTranslation, - TransformationComp_GeometricRotation, - TransformationComp_GeometricScaling, - - TransformationComp_MAXIMUM - }; - -public: - FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones); - ~FBXConverter(); - -private: - // ------------------------------------------------------------------------------------------------ - // find scene root and trigger recursive scene conversion - void ConvertRootNode(); - - // ------------------------------------------------------------------------------------------------ - // collect and assign child nodes - void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - void ConvertLights(const Model& model, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertCameras(const Model& model, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertLight( const Light& light, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertCamera( const Camera& cam, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void GetUniqueName( const std::string &name, std::string& uniqueName ); - - // ------------------------------------------------------------------------------------------------ - // this returns unified names usable within assimp identifiers (i.e. no space characters - - // while these would be allowed, they are a potential trouble spot so better not use them). - const char* NameTransformationComp(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and - // then makes this name unique - std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent); - - // ------------------------------------------------------------------------------------------------ - // note: this returns the REAL fbx property names - const char* NameTransformationCompProperty(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - aiVector3D TransformationCompDefaultValue(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - void GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out); - // ------------------------------------------------------------------------------------------------ - /** - * checks if a node has more than just scaling, rotation and translation components - */ - bool NeedsComplexTransformationChain(const Model& model); - - // ------------------------------------------------------------------------------------------------ - // note: name must be a FixNodeName() result - std::string NameTransformationChainNode(const std::string& name, TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - /** - * note: memory for output_nodes will be managed by the caller - */ - bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, std::vector& post_output_nodes); - - // ------------------------------------------------------------------------------------------------ - void SetupNodeMetadata(const Model& model, aiNode& nd); - - // ------------------------------------------------------------------------------------------------ - void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed - std::vector - ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - std::vector ConvertLine(const LineGeometry& line, const Model& model, - aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent); - - // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, - const aiMatrix4x4 &absolute_transform, aiNode *parent, - aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - std::vector - ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index, - aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits::max() */ - static_cast(-1); - - // ------------------------------------------------------------------------------------------------ - /** - * - if materialIndex == NO_MATERIAL_SEPARATION, materials are not taken into - * account when determining which weights to include. - * - outputVertStartIndices is only used when a material index is specified, it gives for - * each output vertex the DOM index it maps to. - */ - void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, - aiNode *parent = NULL, aiNode *root_node = NULL, - unsigned int materialIndex = NO_MATERIAL_SEPARATION, - std::vector *outputVertStartIndices = NULL); - // lookup - static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node ); - // ------------------------------------------------------------------------------------------------ - void ConvertCluster(std::vector &local_mesh_bones, const Cluster *cl, - std::vector &out_indices, std::vector &index_out_indices, - std::vector &count_out_indices, const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex); - - // ------------------------------------------------------------------------------------------------ - unsigned int GetDefaultMaterial(); - - // ------------------------------------------------------------------------------------------------ - // Material -> aiMaterial - unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - // Video -> aiTexture - unsigned int ConvertVideo(const Video& video); - - // ------------------------------------------------------------------------------------------------ - // convert embedded texture if necessary and return actual texture path - aiString GetTexturePath(const Texture* tex); - - // ------------------------------------------------------------------------------------------------ - void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, - bool& result); - aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate = true); - aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate = true); - - // ------------------------------------------------------------------------------------------------ - void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props); - void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - // get the number of fps for a FrameRate enumerated value - static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0); - - // ------------------------------------------------------------------------------------------------ - // convert animation data to aiAnimation et al - void ConvertAnimations(); - - // ------------------------------------------------------------------------------------------------ - // takes a fbx node name and returns the identifier to be used in the assimp output scene. - // the function is guaranteed to provide consistent results over multiple invocations - // UNLESS RenameNode() is called for a particular node name. - std::string FixNodeName(const std::string& name); - std::string FixAnimMeshName(const std::string& name); - - typedef std::map LayerMap; - - // XXX: better use multi_map .. - typedef std::map > NodeMap; - - // ------------------------------------------------------------------------------------------------ - void ConvertAnimationStack(const AnimationStack& st); - - // ------------------------------------------------------------------------------------------------ - void ProcessMorphAnimDatas(std::map* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); - - // ------------------------------------------------------------------------------------------------ - void GenerateNodeAnimations(std::vector& node_anims, - const std::string& fixed_name, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - bool IsRedundantAnimationData(const Model& target, - TransformationComp comp, - const std::vector& curves); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateRotationNodeAnim(const std::string& name, - const Model& target, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool inverse = false); - - // ------------------------------------------------------------------------------------------------ - // generate node anim, extracting only Rotation, Scaling and Translation from the given chain - aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name, - const Model& target, - NodeMap::const_iterator chain[TransformationComp_MAXIMUM], - NodeMap::const_iterator iter_end, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool reverse_order = false); - - // key (time), value, mapto (component index) - typedef std::tuple, std::shared_ptr, unsigned int > KeyFrameList; - typedef std::vector KeyFrameListList; - - // ------------------------------------------------------------------------------------------------ - KeyFrameListList GetKeyframeList(const std::vector& nodes, int64_t start, int64_t stop); - - // ------------------------------------------------------------------------------------------------ - KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs); - - // ------------------------------------------------------------------------------------------------ - void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& maxTime, - double& minTime, - Model::RotOrder order); - - // ------------------------------------------------------------------------------------------------ - void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, - aiVectorKey* out_translation, - const KeyFrameListList& scaling, - const KeyFrameListList& translation, - const KeyFrameListList& rotation, - const KeyTimeList& times, - double& maxTime, - double& minTime, - Model::RotOrder order, - const aiVector3D& def_scale, - const aiVector3D& def_translate, - const aiVector3D& def_rotation); - - // ------------------------------------------------------------------------------------------------ - // euler xyz -> quat - aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order); - - // ------------------------------------------------------------------------------------------------ - void ConvertScaleKeys(aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime); - - // ------------------------------------------------------------------------------------------------ - void ConvertTranslationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime); - - // ------------------------------------------------------------------------------------------------ - void ConvertRotationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime, - Model::RotOrder order); - - void ConvertGlobalSettings(); - - // ------------------------------------------------------------------------------------------------ - // copy generated meshes, animations, lights, cameras and textures to the output scene - void TransferDataToScene(); - - // ------------------------------------------------------------------------------------------------ - // FBX file could have embedded textures not connected to anything - void ConvertOrphantEmbeddedTextures(); - -private: - // 0: not assigned yet, others: index is value - 1 - unsigned int defaultMaterialIndex; - - std::vector meshes; - std::vector materials; - std::vector animations; - std::vector lights; - std::vector cameras; - std::vector textures; - - using MaterialMap = std::fbx_unordered_map; - MaterialMap materials_converted; - - using VideoMap = std::fbx_unordered_map; - VideoMap textures_converted; - - using MeshMap = std::fbx_unordered_map >; - MeshMap meshes_converted; - - // fixed node name -> which trafo chain components have animations? - using NodeAnimBitMap = std::fbx_unordered_map ; - NodeAnimBitMap node_anim_chain_bits; - - // number of nodes with the same name - using NodeNameCache = std::fbx_unordered_map; - NodeNameCache mNodeNames; - - // Deformer name is not the same as a bone name - it does contain the bone name though :) - // Deformer names in FBX are always unique in an FBX file. - std::map bone_map; - - double anim_fps; - - aiScene* const out; - const FBX::Document& doc; - - static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene, - std::vector& bones); - - void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene, - const std::vector &bones, - std::map &bone_stack, - std::vector &node_stack ); - - static void BuildNodeList(aiNode *current_node, std::vector &nodes); - - static aiNode *GetNodeFromStack(const aiString &node_name, std::vector &nodes); - - static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector &bone_list); - - static bool IsBoneNode(const aiString &bone_name, std::vector &bones); -}; - -} -} - -#endif // INCLUDED_AI_FBX_CONVERTER_H diff --git a/thirdparty/assimp/code/FBX/FBXDeformer.cpp b/thirdparty/assimp/code/FBX/FBXDeformer.cpp deleted file mode 100644 index 69275534502d..000000000000 --- a/thirdparty/assimp/code/FBX/FBXDeformer.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXMeshGeometry.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Object(id,element,name) -{ - const Scope& sc = GetRequiredScope(element); - - const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); - props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true); -} - - -// ------------------------------------------------------------------------------------------------ -Deformer::~Deformer() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Deformer(id,element,doc,name) -, node() -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Indexes = sc["Indexes"]; - const Element* const Weights = sc["Weights"]; - - const Element& Transform = GetRequiredElement(sc,"Transform",&element); - const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&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& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model"); - for(const Connection* con : conns) { - const Model* const mod = ProcessSimpleConnection(*con, false, "Model -> Cluster", element); - if(mod) { - node = mod; - break; - } - } - - if (!node) { - DOMError("failed to read target Node for Cluster",&element); - } -} - - -// ------------------------------------------------------------------------------------------------ -Cluster::~Cluster() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Deformer(id,element,doc,name) -, accuracy( 0.0f ) { - const Scope& sc = GetRequiredScope(element); - - const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"]; - if(Link_DeformAcuracy) { - accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0)); - } - - // resolve assigned clusters - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); - - clusters.reserve(conns.size()); - for(const Connection* con : conns) { - - const Cluster* const cluster = ProcessSimpleConnection(*con, false, "Cluster -> Skin", element); - if(cluster) { - clusters.push_back(cluster); - continue; - } - } -} - - -// ------------------------------------------------------------------------------------------------ -Skin::~Skin() -{ - -} -// ------------------------------------------------------------------------------------------------ -BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Deformer(id, element, doc, name) -{ - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); - blendShapeChannels.reserve(conns.size()); - for (const Connection* con : conns) { - const BlendShapeChannel* const bspc = ProcessSimpleConnection(*con, false, "BlendShapeChannel -> BlendShape", element); - if (bspc) { - blendShapeChannels.push_back(bspc); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShape::~BlendShape() -{ - -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Deformer(id, element, doc, name) -{ - const Scope& sc = GetRequiredScope(element); - const Element* const DeformPercent = sc["DeformPercent"]; - if (DeformPercent) { - percent = ParseTokenAsFloat(GetRequiredToken(*DeformPercent, 0)); - } - const Element* const FullWeights = sc["FullWeights"]; - if (FullWeights) { - ParseVectorDataArray(fullWeights, *FullWeights); - } - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry"); - shapeGeometries.reserve(conns.size()); - for (const Connection* con : conns) { - const ShapeGeometry* const sg = ProcessSimpleConnection(*con, false, "Shape -> BlendShapeChannel", element); - if (sg) { - shapeGeometries.push_back(sg); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::~BlendShapeChannel() -{ - -} -// ------------------------------------------------------------------------------------------------ -} -} -#endif - diff --git a/thirdparty/assimp/code/FBX/FBXDocument.cpp b/thirdparty/assimp/code/FBX/FBXDocument.cpp deleted file mode 100644 index 506fd978ddb8..000000000000 --- a/thirdparty/assimp/code/FBX/FBXDocument.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXDocument.h" -#include "FBXMeshGeometry.h" -#include "FBXParser.h" -#include "FBXUtil.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" - -#include -#include -#include - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) -: doc(doc) -, element(element) -, id(id) -, flags() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject::~LazyObject() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const Object* LazyObject::Get(bool dieOnError) -{ - if(IsBeingConstructed() || FailedToConstruct()) { - return nullptr; - } - - if (object.get()) { - return object.get(); - } - - const Token& key = element.KeyToken(); - const TokenList& tokens = element.Tokens(); - - if(tokens.size() < 3) { - DOMError("expected at least 3 tokens: id, name and class tag",&element); - } - - const char* err; - 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; - - try { - // 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(key.end()-key.begin()); - - // For debugging - //dumpObjectClassInfo( objtype, classtag ); - - 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")) { - object.reset(new LimbNode(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 ) ) { - // FK and IK effectors are not supported - if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) { - 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)); - } - // note: order matters for these two - 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)); - } - } - catch(std::exception& ex) { - flags &= ~BEING_CONSTRUCTED; - flags |= FAILED_TO_CONSTRUCT; - - if(dieOnError || doc.Settings().strictMode) { - throw; - } - - // note: the error message is already formatted, so raw logging is ok - if(!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_ERROR(ex.what()); - } - return NULL; - } - - if (!object.get()) { - //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element); - } - - flags &= ~BEING_CONSTRUCTED; - return object.get(); -} - -// ------------------------------------------------------------------------------------------------ -Object::Object(uint64_t id, const Element& element, const std::string& name) -: element(element) -, name(name) -, id(id) -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Object::~Object() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr props) -: props(props) -, doc(doc) -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::~FileGlobalSettings() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Document::Document(const Parser& parser, const ImportSettings& settings) -: settings(settings) -, parser(parser) -{ - // Cannot use array default initialization syntax because vc8 fails on it - for (auto &timeStamp : creationTimeStamp) { - timeStamp = 0; - } - - ReadHeader(); - 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(ObjectMap::value_type& v : objects) { - delete v.second; - } - - for(ConnectionMap::value_type& v : src_connections) { - delete v.second; - } - // |dest_connections| contain the same Connection objects as the |src_connections| -} - -// ------------------------------------------------------------------------------------------------ -static const unsigned int LowerSupportedVersion = 7100; -static const unsigned int UpperSupportedVersion = 7400; - -void Document::ReadHeader() { - // Read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["FBXHeaderExtension"]; - if(!ehead || !ehead->Compound()) { - DOMError("no FBXHeaderExtension dictionary found"); - } - - const Scope& 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 ) { - DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013"); - } - if(fbxVersion > UpperSupportedVersion ) { - if(Settings().strictMode) { - DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013" - " (turn off strict mode to try anyhow) "); - } - else { - DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013," - " trying to read it nevertheless"); - } - } - - const Element* const ecreator = shead["Creator"]; - if(ecreator) { - creator = ParseTokenAsString(GetRequiredToken(*ecreator,0)); - } - - const Element* const etimestamp = shead["CreationTimeStamp"]; - if(etimestamp && etimestamp->Compound()) { - const Scope& 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)); - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadGlobalSettings() -{ - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["GlobalSettings"]; - if ( nullptr == ehead || !ehead->Compound() ) { - DOMWarning( "no GlobalSettings dictionary found" ); - globals.reset(new FileGlobalSettings(*this, std::make_shared())); - return; - } - - std::shared_ptr props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true ); - - //double v = PropertyGet( *props.get(), std::string("UnitScaleFactor"), 1.0 ); - - if(!props) { - DOMError("GlobalSettings dictionary contains no property table"); - } - - globals.reset(new FileGlobalSettings(*this, props)); -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadObjects() -{ - // read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const eobjects = sc["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 Scope& sobjects = *eobjects->Compound(); - for(const ElementMap::value_type& el : sobjects.Elements()) { - - // extract ID - const TokenList& tok = el.second->Tokens(); - - if (tok.empty()) { - DOMError("expected ID after object key",el.second); - } - - const char* err; - const uint64_t id = ParseTokenAsID(*tok[0], err); - if(err) { - DOMError(err,el.second); - } - - // id=0 is normally implicit - if(id == 0L) { - DOMError("encountered object with implicitly defined id 0",el.second); - } - - if(objects.find(id) != objects.end()) { - DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); - } - - objects[id] = new LazyObject(id, *el.second, *this); - - // grab all animation stacks upfront since there is no listing of them - if(!strcmp(el.first.c_str(),"AnimationStack")) { - animationStacks.push_back(id); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadPropertyTemplates() -{ - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const edefs = sc["Definitions"]; - if(!edefs || !edefs->Compound()) { - DOMWarning("no Definitions dictionary found"); - return; - } - - const Scope& sdefs = *edefs->Compound(); - const ElementCollection otypes = sdefs.GetCollection("ObjectType"); - for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - 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->GetCollection("PropertyTemplate"); - for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el); - continue; - } - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - DOMWarning("expected name for PropertyTemplate element, ignoring",&el); - continue; - } - - const std::string& pname = ParseTokenAsString(*tok[0]); - - const Element* Properties70 = (*sc)["Properties70"]; - if(Properties70) { - std::shared_ptr props = std::make_shared( - *Properties70,std::shared_ptr(static_cast(NULL)) - ); - - templates[oname+"."+pname] = props; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadConnections() -{ - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const econns = sc["Connections"]; - if(!econns || !econns->Compound()) { - DOMError("no Connections dictionary found"); - } - - uint64_t insertionOrder = 0l; - const Scope& sconns = *econns->Compound(); - const ElementCollection conns = sconns.GetCollection("C"); - for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { - const Element& 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& Document::AnimationStacks() const -{ - if (!animationStacksResolved.empty() || animationStacks.empty()) { - return animationStacksResolved; - } - - animationStacksResolved.reserve(animationStacks.size()); - for(uint64_t id : animationStacks) { - LazyObject* const lazy = GetObject(id); - const AnimationStack* stack; - if(!lazy || !(stack = lazy->Get())) { - DOMWarning("failed to read AnimationStack object"); - continue; - } - 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 Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const -{ - std::vector temp; - - const std::pair 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 Document::GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap& conns, - const char* const* classnames, - size_t count) const - -{ - ai_assert(classnames); - ai_assert( count != 0 ); - ai_assert( count <= MAX_CLASSNAMES); - - 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 temp; - const std::pair range = - conns.equal_range(id); - - temp.reserve(std::distance(range.first,range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - const Token& 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(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 Document::GetConnectionsBySourceSequenced(uint64_t source) const -{ - return GetConnectionsSequenced(source, ConnectionsBySource()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const -{ - const char* arr[] = {classname}; - return GetConnectionsBySourceSequenced(src, arr,1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const -{ - return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count); -} - -// ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* classname) const -{ - const char* arr[] = {classname}; - return GetConnectionsByDestinationSequenced(dest, arr,1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsByDestinationSequenced(uint64_t dest) const -{ - return GetConnectionsSequenced(dest, ConnectionsByDestination()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector 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) -{ - ai_assert(doc.Objects().find(src) != doc.Objects().end()); - // dest may be 0 (root node) - ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end()); -} - -// ------------------------------------------------------------------------------------------------ -Connection::~Connection() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject& Connection::LazySourceObject() const -{ - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return *lazy; -} - -// ------------------------------------------------------------------------------------------------ -LazyObject& Connection::LazyDestinationObject() const -{ - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return *lazy; -} - -// ------------------------------------------------------------------------------------------------ -const Object* Connection::SourceObject() const -{ - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return lazy->Get(); -} - -// ------------------------------------------------------------------------------------------------ -const Object* Connection::DestinationObject() const -{ - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return lazy->Get(); -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXDocument.h b/thirdparty/assimp/code/FBX/FBXDocument.h deleted file mode 100644 index a60d7d9efada..000000000000 --- a/thirdparty/assimp/code/FBX/FBXDocument.h +++ /dev/null @@ -1,1215 +0,0 @@ -/* -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.h - * @brief FBX DOM - */ -#ifndef INCLUDED_AI_FBX_DOCUMENT_H -#define INCLUDED_AI_FBX_DOCUMENT_H - -#include -#include -#include -#include "FBXProperties.h" -#include "FBXParser.h" - -#define _AI_CONCAT(a,b) a ## b -#define AI_CONCAT(a,b) _AI_CONCAT(a,b) - -namespace Assimp { -namespace FBX { - -class Parser; -class Object; -struct ImportSettings; - -class PropertyTable; -class Document; -class Material; -class ShapeGeometry; -class LineGeometry; -class Geometry; - -class Video; - -class AnimationCurve; -class AnimationCurveNode; -class AnimationLayer; -class AnimationStack; - -class BlendShapeChannel; -class BlendShape; -class Skin; -class Cluster; - - -/** Represents a delay-parsed FBX objects. Many objects in the scene - * are not needed by assimp, so it makes no sense to parse them - * upfront. */ -class LazyObject { -public: - LazyObject(uint64_t id, const Element& element, const Document& doc); - - ~LazyObject(); - - const Object* Get(bool dieOnError = false); - - template - const T* Get(bool dieOnError = false) { - const Object* const ob = Get(dieOnError); - return ob ? dynamic_cast(ob) : NULL; - } - - uint64_t ID() const { - return id; - } - - bool IsBeingConstructed() const { - return (flags & BEING_CONSTRUCTED) != 0; - } - - bool FailedToConstruct() const { - return (flags & FAILED_TO_CONSTRUCT) != 0; - } - - const Element& GetElement() const { - return element; - } - - const Document& GetDocument() const { - return doc; - } - -private: - const Document& doc; - const Element& element; - std::unique_ptr object; - - const uint64_t id; - - enum Flags { - BEING_CONSTRUCTED = 0x1, - FAILED_TO_CONSTRUCT = 0x2 - }; - - unsigned int flags; -}; - -/** Base class for in-memory (DOM) representations of FBX objects */ -class Object { -public: - Object(uint64_t id, const Element& element, const std::string& name); - - virtual ~Object(); - - const Element& SourceElement() const { - return element; - } - - const std::string& Name() const { - return name; - } - - uint64_t ID() const { - return id; - } - -protected: - const Element& element; - const std::string name; - const uint64_t id; -}; - -/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, - * fixed members are added by deriving classes. */ -class NodeAttribute : public Object { -public: - NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~NodeAttribute(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - -private: - std::shared_ptr props; -}; - -/** DOM base class for FBX camera settings attached to a node */ -class CameraSwitcher : public NodeAttribute { -public: - CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~CameraSwitcher(); - - int CameraID() const { - return cameraId; - } - - const std::string& CameraName() const { - return cameraName; - } - - const std::string& CameraIndexName() const { - return cameraIndexName; - } - -private: - int cameraId; - std::string cameraName; - std::string cameraIndexName; -}; - -#define fbx_stringize(a) #a - -#define fbx_simple_property(name, type, default_value) \ - type name() const { \ - return PropertyGet(Props(), fbx_stringize(name), (default_value)); \ - } - -// XXX improve logging -#define fbx_simple_enum_property(name, type, default_value) \ - type name() const { \ - const int ival = PropertyGet(Props(), fbx_stringize(name), static_cast(default_value)); \ - if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ - ai_assert(static_cast(default_value) >= 0 && static_cast(default_value) < AI_CONCAT(type, _MAX)); \ - return static_cast(default_value); \ - } \ - return static_cast(ival); \ -} - - -/** DOM base class for FBX cameras attached to a node */ -class Camera : public NodeAttribute { -public: - Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Camera(); - - fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) - fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) - fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0)) - - fbx_simple_property(AspectWidth, float, 1.0f) - fbx_simple_property(AspectHeight, float, 1.0f) - fbx_simple_property(FilmWidth, float, 1.0f) - fbx_simple_property(FilmHeight, float, 1.0f) - - fbx_simple_property(NearPlane, float, 0.1f) - fbx_simple_property(FarPlane, float, 100.0f) - - fbx_simple_property(FilmAspectRatio, float, 1.0f) - fbx_simple_property(ApertureMode, int, 0) - - fbx_simple_property(FieldOfView, float, 1.0f) - fbx_simple_property(FocalLength, float, 1.0f) -}; - -/** DOM base class for FBX null markers attached to a node */ -class Null : public NodeAttribute { -public: - Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Null(); -}; - -/** DOM base class for FBX limb node markers attached to a node */ -class LimbNode : public NodeAttribute { -public: - LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LimbNode(); -}; - -/** DOM base class for FBX lights attached to a node */ -class Light : public NodeAttribute { -public: - Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Light(); - - enum Type - { - Type_Point, - Type_Directional, - Type_Spot, - Type_Area, - Type_Volume, - - Type_MAX // end-of-enum sentinel - }; - - enum Decay - { - Decay_None, - Decay_Linear, - Decay_Quadratic, - Decay_Cubic, - - Decay_MAX // end-of-enum sentinel - }; - - fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1)) - fbx_simple_enum_property(LightType, Type, 0) - fbx_simple_property(CastLightOnObject, bool, false) - fbx_simple_property(DrawVolumetricLight, bool, true) - fbx_simple_property(DrawGroundProjection, bool, true) - fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false) - fbx_simple_property(Intensity, float, 100.0f) - fbx_simple_property(InnerAngle, float, 0.0f) - fbx_simple_property(OuterAngle, float, 45.0f) - fbx_simple_property(Fog, int, 50) - fbx_simple_enum_property(DecayType, Decay, 2) - fbx_simple_property(DecayStart, float, 1.0f) - fbx_simple_property(FileName, std::string, "") - - fbx_simple_property(EnableNearAttenuation, bool, false) - fbx_simple_property(NearAttenuationStart, float, 0.0f) - fbx_simple_property(NearAttenuationEnd, float, 0.0f) - fbx_simple_property(EnableFarAttenuation, bool, false) - fbx_simple_property(FarAttenuationStart, float, 0.0f) - fbx_simple_property(FarAttenuationEnd, float, 0.0f) - - fbx_simple_property(CastShadows, bool, true) - fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0)) - - fbx_simple_property(AreaLightShape, int, 0) - - fbx_simple_property(LeftBarnDoor, float, 20.0f) - fbx_simple_property(RightBarnDoor, float, 20.0f) - fbx_simple_property(TopBarnDoor, float, 20.0f) - fbx_simple_property(BottomBarnDoor, float, 20.0f) - fbx_simple_property(EnableBarnDoor, bool, true) -}; - -/** DOM base class for FBX models (even though its semantics are more "node" than "model" */ -class Model : public Object { -public: - 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 { - TransformInheritance_RrSs = 0, - TransformInheritance_RSrs, - TransformInheritance_Rrs, - - TransformInheritance_MAX // end-of-enum sentinel - }; - - Model(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Model(); - - fbx_simple_property(QuaternionInterpolate, int, 0) - - fbx_simple_property(RotationOffset, aiVector3D, aiVector3D()) - fbx_simple_property(RotationPivot, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingOffset, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingPivot, aiVector3D, aiVector3D()) - fbx_simple_property(TranslationActive, bool, false) - - fbx_simple_property(TranslationMin, aiVector3D, aiVector3D()) - fbx_simple_property(TranslationMax, aiVector3D, aiVector3D()) - - fbx_simple_property(TranslationMinX, bool, false) - fbx_simple_property(TranslationMaxX, bool, false) - fbx_simple_property(TranslationMinY, bool, false) - fbx_simple_property(TranslationMaxY, bool, false) - fbx_simple_property(TranslationMinZ, bool, false) - fbx_simple_property(TranslationMaxZ, bool, false) - - fbx_simple_enum_property(RotationOrder, RotOrder, 0) - fbx_simple_property(RotationSpaceForLimitOnly, bool, false) - fbx_simple_property(RotationStiffnessX, float, 0.0f) - fbx_simple_property(RotationStiffnessY, float, 0.0f) - fbx_simple_property(RotationStiffnessZ, float, 0.0f) - fbx_simple_property(AxisLen, float, 0.0f) - - fbx_simple_property(PreRotation, aiVector3D, aiVector3D()) - fbx_simple_property(PostRotation, aiVector3D, aiVector3D()) - fbx_simple_property(RotationActive, bool, false) - - fbx_simple_property(RotationMin, aiVector3D, aiVector3D()) - fbx_simple_property(RotationMax, aiVector3D, aiVector3D()) - - fbx_simple_property(RotationMinX, bool, false) - fbx_simple_property(RotationMaxX, bool, false) - fbx_simple_property(RotationMinY, bool, false) - fbx_simple_property(RotationMaxY, bool, false) - fbx_simple_property(RotationMinZ, bool, false) - fbx_simple_property(RotationMaxZ, bool, false) - fbx_simple_enum_property(InheritType, TransformInheritance, 0) - - fbx_simple_property(ScalingActive, bool, false) - fbx_simple_property(ScalingMin, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingMax, aiVector3D, aiVector3D(1.f,1.f,1.f)) - fbx_simple_property(ScalingMinX, bool, false) - fbx_simple_property(ScalingMaxX, bool, false) - fbx_simple_property(ScalingMinY, bool, false) - fbx_simple_property(ScalingMaxY, bool, false) - fbx_simple_property(ScalingMinZ, bool, false) - fbx_simple_property(ScalingMaxZ, bool, false) - - fbx_simple_property(GeometricTranslation, aiVector3D, aiVector3D()) - fbx_simple_property(GeometricRotation, aiVector3D, aiVector3D()) - fbx_simple_property(GeometricScaling, aiVector3D, aiVector3D(1.f, 1.f, 1.f)) - - fbx_simple_property(MinDampRangeX, float, 0.0f) - fbx_simple_property(MinDampRangeY, float, 0.0f) - fbx_simple_property(MinDampRangeZ, float, 0.0f) - fbx_simple_property(MaxDampRangeX, float, 0.0f) - fbx_simple_property(MaxDampRangeY, float, 0.0f) - fbx_simple_property(MaxDampRangeZ, float, 0.0f) - - fbx_simple_property(MinDampStrengthX, float, 0.0f) - fbx_simple_property(MinDampStrengthY, float, 0.0f) - fbx_simple_property(MinDampStrengthZ, float, 0.0f) - fbx_simple_property(MaxDampStrengthX, float, 0.0f) - fbx_simple_property(MaxDampStrengthY, float, 0.0f) - fbx_simple_property(MaxDampStrengthZ, float, 0.0f) - - fbx_simple_property(PreferredAngleX, float, 0.0f) - fbx_simple_property(PreferredAngleY, float, 0.0f) - fbx_simple_property(PreferredAngleZ, float, 0.0f) - - fbx_simple_property(Show, bool, true) - fbx_simple_property(LODBox, bool, false) - fbx_simple_property(Freeze, bool, false) - - const std::string& Shading() const { - return shading; - } - - const std::string& Culling() const { - return culling; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - /** Get material links */ - const std::vector& GetMaterials() const { - return materials; - } - - /** Get geometry links */ - const std::vector& GetGeometry() const { - return geometry; - } - - /** Get node attachments */ - const std::vector& GetAttributes() const { - return attributes; - } - - /** convenience method to check if the node has a Null node marker */ - bool IsNull() const; - -private: - void ResolveLinks(const Element& element, const Document& doc); - -private: - std::vector materials; - std::vector geometry; - std::vector attributes; - - std::string shading; - std::string culling; - std::shared_ptr props; -}; - -/** DOM class for generic FBX textures */ -class Texture : public Object { -public: - Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Texture(); - - const std::string& Type() const { - return type; - } - - const std::string& FileName() const { - return fileName; - } - - const std::string& RelativeFilename() const { - return relativeFileName; - } - - const std::string& AlphaSource() const { - return alphaSource; - } - - const aiVector2D& UVTranslation() const { - return uvTrans; - } - - const aiVector2D& UVScaling() const { - return uvScaling; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - // return a 4-tuple - const unsigned int* Crop() const { - return crop; - } - - const Video* Media() const { - return media; - } - -private: - aiVector2D uvTrans; - aiVector2D uvScaling; - - std::string type; - std::string relativeFileName; - std::string fileName; - std::string alphaSource; - std::shared_ptr props; - - unsigned int crop[4]; - - const Video* media; -}; - -/** DOM class for layered FBX textures */ -class LayeredTexture : public Object { -public: - LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LayeredTexture(); - - // Can only be called after construction of the layered texture object due to construction flag. - void fillTexture(const Document& doc); - - enum BlendMode { - BlendMode_Translucent, - BlendMode_Additive, - BlendMode_Modulate, - BlendMode_Modulate2, - BlendMode_Over, - BlendMode_Normal, - BlendMode_Dissolve, - BlendMode_Darken, - BlendMode_ColorBurn, - BlendMode_LinearBurn, - BlendMode_DarkerColor, - BlendMode_Lighten, - BlendMode_Screen, - BlendMode_ColorDodge, - BlendMode_LinearDodge, - BlendMode_LighterColor, - BlendMode_SoftLight, - BlendMode_HardLight, - BlendMode_VividLight, - BlendMode_LinearLight, - BlendMode_PinLight, - BlendMode_HardMix, - BlendMode_Difference, - BlendMode_Exclusion, - BlendMode_Subtract, - BlendMode_Divide, - BlendMode_Hue, - BlendMode_Saturation, - BlendMode_Color, - BlendMode_Luminosity, - BlendMode_Overlay, - BlendMode_BlendModeCount - }; - - const Texture* getTexture(int index=0) const - { - return textures[index]; - - } - int textureCount() const { - return static_cast(textures.size()); - } - BlendMode GetBlendMode() const - { - return blendMode; - } - float Alpha() - { - return alpha; - } -private: - std::vector textures; - BlendMode blendMode; - float alpha; -}; - -typedef std::fbx_unordered_map TextureMap; -typedef std::fbx_unordered_map LayeredTextureMap; - - -/** DOM class for generic FBX videos */ -class Video : public Object { -public: - Video(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Video(); - - const std::string& Type() const { - return type; - } - - const std::string& FileName() const { - return fileName; - } - - const std::string& RelativeFilename() const { - return relativeFileName; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const uint8_t* Content() const { - ai_assert(content); - return content; - } - - uint64_t ContentLength() const { - return contentLength; - } - - uint8_t* RelinquishContent() { - uint8_t* ptr = content; - content = 0; - return ptr; - } - - bool operator==(const Video& other) const - { - return ( - type == other.type - && relativeFileName == other.relativeFileName - && fileName == other.fileName - ); - } - - bool operator<(const Video& other) const - { - return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName); - } - -private: - std::string type; - std::string relativeFileName; - std::string fileName; - std::shared_ptr props; - - uint64_t contentLength; - uint8_t* content; -}; - -/** DOM class for generic FBX materials */ -class Material : public Object { -public: - Material(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Material(); - - const std::string& GetShadingModel() const { - return shading; - } - - bool IsMultilayer() const { - return multilayer; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const TextureMap& Textures() const { - return textures; - } - - const LayeredTextureMap& LayeredTextures() const { - return layeredTextures; - } - -private: - std::string shading; - bool multilayer; - std::shared_ptr props; - - TextureMap textures; - LayeredTextureMap layeredTextures; -}; - -typedef std::vector KeyTimeList; -typedef std::vector KeyValueList; - -/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ -class AnimationCurve : public Object { -public: - AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationCurve(); - - /** get list of keyframe positions (time). - * Invariant: |GetKeys()| > 0 */ - const KeyTimeList& GetKeys() const { - return keys; - } - - /** get list of keyframe values. - * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ - const KeyValueList& GetValues() const { - return values; - } - - const std::vector& GetAttributes() const { - return attributes; - } - - const std::vector& GetFlags() const { - return flags; - } - -private: - KeyTimeList keys; - KeyValueList values; - std::vector attributes; - std::vector flags; -}; - -// property-name -> animation curve -typedef std::map AnimationCurveMap; - -/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ -class AnimationCurveNode : public Object { -public: - /* the optional white list specifies a list of property names for which the caller - wants animations for. If the curve node does not match one of these, std::range_error - will be thrown. */ - AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, - const char* const * target_prop_whitelist = NULL, size_t whitelist_size = 0); - - virtual ~AnimationCurveNode(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - - const AnimationCurveMap& Curves() const; - - /** Object the curve is assigned to, this can be NULL if the - * target object has no DOM representation or could not - * be read for other reasons.*/ - const Object* Target() const { - return target; - } - - const Model* TargetAsModel() const { - return dynamic_cast(target); - } - - const NodeAttribute* TargetAsNodeAttribute() const { - return dynamic_cast(target); - } - - /** Property of Target() that is being animated*/ - const std::string& TargetProperty() const { - return prop; - } - -private: - const Object* target; - std::shared_ptr props; - mutable AnimationCurveMap curves; - - std::string prop; - const Document& doc; -}; - -typedef std::vector AnimationCurveNodeList; - -/** Represents a FBX animation layer (i.e. a list of node animations) */ -class AnimationLayer : public Object { -public: - AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationLayer(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - /* the optional white list specifies a list of property names for which the caller - wants animations for. Curves not matching this list will not be added to the - animation layer. */ - AnimationCurveNodeList Nodes(const char* const * target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; - -private: - std::shared_ptr props; - const Document& doc; -}; - -typedef std::vector AnimationLayerList; - -/** Represents a FBX animation stack (i.e. a list of animation layers) */ -class AnimationStack : public Object { -public: - AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationStack(); - - fbx_simple_property(LocalStart, int64_t, 0L) - fbx_simple_property(LocalStop, int64_t, 0L) - fbx_simple_property(ReferenceStart, int64_t, 0L) - fbx_simple_property(ReferenceStop, int64_t, 0L) - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const AnimationLayerList& Layers() const { - return layers; - } - -private: - std::shared_ptr props; - AnimationLayerList layers; -}; - - -/** DOM class for deformers */ -class Deformer : public Object { -public: - Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Deformer(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - -private: - std::shared_ptr props; -}; - -typedef std::vector WeightArray; -typedef std::vector WeightIndexArray; - - -/** DOM class for BlendShapeChannel deformers */ -class BlendShapeChannel : public Deformer { -public: - BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~BlendShapeChannel(); - - float DeformPercent() const { - return percent; - } - - const WeightArray& GetFullWeights() const { - return fullWeights; - } - - const std::vector& GetShapeGeometries() const { - return shapeGeometries; - } - -private: - float percent; - WeightArray fullWeights; - std::vector shapeGeometries; -}; - -/** DOM class for BlendShape deformers */ -class BlendShape : public Deformer { -public: - BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~BlendShape(); - - const std::vector& BlendShapeChannels() const { - return blendShapeChannels; - } - -private: - std::vector blendShapeChannels; -}; - -/** DOM class for skin deformer clusters (aka sub-deformers) */ -class Cluster : public Deformer { -public: - Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Cluster(); - - /** get the list of deformer weights associated with this cluster. - * Use #GetIndices() to get the associated vertices. Both arrays - * have the same size (and may also be empty). */ - const WeightArray& GetWeights() const { - return weights; - } - - /** get indices into the vertex data of the geometry associated - * with this cluster. Use #GetWeights() to get the associated weights. - * Both arrays have the same size (and may also be empty). */ - const WeightIndexArray& GetIndices() const { - return indices; - } - - /** */ - const aiMatrix4x4& Transform() const { - return transform; - } - - const aiMatrix4x4& TransformLink() const { - return transformLink; - } - - const Model* TargetNode() const { - return node; - } - -private: - WeightArray weights; - WeightIndexArray indices; - - aiMatrix4x4 transform; - aiMatrix4x4 transformLink; - - const Model* node; -}; - -/** DOM class for skin deformers */ -class Skin : public Deformer { -public: - Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Skin(); - - float DeformAccuracy() const { - return accuracy; - } - - const std::vector& Clusters() const { - return clusters; - } - -private: - float accuracy; - std::vector clusters; -}; - -/** Represents a link between two FBX objects. */ -class Connection { -public: - Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, const Document& doc); - - ~Connection(); - - // note: a connection ensures that the source and dest objects exist, but - // not that they have DOM representations, so the return value of one of - // these functions can still be NULL. - const Object* SourceObject() const; - const Object* DestinationObject() const; - - // these, however, are always guaranteed to be valid - LazyObject& LazySourceObject() const; - LazyObject& LazyDestinationObject() const; - - - /** return the name of the property the connection is attached to. - * this is an empty string for object to object (OO) connections. */ - const std::string& PropertyName() const { - return prop; - } - - uint64_t InsertionOrder() const { - return insertionOrder; - } - - int CompareTo(const Connection* c) const { - ai_assert( nullptr != c ); - - // note: can't subtract because this would overflow uint64_t - if(InsertionOrder() > c->InsertionOrder()) { - return 1; - } - else if(InsertionOrder() < c->InsertionOrder()) { - return -1; - } - return 0; - } - - bool Compare(const Connection* c) const { - ai_assert( nullptr != c ); - - return InsertionOrder() < c->InsertionOrder(); - } - -public: - uint64_t insertionOrder; - const std::string prop; - - uint64_t src, dest; - const Document& doc; -}; - -// XXX again, unique_ptr would be useful. shared_ptr is too -// bloated since the objects have a well-defined single owner -// during their entire lifetime (Document). FBX files have -// up to many thousands of objects (most of which we never use), -// so the memory overhead for them should be kept at a minimum. -typedef std::fbx_unordered_map ObjectMap; -typedef std::fbx_unordered_map > PropertyTemplateMap; - -typedef std::fbx_unordered_multimap ConnectionMap; - -/** DOM class for global document settings, a single instance per document can - * be accessed via Document.Globals(). */ -class FileGlobalSettings { -public: - FileGlobalSettings(const Document& doc, std::shared_ptr props); - - ~FileGlobalSettings(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const Document& GetDocument() const { - return doc; - } - - fbx_simple_property(UpAxis, int, 1) - fbx_simple_property(UpAxisSign, int, 1) - fbx_simple_property(FrontAxis, int, 2) - fbx_simple_property(FrontAxisSign, int, 1) - fbx_simple_property(CoordAxis, int, 0) - fbx_simple_property(CoordAxisSign, int, 1) - fbx_simple_property(OriginalUpAxis, int, 0) - fbx_simple_property(OriginalUpAxisSign, int, 1) - fbx_simple_property(UnitScaleFactor, float, 1) - fbx_simple_property(OriginalUnitScaleFactor, float, 1) - fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0)) - fbx_simple_property(DefaultCamera, std::string, "") - - - enum FrameRate { - FrameRate_DEFAULT = 0, - FrameRate_120 = 1, - FrameRate_100 = 2, - FrameRate_60 = 3, - FrameRate_50 = 4, - FrameRate_48 = 5, - FrameRate_30 = 6, - FrameRate_30_DROP = 7, - FrameRate_NTSC_DROP_FRAME = 8, - FrameRate_NTSC_FULL_FRAME = 9, - FrameRate_PAL = 10, - FrameRate_CINEMA = 11, - FrameRate_1000 = 12, - FrameRate_CINEMA_ND = 13, - FrameRate_CUSTOM = 14, - - FrameRate_MAX// end-of-enum sentinel - }; - - fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT) - fbx_simple_property(TimeSpanStart, uint64_t, 0L) - fbx_simple_property(TimeSpanStop, uint64_t, 0L) - fbx_simple_property(CustomFrameRate, float, -1.0f) - -private: - std::shared_ptr props; - const Document& doc; -}; - -/** DOM root for a FBX file */ -class Document { -public: - Document(const Parser& parser, const ImportSettings& settings); - - ~Document(); - - LazyObject* GetObject(uint64_t id) const; - - bool IsBinary() const { - return parser.IsBinary(); - } - - unsigned int FBXVersion() const { - return fbxVersion; - } - - const std::string& Creator() const { - return creator; - } - - // elements (in this order): Year, Month, Day, Hour, Second, Millisecond - const unsigned int* CreationTimeStamp() const { - return creationTimeStamp; - } - - const FileGlobalSettings& GlobalSettings() const { - ai_assert(globals.get()); - return *globals.get(); - } - - const PropertyTemplateMap& Templates() const { - return templates; - } - - const ObjectMap& Objects() const { - return objects; - } - - const ImportSettings& Settings() const { - return settings; - } - - const ConnectionMap& ConnectionsBySource() const { - return src_connections; - } - - const ConnectionMap& ConnectionsByDestination() const { - return dest_connections; - } - - // note: the implicit rule in all DOM classes is to always resolve - // from destination to source (since the FBX object hierarchy is, - // with very few exceptions, a DAG, this avoids cycles). In all - // cases that may involve back-facing edges in the object graph, - // use LazyObject::IsBeingConstructed() to check. - - std::vector GetConnectionsBySourceSequenced(uint64_t source) const; - std::vector GetConnectionsByDestinationSequenced(uint64_t dest) const; - - std::vector GetConnectionsBySourceSequenced(uint64_t source, const char* classname) const; - std::vector GetConnectionsByDestinationSequenced(uint64_t dest, const char* classname) const; - - std::vector GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const; - std::vector GetConnectionsByDestinationSequenced(uint64_t dest, - const char* const* classnames, - size_t count) const; - - const std::vector& AnimationStacks() const; - -private: - std::vector GetConnectionsSequenced(uint64_t id, const ConnectionMap&) const; - std::vector GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap&, - const char* const* classnames, - size_t count) const; - void ReadHeader(); - void ReadObjects(); - void ReadPropertyTemplates(); - void ReadConnections(); - void ReadGlobalSettings(); - -private: - const ImportSettings& settings; - - ObjectMap objects; - const Parser& parser; - - PropertyTemplateMap templates; - ConnectionMap src_connections; - ConnectionMap dest_connections; - - unsigned int fbxVersion; - std::string creator; - unsigned int creationTimeStamp[7]; - - std::vector animationStacks; - mutable std::vector animationStacksResolved; - - std::unique_ptr globals; -}; - -} // Namespace FBX -} // Namespace Assimp - -namespace std -{ - template <> - struct hash - { - std::size_t operator()(const Assimp::FBX::Video& video) const - { - using std::size_t; - using std::hash; - using std::string; - - size_t res = 17; - res = res * 31 + hash()(video.Name()); - res = res * 31 + hash()(video.RelativeFilename()); - res = res * 31 + hash()(video.Type()); - - return res; - } - }; -} - -#endif // INCLUDED_AI_FBX_DOCUMENT_H diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.cpp b/thirdparty/assimp/code/FBX/FBXExportNode.cpp deleted file mode 100644 index 06c89cee4687..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExportNode.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/* -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 ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportNode.h" -#include "FBXCommon.h" - -#include // StreamWriterLE -#include // DeadlyExportError -#include -#include // ai_snprintf - -#include -#include -#include // ostringstream -#include // shared_ptr - -namespace Assimp { -// AddP70 helpers... there's no usable pattern here, -// so all are defined as separate functions. -// Even "animatable" properties are often completely different -// from the standard (nonanimated) property definition, -// so they are specified with an 'A' suffix. - -void FBX::Node::AddP70int( - const std::string& name, int32_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "int", "Integer", "", value); - AddChild(n); -} - -void FBX::Node::AddP70bool( - const std::string& name, bool value -) { - FBX::Node n("P"); - n.AddProperties(name, "bool", "", "", int32_t(value)); - AddChild(n); -} - -void FBX::Node::AddP70double( - const std::string& name, double value -) { - FBX::Node n("P"); - n.AddProperties(name, "double", "Number", "", value); - AddChild(n); -} - -void FBX::Node::AddP70numberA( - const std::string& name, double value -) { - FBX::Node n("P"); - n.AddProperties(name, "Number", "", "A", value); - AddChild(n); -} - -void FBX::Node::AddP70color( - const std::string& name, double r, double g, double b -) { - FBX::Node n("P"); - n.AddProperties(name, "ColorRGB", "Color", "", r, g, b); - AddChild(n); -} - -void FBX::Node::AddP70colorA( - const std::string& name, double r, double g, double b -) { - FBX::Node n("P"); - n.AddProperties(name, "Color", "", "A", r, g, b); - AddChild(n); -} - -void FBX::Node::AddP70vector( - const std::string& name, double x, double y, double z -) { - FBX::Node n("P"); - n.AddProperties(name, "Vector3D", "Vector", "", x, y, z); - AddChild(n); -} - -void FBX::Node::AddP70vectorA( - const std::string& name, double x, double y, double z -) { - FBX::Node n("P"); - n.AddProperties(name, "Vector", "", "A", x, y, z); - AddChild(n); -} - -void FBX::Node::AddP70string( - const std::string& name, const std::string& value -) { - FBX::Node n("P"); - n.AddProperties(name, "KString", "", "", value); - AddChild(n); -} - -void FBX::Node::AddP70enum( - const std::string& name, int32_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "enum", "", "", value); - AddChild(n); -} - -void FBX::Node::AddP70time( - const std::string& name, int64_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "KTime", "Time", "", value); - AddChild(n); -} - - -// public member functions for writing nodes to stream - -void FBX::Node::Dump( - std::shared_ptr outfile, - bool binary, int indent -) { - if (binary) { - Assimp::StreamWriterLE outstream(outfile); - DumpBinary(outstream); - } else { - std::ostringstream ss; - DumpAscii(ss, indent); - std::string s = ss.str(); - outfile->Write(s.c_str(), s.size(), 1); - } -} - -void FBX::Node::Dump( - Assimp::StreamWriterLE &outstream, - bool binary, int indent -) { - if (binary) { - DumpBinary(outstream); - } else { - std::ostringstream ss; - DumpAscii(ss, indent); - outstream.PutString(ss.str()); - } -} - - -// public member functions for low-level writing - -void FBX::Node::Begin( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - if (binary) { - BeginBinary(s); - } else { - // assume we're at the correct place to start already - (void)indent; - std::ostringstream ss; - BeginAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::DumpProperties( - Assimp::StreamWriterLE& s, - bool binary, int indent -) { - if (binary) { - DumpPropertiesBinary(s); - } else { - std::ostringstream ss; - DumpPropertiesAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::EndProperties( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - EndProperties(s, binary, indent, properties.size()); -} - -void FBX::Node::EndProperties( - Assimp::StreamWriterLE &s, - bool binary, int indent, - size_t num_properties -) { - if (binary) { - EndPropertiesBinary(s, num_properties); - } else { - // nothing to do - (void)indent; - } -} - -void FBX::Node::BeginChildren( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - if (binary) { - // nothing to do - } else { - std::ostringstream ss; - BeginChildrenAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::DumpChildren( - Assimp::StreamWriterLE& s, - bool binary, int indent -) { - if (binary) { - DumpChildrenBinary(s); - } else { - std::ostringstream ss; - DumpChildrenAscii(ss, indent); - if (ss.tellp() > 0) - s.PutString(ss.str()); - } -} - -void FBX::Node::End( - Assimp::StreamWriterLE &s, - bool binary, int indent, - bool has_children -) { - if (binary) { - EndBinary(s, has_children); - } else { - std::ostringstream ss; - EndAscii(ss, indent, has_children); - if (ss.tellp() > 0) - s.PutString(ss.str()); - } -} - - -// public member functions for writing to binary fbx - -void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s) -{ - // write header section (with placeholders for some things) - BeginBinary(s); - - // write properties - DumpPropertiesBinary(s); - - // go back and fill in property related placeholders - EndPropertiesBinary(s, properties.size()); - - // write children - DumpChildrenBinary(s); - - // finish, filling in end offset placeholder - EndBinary(s, force_has_children || !children.empty()); -} - - -// public member functions for writing to ascii fbx - -void FBX::Node::DumpAscii(std::ostream &s, int indent) -{ - // write name - BeginAscii(s, indent); - - // write properties - DumpPropertiesAscii(s, indent); - - if (force_has_children || !children.empty()) { - // begin children (with a '{') - BeginChildrenAscii(s, indent + 1); - // write children - DumpChildrenAscii(s, indent + 1); - } - - // finish (also closing the children bracket '}') - EndAscii(s, indent, force_has_children || !children.empty()); -} - - -// private member functions for low-level writing to fbx - -void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s) -{ - // remember start pos so we can come back and write the end pos - this->start_pos = s.Tell(); - - // placeholders for end pos and property section info - s.PutU4(0); // end pos - s.PutU4(0); // number of properties - s.PutU4(0); // total property section length - - // node name - s.PutU1(uint8_t(name.size())); // length of node name - s.PutString(name); // node name as raw bytes - - // property data comes after here - this->property_start = s.Tell(); -} - -void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s) -{ - for (auto &p : properties) { - p.DumpBinary(s); - } -} - -void FBX::Node::EndPropertiesBinary( - Assimp::StreamWriterLE &s, - size_t num_properties -) { - if (num_properties == 0) { return; } - size_t pos = s.Tell(); - ai_assert(pos > property_start); - size_t property_section_size = pos - property_start; - s.Seek(start_pos + 4); - s.PutU4(uint32_t(num_properties)); - s.PutU4(uint32_t(property_section_size)); - s.Seek(pos); -} - -void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s) -{ - for (FBX::Node& child : children) { - child.DumpBinary(s); - } -} - -void FBX::Node::EndBinary( - Assimp::StreamWriterLE &s, - bool has_children -) { - // if there were children, add a null record - if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); } - - // now go back and write initial pos - this->end_pos = s.Tell(); - s.Seek(start_pos); - s.PutU4(uint32_t(end_pos)); - s.Seek(end_pos); -} - - -void FBX::Node::BeginAscii(std::ostream& s, int indent) -{ - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << name << ": "; -} - -void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent) -{ - for (size_t i = 0; i < properties.size(); ++i) { - if (i > 0) { s << ", "; } - properties[i].DumpAscii(s, indent); - } -} - -void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent) -{ - // only call this if there are actually children - s << " {"; - (void)indent; -} - -void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent) -{ - // children will need a lot of padding and corralling - if (children.size() || force_has_children) { - for (size_t i = 0; i < children.size(); ++i) { - // no compression in ascii files, so skip this node if it exists - if (children[i].name == "EncryptionType") { continue; } - // the child can dump itself - children[i].DumpAscii(s, indent); - } - } -} - -void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) -{ - if (!has_children) { return; } // nothing to do - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "}"; -} - -// private helpers for static member functions - -// ascii property node from vector of doubles -void FBX::Node::WritePropertyNodeAscii( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - int indent -){ - char buffer[32]; - FBX::Node node(name); - node.Begin(s, false, indent); - std::string vsize = to_string(v.size()); - // * { - s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); - // indent + 1 - for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } - // a: value,value,value,... - s.PutString("a: "); - int count = 0; - for (size_t i = 0; i < v.size(); ++i) { - if (i > 0) { s.PutChar(','); } - int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]); - count += len; - if (count > 2048) { s.PutChar('\n'); count = 0; } - if (len < 0 || len > 31) { - // this should never happen - throw DeadlyExportError("failed to convert double to string"); - } - for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } - } - // } - s.PutChar('\n'); - for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } - s.PutChar('}'); s.PutChar(' '); - node.End(s, false, indent, false); -} - -// ascii property node from vector of int32_t -void FBX::Node::WritePropertyNodeAscii( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - int indent -){ - char buffer[32]; - FBX::Node node(name); - node.Begin(s, false, indent); - std::string vsize = to_string(v.size()); - // * { - s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); - // indent + 1 - for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } - // a: value,value,value,... - s.PutString("a: "); - int count = 0; - for (size_t i = 0; i < v.size(); ++i) { - if (i > 0) { s.PutChar(','); } - int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]); - count += len; - if (count > 2048) { s.PutChar('\n'); count = 0; } - if (len < 0 || len > 31) { - // this should never happen - throw DeadlyExportError("failed to convert double to string"); - } - for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } - } - // } - s.PutChar('\n'); - for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } - s.PutChar('}'); s.PutChar(' '); - node.End(s, false, indent, false); -} - -// binary property node from vector of doubles -// TODO: optional zip compression! -void FBX::Node::WritePropertyNodeBinary( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s -){ - FBX::Node node(name); - node.BeginBinary(s); - s.PutU1('d'); - s.PutU4(uint32_t(v.size())); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - s.PutU4(uint32_t(v.size()) * 8); // data size - for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); } - node.EndPropertiesBinary(s, 1); - node.EndBinary(s, false); -} - -// binary property node from vector of int32_t -// TODO: optional zip compression! -void FBX::Node::WritePropertyNodeBinary( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s -){ - FBX::Node node(name); - node.BeginBinary(s); - s.PutU1('i'); - s.PutU4(uint32_t(v.size())); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - s.PutU4(uint32_t(v.size()) * 4); // data size - for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); } - node.EndPropertiesBinary(s, 1); - node.EndBinary(s, false); -} - -// public static member functions - -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. -void FBX::Node::WritePropertyNode( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - bool binary, int indent -){ - if (binary) { - FBX::Node::WritePropertyNodeBinary(name, v, s); - } else { - FBX::Node::WritePropertyNodeAscii(name, v, s, indent); - } -} - -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. -void FBX::Node::WritePropertyNode( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - bool binary, int indent -){ - if (binary) { - FBX::Node::WritePropertyNodeBinary(name, v, s); - } else { - FBX::Node::WritePropertyNodeAscii(name, v, s, indent); - } -} -} -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.h b/thirdparty/assimp/code/FBX/FBXExportNode.h deleted file mode 100644 index ef3bc781a470..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExportNode.h +++ /dev/null @@ -1,271 +0,0 @@ -/* -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 FBXExportNode.h -* Declares the FBX::Node helper class for fbx export. -*/ -#ifndef AI_FBXEXPORTNODE_H_INC -#define AI_FBXEXPORTNODE_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportProperty.h" - -#include // StreamWriterLE - -#include -#include - -namespace Assimp { -namespace FBX { - class Node; -} - -class FBX::Node { -public: - // TODO: accessors - std::string name; // node name - std::vector properties; // node properties - std::vector children; // child nodes - - // some nodes always pretend they have children... - bool force_has_children = false; - -public: // constructors - /// The default class constructor. - Node() = default; - - /// The class constructor with the name. - Node(const std::string& n) - : name(n) - , properties() - , children() - , force_has_children( false ) { - // empty - } - - // convenience template to construct with properties directly - template - Node(const std::string& n, const More... more) - : name(n) - , properties() - , children() - , force_has_children(false) { - AddProperties(more...); - } - -public: // functions to add properties or children - // add a single property to the node - template - void AddProperty(T value) { - properties.emplace_back(value); - } - - // convenience function to add multiple properties at once - template - void AddProperties(T value, More... more) { - properties.emplace_back(value); - AddProperties(more...); - } - void AddProperties() {} - - // add a child node directly - void AddChild(const Node& node) { children.push_back(node); } - - // convenience function to add a child node with a single property - template - void AddChild( - const std::string& name, - More... more - ) { - FBX::Node c(name); - c.AddProperties(more...); - children.push_back(c); - } - -public: // support specifically for dealing with Properties70 nodes - - // it really is simpler to make these all separate functions. - // the versions with 'A' suffixes are for animatable properties. - // those often follow a completely different format internally in FBX. - void AddP70int(const std::string& name, int32_t value); - void AddP70bool(const std::string& name, bool value); - void AddP70double(const std::string& name, double value); - void AddP70numberA(const std::string& name, double value); - void AddP70color(const std::string& name, double r, double g, double b); - void AddP70colorA(const std::string& name, double r, double g, double b); - void AddP70vector(const std::string& name, double x, double y, double z); - void AddP70vectorA(const std::string& name, double x, double y, double z); - void AddP70string(const std::string& name, const std::string& value); - void AddP70enum(const std::string& name, int32_t value); - void AddP70time(const std::string& name, int64_t value); - - // template for custom P70 nodes. - // anything that doesn't fit in the above can be created manually. - template - void AddP70( - const std::string& name, - const std::string& type, - const std::string& type2, - const std::string& flags, - More... more - ) { - Node n("P"); - n.AddProperties(name, type, type2, flags, more...); - AddChild(n); - } - -public: // member functions for writing data to a file or stream - - // write the full node to the given file or stream - void Dump( - std::shared_ptr outfile, - bool binary, int indent - ); - void Dump(Assimp::StreamWriterLE &s, bool binary, int indent); - - // these other functions are for writing data piece by piece. - // they must be used carefully. - // for usage examples see FBXExporter.cpp. - void Begin(Assimp::StreamWriterLE &s, bool binary, int indent); - void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent); - void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent); - void EndProperties( - Assimp::StreamWriterLE &s, bool binary, int indent, - size_t num_properties - ); - void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent); - void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent); - void End( - Assimp::StreamWriterLE &s, bool binary, int indent, - bool has_children - ); - -private: // internal functions used for writing - - void DumpBinary(Assimp::StreamWriterLE &s); - void DumpAscii(Assimp::StreamWriterLE &s, int indent); - void DumpAscii(std::ostream &s, int indent); - - void BeginBinary(Assimp::StreamWriterLE &s); - void DumpPropertiesBinary(Assimp::StreamWriterLE& s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties); - void DumpChildrenBinary(Assimp::StreamWriterLE& s); - void EndBinary(Assimp::StreamWriterLE &s, bool has_children); - - void BeginAscii(std::ostream &s, int indent); - void DumpPropertiesAscii(std::ostream &s, int indent); - void BeginChildrenAscii(std::ostream &s, int indent); - void DumpChildrenAscii(std::ostream &s, int indent); - void EndAscii(std::ostream &s, int indent, bool has_children); - -private: // data used for binary dumps - size_t start_pos; // starting position in stream - size_t end_pos; // ending position in stream - size_t property_start; // starting position of property section - -public: // static member functions - - // convenience function to create a node with a single property, - // and write it to the stream. - template - static void WritePropertyNode( - const std::string& name, - const T value, - Assimp::StreamWriterLE& s, - bool binary, int indent - ) { - FBX::FBXExportProperty p(value); - FBX::Node node(name, p); - node.Dump(s, binary, indent); - } - - // convenience function to create and write a property node, - // holding a single property which is an array of values. - // does not copy the data, so is efficient for large arrays. - static void WritePropertyNode( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - bool binary, int indent - ); - - // convenience function to create and write a property node, - // holding a single property which is an array of values. - // does not copy the data, so is efficient for large arrays. - static void WritePropertyNode( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - bool binary, int indent - ); - -private: // static helper functions - static void WritePropertyNodeAscii( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - int indent - ); - static void WritePropertyNodeAscii( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - int indent - ); - static void WritePropertyNodeBinary( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s - ); - static void WritePropertyNodeBinary( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s - ); - -}; -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTNODE_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp b/thirdparty/assimp/code/FBX/FBXExportProperty.cpp deleted file mode 100644 index f2a63b72b906..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -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 ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportProperty.h" - -#include // StreamWriterLE -#include // DeadlyExportError - -#include -#include -#include -#include -#include // ostringstream - -namespace Assimp { -namespace FBX { - -// constructors for single element properties - -FBXExportProperty::FBXExportProperty(bool v) -: type('C') -, data(1, uint8_t(v)) {} - -FBXExportProperty::FBXExportProperty(int16_t v) -: type('Y') -, data(2) { - uint8_t* d = data.data(); - (reinterpret_cast(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(int32_t v) -: type('I') -, data(4) { - uint8_t* d = data.data(); - (reinterpret_cast(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(float v) -: type('F') -, data(4) { - uint8_t* d = data.data(); - (reinterpret_cast(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(double v) -: type('D') -, data(8) { - uint8_t* d = data.data(); - (reinterpret_cast(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(int64_t v) -: type('L') -, data(8) { - uint8_t* d = data.data(); - (reinterpret_cast(d))[0] = v; -} - -// constructors for array-type properties - -FBXExportProperty::FBXExportProperty(const char* c, bool raw) -: FBXExportProperty(std::string(c), raw) { - // empty -} - -// strings can either be saved as "raw" (R) data, or "string" (S) data -FBXExportProperty::FBXExportProperty(const std::string& s, bool raw) -: type(raw ? 'R' : 'S') -, data(s.size()) { - for (size_t i = 0; i < s.size(); ++i) { - data[i] = uint8_t(s[i]); - } -} - -FBXExportProperty::FBXExportProperty(const std::vector& r) -: type('R') -, data(r) { - // empty -} - -FBXExportProperty::FBXExportProperty(const std::vector& va) -: type('i') -, data(4 * va.size() ) { - int32_t* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector& va) -: type('l') -, data(8 * va.size()) { - int64_t* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector& va) -: type('f') -, data(4 * va.size()) { - float* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector& va) -: type('d') -, data(8 * va.size()) { - double* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm) -: type('d') -, data(8 * 16) { - double* d = reinterpret_cast(data.data()); - for (unsigned int c = 0; c < 4; ++c) { - for (unsigned int r = 0; r < 4; ++r) { - d[4 * c + r] = vm[r][c]; - } - } -} - -// public member functions - -size_t FBXExportProperty::size() { - switch (type) { - case 'C': - case 'Y': - case 'I': - case 'F': - case 'D': - case 'L': - return data.size() + 1; - case 'S': - case 'R': - return data.size() + 5; - case 'i': - case 'd': - return data.size() + 13; - default: - throw DeadlyExportError("Requested size on property of unknown type"); - } -} - -void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) { - s.PutU1(type); - uint8_t* d = data.data(); - size_t N; - switch (type) { - case 'C': s.PutU1(*(reinterpret_cast(d))); return; - case 'Y': s.PutI2(*(reinterpret_cast(d))); return; - case 'I': s.PutI4(*(reinterpret_cast(d))); return; - case 'F': s.PutF4(*(reinterpret_cast(d))); return; - case 'D': s.PutF8(*(reinterpret_cast(d))); return; - case 'L': s.PutI8(*(reinterpret_cast(d))); return; - case 'S': - case 'R': - s.PutU4(uint32_t(data.size())); - for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); } - return; - case 'i': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI4((reinterpret_cast(d))[i]); - } - return; - case 'l': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI8((reinterpret_cast(d))[i]); - } - return; - case 'f': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF4((reinterpret_cast(d))[i]); - } - return; - case 'd': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF8((reinterpret_cast(d))[i]); - } - return; - default: - std::ostringstream err; - err << "Tried to dump property with invalid type '"; - err << type << "'!"; - throw DeadlyExportError(err.str()); - } -} - -void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) { - std::ostringstream ss; - ss.imbue(std::locale::classic()); - ss.precision(15); // this seems to match official FBX SDK exports - DumpAscii(ss, indent); - outstream.PutString(ss.str()); -} - -void FBXExportProperty::DumpAscii(std::ostream& s, int indent) { - // no writing type... or anything. just shove it into the stream. - uint8_t* d = data.data(); - size_t N; - size_t swap = data.size(); - size_t count = 0; - switch (type) { - case 'C': - if (*(reinterpret_cast(d))) { s << 'T'; } - else { s << 'F'; } - return; - case 'Y': s << *(reinterpret_cast(d)); return; - case 'I': s << *(reinterpret_cast(d)); return; - case 'F': s << *(reinterpret_cast(d)); return; - case 'D': s << *(reinterpret_cast(d)); return; - case 'L': s << *(reinterpret_cast(d)); return; - case 'S': - // first search to see if it has "\x00\x01" in it - - // which separates fields which are reversed in the ascii version. - // yeah. - // FBX, yeah. - for (size_t i = 0; i < data.size(); ++i) { - if (data[i] == '\0') { - swap = i; - break; - } - } - case 'R': - s << '"'; - // we might as well check this now, - // probably it will never happen - for (size_t i = 0; i < data.size(); ++i) { - char c = data[i]; - if (c == '"') { - throw runtime_error("can't handle quotes in property string"); - } - } - // first write the SWAPPED member (if any) - for (size_t i = swap + 2; i < data.size(); ++i) { - char c = data[i]; - s << c; - } - // then a separator - if (swap != data.size()) { - s << "::"; - } - // then the initial member - for (size_t i = 0; i < swap; ++i) { - char c = data[i]; - s << c; - } - s << '"'; - return; - case 'i': - N = data.size() / 4; // number of elements - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'l': - N = data.size() / 8; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'f': - N = data.size() / 4; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'd': - N = data.size() / 8; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - // set precision to something that can handle doubles - s.precision(15); - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - default: - std::ostringstream err; - err << "Tried to dump property with invalid type '"; - err << type << "'!"; - throw runtime_error(err.str()); - } -} - -} // Namespace FBX -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.h b/thirdparty/assimp/code/FBX/FBXExportProperty.h deleted file mode 100644 index d692fe6ee35f..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExportProperty.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -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 FBXExportProperty.h -* Declares the FBX::Property helper class for fbx export. -*/ -#ifndef AI_FBXEXPORTPROPERTY_H_INC -#define AI_FBXEXPORTPROPERTY_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include // aiMatrix4x4 -#include // StreamWriterLE - -#include -#include -#include -#include // is_void - -namespace Assimp { -namespace FBX { - -/** @brief FBX::Property - * - * Holds a value of any of FBX's recognized types, - * each represented by a particular one-character code. - * C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true - * Y : 2-byte int16 - * I : 4-byte int32 - * F : 4-byte float - * D : 8-byte double - * L : 8-byte int64 - * i : array of int32 - * f : array of float - * d : array of double - * l : array of int64 - * b : array of 1-byte booleans (0x00 or 0x01) - * S : string (array of 1-byte char) - * R : raw data (array of bytes) - */ -class FBXExportProperty { -public: - // constructors for basic types. - // all explicit to avoid accidental typecasting - explicit FBXExportProperty(bool v); - // TODO: determine if there is actually a byte type, - // or if this always means . 'C' seems to imply , - // so possibly the above was intended to represent both. - explicit FBXExportProperty(int16_t v); - explicit FBXExportProperty(int32_t v); - explicit FBXExportProperty(float v); - explicit FBXExportProperty(double v); - explicit FBXExportProperty(int64_t v); - // strings can either be stored as 'R' (raw) or 'S' (string) type - explicit FBXExportProperty(const char* c, bool raw = false); - explicit FBXExportProperty(const std::string& s, bool raw = false); - explicit FBXExportProperty(const std::vector& r); - explicit FBXExportProperty(const std::vector& va); - explicit FBXExportProperty(const std::vector& va); - explicit FBXExportProperty(const std::vector& va); - explicit FBXExportProperty(const std::vector& va); - explicit FBXExportProperty(const aiMatrix4x4& vm); - - // this will catch any type not defined above, - // so that we don't accidentally convert something we don't want. - // for example (const char*) --> (bool)... seriously wtf C++ - template - explicit FBXExportProperty(T v) : type('X') { - static_assert(std::is_void::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION"); - } // note: no line wrap so it appears verbatim on the compiler error - - // the size of this property node in a binary file, in bytes - size_t size(); - - // write this property node as binary data to the given stream - void DumpBinary(Assimp::StreamWriterLE& s); - void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0); - void DumpAscii(std::ostream& s, int indent = 0); - // note: make sure the ostream is in classic "C" locale - -private: - char type; - std::vector data; -}; - -} // Namespace FBX -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTPROPERTY_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXExporter.cpp b/thirdparty/assimp/code/FBX/FBXExporter.cpp deleted file mode 100644 index 9316dc4f0269..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExporter.cpp +++ /dev/null @@ -1,2556 +0,0 @@ -/* -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 ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExporter.h" -#include "FBXExportNode.h" -#include "FBXExportProperty.h" -#include "FBXCommon.h" -#include "FBXUtil.h" - -#include // aiGetVersion -#include -#include -#include -#include // StreamWriterLE -#include // DeadlyExportError -#include // aiTextureType -#include -#include - -// Header files, standard library. -#include // shared_ptr -#include -#include // stringstream -#include // localtime, tm_* -#include -#include -#include -#include -#include -#include - -// RESOURCES: -// https://code.blender.org/2013/08/fbx-binary-file-format-specification/ -// https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure - -const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian - -using namespace Assimp; -using namespace Assimp::FBX; - -// some constants that we'll use for writing metadata -namespace Assimp { -namespace FBX { - const std::string EXPORT_VERSION_STR = "7.4.0"; - const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015 - // FBX files have some hashed values that depend on the creation time field, - // but for now we don't actually know how to generate these. - // what we can do is set them to a known-working version. - // this is the data that Blender uses in their FBX export process. - const std::string GENERIC_CTIME = "1970-01-01 10:00:00:000"; - const std::string GENERIC_FILEID = - "\x28\xb3\x2a\xeb\xb6\x24\xcc\xc2\xbf\xc8\xb0\x2a\xa9\x2b\xfc\xf1"; - const std::string GENERIC_FOOTID = - "\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e"; - const std::string FOOT_MAGIC = - "\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b"; - const std::string COMMENT_UNDERLINE = - ";------------------------------------------------------------------"; -} - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to binary FBX. - // Prototyped and registered in Exporter.cpp - void ExportSceneFBX ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - ){ - // initialize the exporter - FBXExporter exporter(pScene, pProperties); - - // perform binary export - exporter.ExportBinary(pFile, pIOSystem); - } - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to ASCII FBX. - // Prototyped and registered in Exporter.cpp - void ExportSceneFBXA ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - - ){ - // initialize the exporter - FBXExporter exporter(pScene, pProperties); - - // perform ascii export - exporter.ExportAscii(pFile, pIOSystem); - } - -} // end of namespace Assimp - -FBXExporter::FBXExporter ( const aiScene* pScene, const ExportProperties* pProperties ) -: binary(false) -, mScene(pScene) -, mProperties(pProperties) -, outfile() -, connections() -, mesh_uids() -, material_uids() -, node_uids() { - // will probably need to determine UIDs, connections, etc here. - // basically anything that needs to be known - // before we start writing sections to the stream. -} - -void FBXExporter::ExportBinary ( - const char* pFile, - IOSystem* pIOSystem -){ - // remember that we're exporting in binary mode - binary = true; - - // we're not currently using these preferences, - // but clang will cry about it if we never touch it. - // TODO: some of these might be relevant to export - (void)mProperties; - - // open the indicated file for writing (in binary mode) - outfile.reset(pIOSystem->Open(pFile,"wb")); - if (!outfile) { - throw DeadlyExportError( - "could not open output .fbx file: " + std::string(pFile) - ); - } - - // first a binary-specific file header - WriteBinaryHeader(); - - // the rest of the file is in node entries. - // we have to serialize each entry before we write to the output, - // as the first thing we write is the byte offset of the _next_ entry. - // Either that or we can skip back to write the offset when we finish. - WriteAllNodes(); - - // finally we have a binary footer to the file - WriteBinaryFooter(); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); -} - -void FBXExporter::ExportAscii ( - const char* pFile, - IOSystem* pIOSystem -){ - // remember that we're exporting in ascii mode - binary = false; - - // open the indicated file for writing in text mode - outfile.reset(pIOSystem->Open(pFile,"wt")); - if (!outfile) { - throw DeadlyExportError( - "could not open output .fbx file: " + std::string(pFile) - ); - } - - // write the ascii header - WriteAsciiHeader(); - - // write all the sections - WriteAllNodes(); - - // make sure the file ends with a newline. - // note: if the file is opened in text mode, - // this should do the right cross-platform thing. - outfile->Write("\n", 1, 1); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); -} - -void FBXExporter::WriteAsciiHeader() -{ - // basically just a comment at the top of the file - std::stringstream head; - head << "; FBX " << EXPORT_VERSION_STR << " project file\n"; - head << "; Created by the Open Asset Import Library (Assimp)\n"; - head << "; http://assimp.org\n"; - head << "; -------------------------------------------------\n"; - const std::string ascii_header = head.str(); - outfile->Write(ascii_header.c_str(), ascii_header.size(), 1); -} - -void FBXExporter::WriteAsciiSectionHeader(const std::string& title) -{ - StreamWriterLE outstream(outfile); - std::stringstream s; - s << "\n\n; " << title << '\n'; - s << FBX::COMMENT_UNDERLINE << "\n"; - outstream.PutString(s.str()); -} - -void FBXExporter::WriteBinaryHeader() -{ - // first a specific sequence of 23 bytes, always the same - const char binary_header[24] = "Kaydara FBX Binary\x20\x20\x00\x1a\x00"; - outfile->Write(binary_header, 1, 23); - - // then FBX version number, "multiplied" by 1000, as little-endian uint32. - // so 7.3 becomes 7300 == 0x841C0000, 7.4 becomes 7400 == 0xE81C0000, etc - { - StreamWriterLE outstream(outfile); - outstream.PutU4(EXPORT_VERSION_INT); - } // StreamWriter destructor writes the data to the file - - // after this the node data starts immediately - // (probably with the FBXHEaderExtension node) -} - -void FBXExporter::WriteBinaryFooter() -{ - outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1); - - outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1); - - // here some padding is added for alignment to 16 bytes. - // if already aligned, the full 16 bytes is added. - size_t pos = outfile->Tell(); - size_t pad = 16 - (pos % 16); - for (size_t i = 0; i < pad; ++i) { - outfile->Write("\x00", 1, 1); - } - - // not sure what this is, but it seems to always be 0 in modern files - for (size_t i = 0; i < 4; ++i) { - outfile->Write("\x00", 1, 1); - } - - // now the file version again - { - StreamWriterLE outstream(outfile); - outstream.PutU4(EXPORT_VERSION_INT); - } // StreamWriter destructor writes the data to the file - - // and finally some binary footer added to all files - for (size_t i = 0; i < 120; ++i) { - outfile->Write("\x00", 1, 1); - } - outfile->Write(FOOT_MAGIC.c_str(), FOOT_MAGIC.size(), 1); -} - -void FBXExporter::WriteAllNodes () -{ - // header - // (and fileid, creation time, creator, if binary) - WriteHeaderExtension(); - - // global settings - WriteGlobalSettings(); - - // documents - WriteDocuments(); - - // references - WriteReferences(); - - // definitions - WriteDefinitions(); - - // objects - WriteObjects(); - - // connections - WriteConnections(); - - // WriteTakes? (deprecated since at least 2015 (fbx 7.4)) -} - -//FBXHeaderExtension top-level node -void FBXExporter::WriteHeaderExtension () -{ - if (!binary) { - // no title, follows directly from the top comment - } - FBX::Node n("FBXHeaderExtension"); - StreamWriterLE outstream(outfile); - int indent = 0; - - // begin node - n.Begin(outstream, binary, indent); - - // write properties - // (none) - - // finish properties - n.EndProperties(outstream, binary, indent, 0); - - // begin children - n.BeginChildren(outstream, binary, indent); - - indent = 1; - - // write child nodes - FBX::Node::WritePropertyNode( - "FBXHeaderVersion", int32_t(1003), outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent - ); - if (binary) { - FBX::Node::WritePropertyNode( - "EncryptionType", int32_t(0), outstream, binary, indent - ); - } - - FBX::Node CreationTimeStamp("CreationTimeStamp"); - time_t rawtime; - time(&rawtime); - struct tm * now = localtime(&rawtime); - CreationTimeStamp.AddChild("Version", int32_t(1000)); - CreationTimeStamp.AddChild("Year", int32_t(now->tm_year + 1900)); - CreationTimeStamp.AddChild("Month", int32_t(now->tm_mon + 1)); - CreationTimeStamp.AddChild("Day", int32_t(now->tm_mday)); - CreationTimeStamp.AddChild("Hour", int32_t(now->tm_hour)); - CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min)); - CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec)); - CreationTimeStamp.AddChild("Millisecond", int32_t(0)); - CreationTimeStamp.Dump(outstream, binary, indent); - - std::stringstream creator; - creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor() - << "." << aiGetVersionMinor() << "." << aiGetVersionRevision(); - FBX::Node::WritePropertyNode( - "Creator", creator.str(), outstream, binary, indent - ); - - //FBX::Node sceneinfo("SceneInfo"); - //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo"); - // not sure if any of this is actually needed, - // so just write an empty node for now. - //sceneinfo.Dump(outstream, binary, indent); - - indent = 0; - - // finish node - n.End(outstream, binary, indent, true); - - // that's it for FBXHeaderExtension... - if (!binary) { return; } - - // but binary files also need top-level FileID, CreationTime, Creator: - std::vector raw(GENERIC_FILEID.size()); - for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) { - raw[i] = uint8_t(GENERIC_FILEID[i]); - } - FBX::Node::WritePropertyNode( - "FileId", raw, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "CreationTime", GENERIC_CTIME, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "Creator", creator.str(), outstream, binary, indent - ); -} - -void FBXExporter::WriteGlobalSettings () -{ - if (!binary) { - // no title, follows directly from the header extension - } - FBX::Node gs("GlobalSettings"); - gs.AddChild("Version", int32_t(1000)); - - FBX::Node p("Properties70"); - p.AddP70int("UpAxis", 1); - p.AddP70int("UpAxisSign", 1); - p.AddP70int("FrontAxis", 2); - p.AddP70int("FrontAxisSign", 1); - p.AddP70int("CoordAxis", 0); - p.AddP70int("CoordAxisSign", 1); - p.AddP70int("OriginalUpAxis", 1); - p.AddP70int("OriginalUpAxisSign", 1); - p.AddP70double("UnitScaleFactor", 1.0); - p.AddP70double("OriginalUnitScaleFactor", 1.0); - p.AddP70color("AmbientColor", 0.0, 0.0, 0.0); - p.AddP70string("DefaultCamera", "Producer Perspective"); - p.AddP70enum("TimeMode", 11); - p.AddP70enum("TimeProtocol", 2); - p.AddP70enum("SnapOnFrameMode", 0); - p.AddP70time("TimeSpanStart", 0); // TODO: animation support - p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support - p.AddP70double("CustomFrameRate", -1.0); - p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is - p.AddP70int("CurrentTimeMarker", -1); - gs.AddChild(p); - - gs.Dump(outfile, binary, 0); -} - -void FBXExporter::WriteDocuments () -{ - if (!binary) { - WriteAsciiSectionHeader("Documents Description"); - } - - // not sure what the use of multiple documents would be, - // or whether any end-application supports it - FBX::Node docs("Documents"); - docs.AddChild("Count", int32_t(1)); - FBX::Node doc("Document"); - - // generate uid - int64_t uid = generate_uid(); - doc.AddProperties(uid, "", "Scene"); - FBX::Node p("Properties70"); - p.AddP70("SourceObject", "object", "", ""); // what is this even for? - p.AddP70string("ActiveAnimStackName", ""); // should do this properly? - doc.AddChild(p); - - // UID for root node in scene hierarchy. - // always set to 0 in the case of a single document. - // not sure what happens if more than one document exists, - // but that won't matter to us as we're exporting a single scene. - doc.AddChild("RootNode", int64_t(0)); - - docs.AddChild(doc); - docs.Dump(outfile, binary, 0); -} - -void FBXExporter::WriteReferences () -{ - if (!binary) { - WriteAsciiSectionHeader("Document References"); - } - // always empty for now. - // not really sure what this is for. - FBX::Node n("References"); - n.force_has_children = true; - n.Dump(outfile, binary, 0); -} - - -// --------------------------------------------------------------- -// some internal helper functions used for writing the definitions -// (before any actual data is written) -// --------------------------------------------------------------- - -size_t count_nodes(const aiNode* n) { - size_t count = 1; - for (size_t i = 0; i < n->mNumChildren; ++i) { - count += count_nodes(n->mChildren[i]); - } - return count; -} - -bool has_phong_mat(const aiScene* scene) -{ - // just search for any material with a shininess exponent - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - float shininess = 0; - mat->Get(AI_MATKEY_SHININESS, shininess); - if (shininess > 0) { - return true; - } - } - return false; -} - -size_t count_images(const aiScene* scene) { - std::unordered_set images; - aiString texpath; - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - const aiTextureType textype = static_cast(tt); - const size_t texcount = mat->GetTextureCount(textype); - for (unsigned int j = 0; j < texcount; ++j) { - mat->GetTexture(textype, j, &texpath); - images.insert(std::string(texpath.C_Str())); - } - } - } - return images.size(); -} - -size_t count_textures(const aiScene* scene) { - size_t count = 0; - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - // TODO: handle layered textures - if (mat->GetTextureCount(static_cast(tt)) > 0) { - count += 1; - } - } - } - return count; -} - -size_t count_deformers(const aiScene* scene) { - size_t count = 0; - for (size_t i = 0; i < scene->mNumMeshes; ++i) { - const size_t n = scene->mMeshes[i]->mNumBones; - if (n) { - // 1 main deformer, 1 subdeformer per bone - count += n + 1; - } - } - return count; -} - -void FBXExporter::WriteDefinitions () -{ - // basically this is just bookkeeping: - // determining how many of each type of object there are - // and specifying the base properties to use when otherwise unspecified. - - // ascii section header - if (!binary) { - WriteAsciiSectionHeader("Object definitions"); - } - - // we need to count the objects - int32_t count; - int32_t total_count = 0; - - // and store them - std::vector object_nodes; - FBX::Node n, pt, p; - - // GlobalSettings - // this seems to always be here in Maya exports - n = FBX::Node("ObjectType", "GlobalSettings"); - count = 1; - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - - // AnimationStack / FbxAnimStack - // this seems to always be here in Maya exports, - // but no harm seems to come of leaving it out. - count = mScene->mNumAnimations; - if (count) { - n = FBX::Node("ObjectType", "AnimationStack"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxAnimStack"); - p = FBX::Node("Properties70"); - p.AddP70string("Description", ""); - p.AddP70time("LocalStart", 0); - p.AddP70time("LocalStop", 0); - p.AddP70time("ReferenceStart", 0); - p.AddP70time("ReferenceStop", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationLayer / FbxAnimLayer - // this seems to always be here in Maya exports, - // but no harm seems to come of leaving it out. - // Assimp doesn't support animation layers, - // so there will be one per aiAnimation - count = mScene->mNumAnimations; - if (count) { - n = FBX::Node("ObjectType", "AnimationLayer"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FBXAnimLayer"); - p = FBX::Node("Properties70"); - p.AddP70("Weight", "Number", "", "A", double(100)); - p.AddP70bool("Mute", 0); - p.AddP70bool("Solo", 0); - p.AddP70bool("Lock", 0); - p.AddP70color("Color", 0.8, 0.8, 0.8); - p.AddP70("BlendMode", "enum", "", "", int32_t(0)); - p.AddP70("RotationAccumulationMode", "enum", "", "", int32_t(0)); - p.AddP70("ScaleAccumulationMode", "enum", "", "", int32_t(0)); - p.AddP70("BlendModeBypass", "ULongLong", "", "", int64_t(0)); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // NodeAttribute - // this is completely absurd. - // there can only be one "NodeAttribute" template, - // but FbxSkeleton, FbxCamera, FbxLight all are "NodeAttributes". - // so if only one exists we should set the template for that, - // otherwise... we just pick one :/. - // the others have to set all their properties every instance, - // because there's no template. - count = 1; // TODO: select properly - if (count) { - // FbxSkeleton - n = FBX::Node("ObjectType", "NodeAttribute"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxSkeleton"); - p = FBX::Node("Properties70"); - p.AddP70color("Color", 0.8, 0.8, 0.8); - p.AddP70double("Size", 33.333333333333); - p.AddP70("LimbLength", "double", "Number", "H", double(1)); - // note: not sure what the "H" flag is for - hidden? - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Model / FbxNode - // <~~ node hierarchy - count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node) - if (count) { - n = FBX::Node("ObjectType", "Model"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxNode"); - p = FBX::Node("Properties70"); - p.AddP70enum("QuaternionInterpolate", 0); - p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0); - p.AddP70vector("RotationPivot", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingOffset", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingPivot", 0.0, 0.0, 0.0); - p.AddP70bool("TranslationActive", 0); - p.AddP70vector("TranslationMin", 0.0, 0.0, 0.0); - p.AddP70vector("TranslationMax", 0.0, 0.0, 0.0); - p.AddP70bool("TranslationMinX", 0); - p.AddP70bool("TranslationMinY", 0); - p.AddP70bool("TranslationMinZ", 0); - p.AddP70bool("TranslationMaxX", 0); - p.AddP70bool("TranslationMaxY", 0); - p.AddP70bool("TranslationMaxZ", 0); - p.AddP70enum("RotationOrder", 0); - p.AddP70bool("RotationSpaceForLimitOnly", 0); - p.AddP70double("RotationStiffnessX", 0.0); - p.AddP70double("RotationStiffnessY", 0.0); - p.AddP70double("RotationStiffnessZ", 0.0); - p.AddP70double("AxisLen", 10.0); - p.AddP70vector("PreRotation", 0.0, 0.0, 0.0); - p.AddP70vector("PostRotation", 0.0, 0.0, 0.0); - p.AddP70bool("RotationActive", 0); - p.AddP70vector("RotationMin", 0.0, 0.0, 0.0); - p.AddP70vector("RotationMax", 0.0, 0.0, 0.0); - p.AddP70bool("RotationMinX", 0); - p.AddP70bool("RotationMinY", 0); - p.AddP70bool("RotationMinZ", 0); - p.AddP70bool("RotationMaxX", 0); - p.AddP70bool("RotationMaxY", 0); - p.AddP70bool("RotationMaxZ", 0); - p.AddP70enum("InheritType", 0); - p.AddP70bool("ScalingActive", 0); - p.AddP70vector("ScalingMin", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingMax", 1.0, 1.0, 1.0); - p.AddP70bool("ScalingMinX", 0); - p.AddP70bool("ScalingMinY", 0); - p.AddP70bool("ScalingMinZ", 0); - p.AddP70bool("ScalingMaxX", 0); - p.AddP70bool("ScalingMaxY", 0); - p.AddP70bool("ScalingMaxZ", 0); - p.AddP70vector("GeometricTranslation", 0.0, 0.0, 0.0); - p.AddP70vector("GeometricRotation", 0.0, 0.0, 0.0); - p.AddP70vector("GeometricScaling", 1.0, 1.0, 1.0); - p.AddP70double("MinDampRangeX", 0.0); - p.AddP70double("MinDampRangeY", 0.0); - p.AddP70double("MinDampRangeZ", 0.0); - p.AddP70double("MaxDampRangeX", 0.0); - p.AddP70double("MaxDampRangeY", 0.0); - p.AddP70double("MaxDampRangeZ", 0.0); - p.AddP70double("MinDampStrengthX", 0.0); - p.AddP70double("MinDampStrengthY", 0.0); - p.AddP70double("MinDampStrengthZ", 0.0); - p.AddP70double("MaxDampStrengthX", 0.0); - p.AddP70double("MaxDampStrengthY", 0.0); - p.AddP70double("MaxDampStrengthZ", 0.0); - p.AddP70double("PreferedAngleX", 0.0); - p.AddP70double("PreferedAngleY", 0.0); - p.AddP70double("PreferedAngleZ", 0.0); - p.AddP70("LookAtProperty", "object", "", ""); - p.AddP70("UpVectorProperty", "object", "", ""); - p.AddP70bool("Show", 1); - p.AddP70bool("NegativePercentShapeSupport", 1); - p.AddP70int("DefaultAttributeIndex", -1); - p.AddP70bool("Freeze", 0); - p.AddP70bool("LODBox", 0); - p.AddP70( - "Lcl Translation", "Lcl Translation", "", "A", - double(0), double(0), double(0) - ); - p.AddP70( - "Lcl Rotation", "Lcl Rotation", "", "A", - double(0), double(0), double(0) - ); - p.AddP70( - "Lcl Scaling", "Lcl Scaling", "", "A", - double(1), double(1), double(1) - ); - p.AddP70("Visibility", "Visibility", "", "A", double(1)); - p.AddP70( - "Visibility Inheritance", "Visibility Inheritance", "", "", - int32_t(1) - ); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Geometry / FbxMesh - // <~~ aiMesh - count = mScene->mNumMeshes; - if (count) { - n = FBX::Node("ObjectType", "Geometry"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxMesh"); - p = FBX::Node("Properties70"); - p.AddP70color("Color", 0, 0, 0); - p.AddP70vector("BBoxMin", 0, 0, 0); - p.AddP70vector("BBoxMax", 0, 0, 0); - p.AddP70bool("Primary Visibility", 1); - p.AddP70bool("Casts Shadows", 1); - p.AddP70bool("Receive Shadows", 1); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Material / FbxSurfacePhong, FbxSurfaceLambert, FbxSurfaceMaterial - // <~~ aiMaterial - // basically if there's any phong material this is defined as phong, - // and otherwise lambert. - // More complex materials cause a bare-bones FbxSurfaceMaterial definition - // and are treated specially, as they're not really supported by FBX. - // TODO: support Maya's Stingray PBS material - count = mScene->mNumMaterials; - if (count) { - bool has_phong = has_phong_mat(mScene); - n = FBX::Node("ObjectType", "Material"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate"); - if (has_phong) { - pt.AddProperty("FbxSurfacePhong"); - } else { - pt.AddProperty("FbxSurfaceLambert"); - } - p = FBX::Node("Properties70"); - if (has_phong) { - p.AddP70string("ShadingModel", "Phong"); - } else { - p.AddP70string("ShadingModel", "Lambert"); - } - p.AddP70bool("MultiLayer", 0); - p.AddP70colorA("EmissiveColor", 0.0, 0.0, 0.0); - p.AddP70numberA("EmissiveFactor", 1.0); - p.AddP70colorA("AmbientColor", 0.2, 0.2, 0.2); - p.AddP70numberA("AmbientFactor", 1.0); - p.AddP70colorA("DiffuseColor", 0.8, 0.8, 0.8); - p.AddP70numberA("DiffuseFactor", 1.0); - p.AddP70vector("Bump", 0.0, 0.0, 0.0); - p.AddP70vector("NormalMap", 0.0, 0.0, 0.0); - p.AddP70double("BumpFactor", 1.0); - p.AddP70colorA("TransparentColor", 0.0, 0.0, 0.0); - p.AddP70numberA("TransparencyFactor", 0.0); - p.AddP70color("DisplacementColor", 0.0, 0.0, 0.0); - p.AddP70double("DisplacementFactor", 1.0); - p.AddP70color("VectorDisplacementColor", 0.0, 0.0, 0.0); - p.AddP70double("VectorDisplacementFactor", 1.0); - if (has_phong) { - p.AddP70colorA("SpecularColor", 0.2, 0.2, 0.2); - p.AddP70numberA("SpecularFactor", 1.0); - p.AddP70numberA("ShininessExponent", 20.0); - p.AddP70colorA("ReflectionColor", 0.0, 0.0, 0.0); - p.AddP70numberA("ReflectionFactor", 1.0); - } - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Video / FbxVideo - // one for each image file. - count = int32_t(count_images(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Video"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxVideo"); - p = FBX::Node("Properties70"); - p.AddP70bool("ImageSequence", 0); - p.AddP70int("ImageSequenceOffset", 0); - p.AddP70double("FrameRate", 0.0); - p.AddP70int("LastFrame", 0); - p.AddP70int("Width", 0); - p.AddP70int("Height", 0); - p.AddP70("Path", "KString", "XRefUrl", "", ""); - p.AddP70int("StartFrame", 0); - p.AddP70int("StopFrame", 0); - p.AddP70double("PlaySpeed", 0.0); - p.AddP70time("Offset", 0); - p.AddP70enum("InterlaceMode", 0); - p.AddP70bool("FreeRunning", 0); - p.AddP70bool("Loop", 0); - p.AddP70enum("AccessMode", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Texture / FbxFileTexture - // <~~ aiTexture - count = int32_t(count_textures(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Texture"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxFileTexture"); - p = FBX::Node("Properties70"); - p.AddP70enum("TextureTypeUse", 0); - p.AddP70numberA("Texture alpha", 1.0); - p.AddP70enum("CurrentMappingType", 0); - p.AddP70enum("WrapModeU", 0); - p.AddP70enum("WrapModeV", 0); - p.AddP70bool("UVSwap", 0); - p.AddP70bool("PremultiplyAlpha", 1); - p.AddP70vectorA("Translation", 0.0, 0.0, 0.0); - p.AddP70vectorA("Rotation", 0.0, 0.0, 0.0); - p.AddP70vectorA("Scaling", 1.0, 1.0, 1.0); - p.AddP70vector("TextureRotationPivot", 0.0, 0.0, 0.0); - p.AddP70vector("TextureScalingPivot", 0.0, 0.0, 0.0); - p.AddP70enum("CurrentTextureBlendMode", 1); - p.AddP70string("UVSet", "default"); - p.AddP70bool("UseMaterial", 0); - p.AddP70bool("UseMipMap", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationCurveNode / FbxAnimCurveNode - count = mScene->mNumAnimations * 3; - if (count) { - n = FBX::Node("ObjectType", "AnimationCurveNode"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode"); - p = FBX::Node("Properties70"); - p.AddP70("d", "Compound", "", ""); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationCurve / FbxAnimCurve - count = mScene->mNumAnimations * 9; - if (count) { - n = FBX::Node("ObjectType", "AnimationCurve"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // Pose - count = 0; - for (size_t i = 0; i < mScene->mNumMeshes; ++i) { - aiMesh* mesh = mScene->mMeshes[i]; - if (mesh->HasBones()) { ++count; } - } - if (count) { - n = FBX::Node("ObjectType", "Pose"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // Deformer - count = int32_t(count_deformers(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Deformer"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // (template) - count = 0; - if (count) { - n = FBX::Node("ObjectType", ""); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", ""); - p = FBX::Node("Properties70"); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // now write it all - FBX::Node defs("Definitions"); - defs.AddChild("Version", int32_t(100)); - defs.AddChild("Count", int32_t(total_count)); - for (auto &n : object_nodes) { defs.AddChild(n); } - defs.Dump(outfile, binary, 0); -} - - -// ------------------------------------------------------------------- -// some internal helper functions used for writing the objects section -// (which holds the actual data) -// ------------------------------------------------------------------- - -aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) -{ - for (size_t i = 0; i < node->mNumMeshes; ++i) { - if (node->mMeshes[i] == meshIndex) { - return node; - } - } - for (size_t i = 0; i < node->mNumChildren; ++i) { - aiNode* ret = get_node_for_mesh(meshIndex, node->mChildren[i]); - if (ret) { return ret; } - } - return nullptr; -} - -aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) -{ - std::vector node_chain; - while (node != scene->mRootNode) { - node_chain.push_back(node); - node = node->mParent; - } - aiMatrix4x4 transform; - for (auto n = node_chain.rbegin(); n != node_chain.rend(); ++n) { - transform *= (*n)->mTransformation; - } - return transform; -} - -int64_t to_ktime(double ticks, const aiAnimation* anim) { - if (anim->mTicksPerSecond <= 0) { - return static_cast(ticks) * FBX::SECOND; - } - return (static_cast(ticks) / static_cast(anim->mTicksPerSecond)) * FBX::SECOND; -} - -int64_t to_ktime(double time) { - return (static_cast(time * FBX::SECOND)); -} - -void FBXExporter::WriteObjects () -{ - if (!binary) { - WriteAsciiSectionHeader("Object properties"); - } - // numbers should match those given in definitions! make sure to check - StreamWriterLE outstream(outfile); - FBX::Node object_node("Objects"); - int indent = 0; - object_node.Begin(outstream, binary, indent); - object_node.EndProperties(outstream, binary, indent); - object_node.BeginChildren(outstream, binary, indent); - - bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true); - std::vector> vVertexIndice;//save vertex_indices as it is needed later - - // geometry (aiMesh) - mesh_uids.clear(); - indent = 1; - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - // it's all about this mesh - aiMesh* m = mScene->mMeshes[mi]; - - // start the node record - FBX::Node n("Geometry"); - int64_t uid = generate_uid(); - mesh_uids.push_back(uid); - n.AddProperty(uid); - n.AddProperty(FBX::SEPARATOR + "Geometry"); - n.AddProperty("Mesh"); - n.Begin(outstream, binary, indent); - n.DumpProperties(outstream, binary, indent); - n.EndProperties(outstream, binary, indent); - n.BeginChildren(outstream, binary, indent); - indent = 2; - - // output vertex data - each vertex should be unique (probably) - std::vector flattened_vertices; - // index of original vertex in vertex data vector - std::vector vertex_indices; - // map of vertex value to its index in the data vector - std::map index_by_vertex_value; - if(bJoinIdenticalVertices){ - int32_t index = 0; - for (size_t vi = 0; vi < m->mNumVertices; ++vi) { - aiVector3D vtx = m->mVertices[vi]; - auto elem = index_by_vertex_value.find(vtx); - if (elem == index_by_vertex_value.end()) { - vertex_indices.push_back(index); - index_by_vertex_value[vtx] = index; - flattened_vertices.push_back(vtx[0]); - flattened_vertices.push_back(vtx[1]); - flattened_vertices.push_back(vtx[2]); - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); - } - } - } - else { // do not join vertex, respect the export flag - vertex_indices.resize(m->mNumVertices); - std::iota(vertex_indices.begin(), vertex_indices.end(), 0); - for(unsigned int v = 0; v < m->mNumVertices; ++ v) { - aiVector3D vtx = m->mVertices[v]; - flattened_vertices.push_back(vtx.x); - flattened_vertices.push_back(vtx.y); - flattened_vertices.push_back(vtx.z); - } - } - vVertexIndice.push_back(vertex_indices); - - FBX::Node::WritePropertyNode( - "Vertices", flattened_vertices, outstream, binary, indent - ); - - // output polygon data as a flattened array of vertex indices. - // the last vertex index of each polygon is negated and - 1 - std::vector polygon_data; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices - 1; ++pvi) { - polygon_data.push_back(vertex_indices[f.mIndices[pvi]]); - } - polygon_data.push_back( - -1 - vertex_indices[f.mIndices[f.mNumIndices-1]] - ); - } - FBX::Node::WritePropertyNode( - "PolygonVertexIndex", polygon_data, outstream, binary, indent - ); - - // here could be edges but they're insane. - // it's optional anyway, so let's ignore it. - - FBX::Node::WritePropertyNode( - "GeometryVersion", int32_t(124), outstream, binary, indent - ); - - // normals, if any - if (m->HasNormals()) { - FBX::Node normals("LayerElementNormal", int32_t(0)); - normals.Begin(outstream, binary, indent); - normals.DumpProperties(outstream, binary, indent); - normals.EndProperties(outstream, binary, indent); - normals.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - // TODO: vertex-normals or indexed normals when appropriate - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector normal_data; - normal_data.reserve(3 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &n = m->mNormals[f.mIndices[pvi]]; - normal_data.push_back(n.x); - normal_data.push_back(n.y); - normal_data.push_back(n.z); - } - } - FBX::Node::WritePropertyNode( - "Normals", normal_data, outstream, binary, indent - ); - // note: version 102 has a NormalsW also... not sure what it is, - // so we can stick with version 101 for now. - indent = 2; - normals.End(outstream, binary, indent, true); - } - - // colors, if any - // TODO only one color channel currently - const int32_t colorChannelIndex = 0; - if (m->HasVertexColors(colorChannelIndex)) { - FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex)); - vertexcolors.Begin(outstream, binary, indent); - vertexcolors.DumpProperties(outstream, binary, indent); - vertexcolors.EndProperties(outstream, binary, indent); - vertexcolors.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - char layerName[8]; - sprintf(layerName, "COLOR_%d", colorChannelIndex); - FBX::Node::WritePropertyNode( - "Name", (const char*)layerName, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector color_data; - color_data.reserve(4 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]]; - color_data.push_back(c.r); - color_data.push_back(c.g); - color_data.push_back(c.b); - color_data.push_back(c.a); - } - } - FBX::Node::WritePropertyNode( - "Colors", color_data, outstream, binary, indent - ); - indent = 2; - vertexcolors.End(outstream, binary, indent, true); - } - - // uvs, if any - for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) { - if (m->mNumUVComponents[uvi] > 2) { - // FBX only supports 2-channel UV maps... - // or at least i'm not sure how to indicate a different number - std::stringstream err; - err << "Only 2-channel UV maps supported by FBX,"; - err << " but mesh " << mi; - if (m->mName.length) { - err << " (" << m->mName.C_Str() << ")"; - } - err << " UV map " << uvi; - err << " has " << m->mNumUVComponents[uvi]; - err << " components! Data will be preserved,"; - err << " but may be incorrectly interpreted on load."; - ASSIMP_LOG_WARN(err.str()); - } - FBX::Node uv("LayerElementUV", int32_t(uvi)); - uv.Begin(outstream, binary, indent); - uv.DumpProperties(outstream, binary, indent); - uv.EndProperties(outstream, binary, indent); - uv.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - // it doesn't seem like assimp keeps the uv map name, - // so just leave it blank. - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "IndexToDirect", - outstream, binary, indent - ); - - std::vector uv_data; - std::vector uv_indices; - std::map index_by_uv; - int32_t index = 0; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &uv = - m->mTextureCoords[uvi][f.mIndices[pvi]]; - auto elem = index_by_uv.find(uv); - if (elem == index_by_uv.end()) { - index_by_uv[uv] = index; - uv_indices.push_back(index); - for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) { - uv_data.push_back(uv[x]); - } - ++index; - } else { - uv_indices.push_back(elem->second); - } - } - } - FBX::Node::WritePropertyNode( - "UV", uv_data, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "UVIndex", uv_indices, outstream, binary, indent - ); - indent = 2; - uv.End(outstream, binary, indent, true); - } - - // i'm not really sure why this material section exists, - // as the material is linked via "Connections". - // it seems to always have the same "0" value. - FBX::Node mat("LayerElementMaterial", int32_t(0)); - mat.AddChild("Version", int32_t(101)); - mat.AddChild("Name", ""); - mat.AddChild("MappingInformationType", "AllSame"); - mat.AddChild("ReferenceInformationType", "IndexToDirect"); - std::vector mat_indices = {0}; - mat.AddChild("Materials", mat_indices); - mat.Dump(outstream, binary, indent); - - // finally we have the layer specifications, - // which select the normals / UV set / etc to use. - // TODO: handle multiple uv sets correctly? - FBX::Node layer("Layer", int32_t(0)); - layer.AddChild("Version", int32_t(100)); - FBX::Node le("LayerElement"); - le.AddChild("Type", "LayerElementNormal"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - // TODO only 1 color channel currently - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementColor"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementMaterial"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementUV"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - layer.Dump(outstream, binary, indent); - - for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr) - { - FBX::Node layerExtra("Layer", int32_t(lr)); - layerExtra.AddChild("Version", int32_t(100)); - FBX::Node leExtra("LayerElement"); - leExtra.AddChild("Type", "LayerElementUV"); - leExtra.AddChild("TypedIndex", int32_t(lr)); - layerExtra.AddChild(leExtra); - layerExtra.Dump(outstream, binary, indent); - } - // finish the node record - indent = 1; - n.End(outstream, binary, indent, true); - } - - // aiMaterial - material_uids.clear(); - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - // it's all about this material - aiMaterial* m = mScene->mMaterials[i]; - - // these are used to receive material data - float f; aiColor3D c; - - // start the node record - FBX::Node n("Material"); - - int64_t uid = generate_uid(); - material_uids.push_back(uid); - n.AddProperty(uid); - - aiString name; - m->Get(AI_MATKEY_NAME, name); - n.AddProperty(name.C_Str() + FBX::SEPARATOR + "Material"); - - n.AddProperty(""); - - n.AddChild("Version", int32_t(102)); - f = 0; - m->Get(AI_MATKEY_SHININESS, f); - bool phong = (f > 0); - if (phong) { - n.AddChild("ShadingModel", "phong"); - } else { - n.AddChild("ShadingModel", "lambert"); - } - n.AddChild("MultiLayer", int32_t(0)); - - FBX::Node p("Properties70"); - - // materials exported using the FBX SDK have two sets of fields. - // there are the properties specified in the PropertyTemplate, - // which are those supported by the modernFBX SDK, - // and an extra set of properties with simpler names. - // The extra properties are a legacy material system from pre-2009. - // - // In the modern system, each property has "color" and "factor". - // Generally the interpretation of these seems to be - // that the colour is multiplied by the factor before use, - // but this is not always clear-cut. - // - // Usually assimp only stores the colour, - // so we can just leave the factors at the default "1.0". - - // first we can export the "standard" properties - if (m->Get(AI_MATKEY_COLOR_AMBIENT, c) == aiReturn_SUCCESS) { - p.AddP70colorA("AmbientColor", c.r, c.g, c.b); - //p.AddP70numberA("AmbientFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_DIFFUSE, c) == aiReturn_SUCCESS) { - p.AddP70colorA("DiffuseColor", c.r, c.g, c.b); - //p.AddP70numberA("DiffuseFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) { - // "TransparentColor" / "TransparencyFactor"... - // thanks FBX, for your insightful interpretation of consistency - p.AddP70colorA("TransparentColor", c.r, c.g, c.b); - // TransparencyFactor defaults to 0.0, so set it to 1.0. - // note: Maya always sets this to 1.0, - // so we can't use it sensibly as "Opacity". - // In stead we rely on the legacy "Opacity" value, below. - // Blender also relies on "Opacity" not "TransparencyFactor", - // probably for a similar reason. - p.AddP70numberA("TransparencyFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) { - p.AddP70colorA("ReflectionColor", c.r, c.g, c.b); - } - if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ReflectionFactor", f); - } - if (phong) { - if (m->Get(AI_MATKEY_COLOR_SPECULAR, c) == aiReturn_SUCCESS) { - p.AddP70colorA("SpecularColor", c.r, c.g, c.b); - } - if (m->Get(AI_MATKEY_SHININESS_STRENGTH, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ShininessFactor", f); - } - if (m->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ShininessExponent", f); - } - if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ReflectionFactor", f); - } - } - - // Now the legacy system. - // For safety let's include it. - // thrse values don't exist in the property template, - // and usually are completely ignored when loading. - // One notable exception is the "Opacity" property, - // which Blender uses as (1.0 - alpha). - c.r = 0.0f; c.g = 0.0f; c.b = 0.0f; - m->Get(AI_MATKEY_COLOR_EMISSIVE, c); - p.AddP70vector("Emissive", c.r, c.g, c.b); - c.r = 0.2f; c.g = 0.2f; c.b = 0.2f; - m->Get(AI_MATKEY_COLOR_AMBIENT, c); - p.AddP70vector("Ambient", c.r, c.g, c.b); - c.r = 0.8f; c.g = 0.8f; c.b = 0.8f; - m->Get(AI_MATKEY_COLOR_DIFFUSE, c); - p.AddP70vector("Diffuse", c.r, c.g, c.b); - // The FBX SDK determines "Opacity" from transparency colour (RGB) - // and factor (F) as: O = (1.0 - F * ((R + G + B) / 3)). - // However we actually have an opacity value, - // so we should take it from AI_MATKEY_OPACITY if possible. - // It might make more sense to use TransparencyFactor, - // but Blender actually loads "Opacity" correctly, so let's use it. - f = 1.0f; - if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) { - f = 1.0f - ((c.r + c.g + c.b) / 3.0f); - } - m->Get(AI_MATKEY_OPACITY, f); - p.AddP70double("Opacity", f); - if (phong) { - // specular color is multiplied by shininess_strength - c.r = 0.2f; c.g = 0.2f; c.b = 0.2f; - m->Get(AI_MATKEY_COLOR_SPECULAR, c); - f = 1.0f; - m->Get(AI_MATKEY_SHININESS_STRENGTH, f); - p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b); - f = 20.0f; - m->Get(AI_MATKEY_SHININESS, f); - p.AddP70double("Shininess", f); - // Legacy "Reflectivity" is F*F*((R+G+B)/3), - // where F is the proportion of light reflected (AKA reflectivity), - // and RGB is the reflective colour of the material. - // No idea why, but we might as well set it the same way. - f = 0.0f; - m->Get(AI_MATKEY_REFLECTIVITY, f); - c.r = 1.0f, c.g = 1.0f, c.b = 1.0f; - m->Get(AI_MATKEY_COLOR_REFLECTIVE, c); - p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0)); - } - - n.AddChild(p); - - n.Dump(outstream, binary, indent); - } - - // we need to look up all the images we're using, - // so we can generate uids, and eliminate duplicates. - std::map uid_by_image; - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - aiString texpath; - aiMaterial* mat = mScene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - const aiTextureType textype = static_cast(tt); - const size_t texcount = mat->GetTextureCount(textype); - for (size_t j = 0; j < texcount; ++j) { - mat->GetTexture(textype, (unsigned int)j, &texpath); - const std::string texstring = texpath.C_Str(); - auto elem = uid_by_image.find(texstring); - if (elem == uid_by_image.end()) { - uid_by_image[texstring] = generate_uid(); - } - } - } - } - - // FbxVideo - stores images used by textures. - for (const auto &it : uid_by_image) { - FBX::Node n("Video"); - const int64_t& uid = it.second; - const std::string name = ""; // TODO: ... name??? - n.AddProperties(uid, name + FBX::SEPARATOR + "Video", "Clip"); - n.AddChild("Type", "Clip"); - FBX::Node p("Properties70"); - // TODO: get full path... relative path... etc... ugh... - // for now just use the same path for everything, - // and hopefully one of them will work out. - std::string path = it.first; - // try get embedded texture - const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str()); - if (embedded_texture != nullptr) { - // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension) - std::stringstream newPath; - if (embedded_texture->mFilename.length > 0) { - newPath << embedded_texture->mFilename.C_Str(); - } else if (embedded_texture->achFormatHint[0]) { - int texture_index = std::stoi(path.substr(1, path.size() - 1)); - newPath << texture_index << "." << embedded_texture->achFormatHint; - } - path = newPath.str(); - // embed the texture - size_t texture_size = static_cast(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u)); - if (binary) { - // embed texture as binary data - std::vector tex_data; - tex_data.resize(texture_size); - memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size); - n.AddChild("Content", tex_data); - } else { - // embed texture in base64 encoding - std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size); - n.AddChild("Content", encoded_texture); - } - } - p.AddP70("Path", "KString", "XRefUrl", "", path); - n.AddChild(p); - n.AddChild("UseMipMap", int32_t(0)); - n.AddChild("Filename", path); - n.AddChild("RelativeFilename", path); - n.Dump(outstream, binary, indent); - } - - // Textures - // referenced by material_index/texture_type pairs. - std::map,int64_t> texture_uids; - const std::map prop_name_by_tt = { - {aiTextureType_DIFFUSE, "DiffuseColor"}, - {aiTextureType_SPECULAR, "SpecularColor"}, - {aiTextureType_AMBIENT, "AmbientColor"}, - {aiTextureType_EMISSIVE, "EmissiveColor"}, - {aiTextureType_HEIGHT, "Bump"}, - {aiTextureType_NORMALS, "NormalMap"}, - {aiTextureType_SHININESS, "ShininessExponent"}, - {aiTextureType_OPACITY, "TransparentColor"}, - {aiTextureType_DISPLACEMENT, "DisplacementColor"}, - //{aiTextureType_LIGHTMAP, "???"}, - {aiTextureType_REFLECTION, "ReflectionColor"} - //{aiTextureType_UNKNOWN, ""} - }; - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - // textures are attached to materials - aiMaterial* mat = mScene->mMaterials[i]; - int64_t material_uid = material_uids[i]; - - for ( - size_t j = aiTextureType_DIFFUSE; - j < aiTextureType_UNKNOWN; - ++j - ) { - const aiTextureType tt = static_cast(j); - size_t n = mat->GetTextureCount(tt); - - if (n < 1) { // no texture of this type - continue; - } - - if (n > 1) { - // TODO: multilayer textures - std::stringstream err; - err << "Multilayer textures not supported (for now),"; - err << " skipping texture type " << j; - err << " of material " << i; - ASSIMP_LOG_WARN(err.str()); - } - - // get image path for this (single-image) texture - aiString tpath; - if (mat->GetTexture(tt, 0, &tpath) != aiReturn_SUCCESS) { - std::stringstream err; - err << "Failed to get texture 0 for texture of type " << tt; - err << " on material " << i; - err << ", however GetTextureCount returned 1."; - throw DeadlyExportError(err.str()); - } - const std::string texture_path(tpath.C_Str()); - - // get connected image uid - auto elem = uid_by_image.find(texture_path); - if (elem == uid_by_image.end()) { - // this should never happen - std::stringstream err; - err << "Failed to find video element for texture with path"; - err << " \"" << texture_path << "\""; - err << ", type " << j << ", material " << i; - throw DeadlyExportError(err.str()); - } - const int64_t image_uid = elem->second; - - // get the name of the material property to connect to - auto elem2 = prop_name_by_tt.find(tt); - if (elem2 == prop_name_by_tt.end()) { - // don't know how to handle this type of texture, - // so skip it. - std::stringstream err; - err << "Not sure how to handle texture of type " << j; - err << " on material " << i; - err << ", skipping..."; - ASSIMP_LOG_WARN(err.str()); - continue; - } - const std::string& prop_name = elem2->second; - - // generate a uid for this texture - const int64_t texture_uid = generate_uid(); - - // link the texture to the material - connections.emplace_back( - "C", "OP", texture_uid, material_uid, prop_name - ); - - // link the image data to the texture - connections.emplace_back("C", "OO", image_uid, texture_uid); - - // now write the actual texture node - FBX::Node tnode("Texture"); - // TODO: some way to determine texture name? - const std::string texture_name = "" + FBX::SEPARATOR + "Texture"; - tnode.AddProperties(texture_uid, texture_name, ""); - // there really doesn't seem to be a better type than this: - tnode.AddChild("Type", "TextureVideoClip"); - tnode.AddChild("Version", int32_t(202)); - tnode.AddChild("TextureName", texture_name); - FBX::Node p("Properties70"); - p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify - //p.AddP70string("UVSet", ""); // TODO: how should this work? - p.AddP70bool("UseMaterial", 1); - tnode.AddChild(p); - // can't easily detrmine which texture path will be correct, - // so just store what we have in every field. - // these being incorrect is a common problem with FBX anyway. - tnode.AddChild("FileName", texture_path); - tnode.AddChild("RelativeFilename", texture_path); - tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0)); - tnode.AddChild("ModelUVScaling", double(1.0), double(1.0)); - tnode.AddChild("Texture_Alpha_Source", "None"); - tnode.AddChild( - "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0) - ); - tnode.Dump(outstream, binary, indent); - } - } - - // bones. - // - // output structure: - // subset of node hierarchy that are "skeleton", - // i.e. do not have meshes but only bones. - // but.. i'm not sure how anyone could guarantee that... - // - // input... - // well, for each mesh it has "bones", - // and the bone names correspond to nodes. - // of course we also need the parent nodes, - // as they give some of the transform........ - // - // well. we can assume a sane input, i suppose. - // - // so input is the bone node hierarchy, - // with an extra thing for the transformation of the MESH in BONE space. - // - // output is a set of bone nodes, - // a "bindpose" which indicates the default local transform of all bones, - // and a set of "deformers". - // each deformer is parented to a mesh geometry, - // and has one or more "subdeformer"s as children. - // each subdeformer has one bone node as a child, - // and represents the influence of that bone on the grandparent mesh. - // the subdeformer has a list of indices, and weights, - // with indices specifying vertex indices, - // and weights specifying the corresponding influence of this bone. - // it also has Transform and TransformLink elements, - // specifying the transform of the MESH in BONE space, - // and the transformation of the BONE in WORLD space, - // likely in the bindpose. - // - // the input bone structure is different but similar, - // storing the number of weights for this bone, - // and an array of (vertex index, weight) pairs. - // - // one sticky point is that the number of vertices may not match, - // because assimp splits vertices by normal, uv, etc. - - // functor for aiNode sorting - struct SortNodeByName - { - bool operator()(const aiNode *lhs, const aiNode *rhs) const - { - return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0; - } - }; - - // first we should mark the skeleton for each mesh. - // the skeleton must include not only the aiBones, - // but also all their parent nodes. - // anything that affects the position of any bone node must be included. - // Use SorNodeByName to make sure the exported result will be the same across all systems - // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent - std::vector> skeleton_by_mesh(mScene->mNumMeshes); - // at the same time we can build a list of all the skeleton nodes, - // which will be used later to mark them as type "limbNode". - std::unordered_set limbnodes; - - //actual bone nodes in fbx, without parenting-up - std::unordered_set setAllBoneNamesInScene; - for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) - { - aiMesh* pMesh = mScene->mMeshes[m]; - for(unsigned int b = 0; b < pMesh->mNumBones; ++ b) - setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data); - } - aiMatrix4x4 mxTransIdentity; - - // and a map of nodes by bone name, as finding them is annoying. - std::map node_by_bone; - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - const aiMesh* m = mScene->mMeshes[mi]; - std::set skeleton; - for (size_t bi =0; bi < m->mNumBones; ++bi) { - const aiBone* b = m->mBones[bi]; - const std::string name(b->mName.C_Str()); - auto elem = node_by_bone.find(name); - aiNode* n; - if (elem != node_by_bone.end()) { - n = elem->second; - } else { - n = mScene->mRootNode->FindNode(b->mName); - if (!n) { - // this should never happen - std::stringstream err; - err << "Failed to find node for bone: \"" << name << "\""; - throw DeadlyExportError(err.str()); - } - node_by_bone[name] = n; - limbnodes.insert(n); - } - skeleton.insert(n); - // mark all parent nodes as skeleton as well, - // up until we find the root node, - // or else the node containing the mesh, - // or else the parent of a node containig the mesh. - for ( - const aiNode* parent = n->mParent; - parent && parent != mScene->mRootNode; - parent = parent->mParent - ) { - // if we've already done this node we can skip it all - if (skeleton.count(parent)) { - break; - } - // ignore fbx transform nodes as these will be collapsed later - // TODO: cache this by aiNode* - const std::string node_name(parent->mName.C_Str()); - if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { - continue; - } - //not a bone in scene && no effect in transform - if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end() - && parent->mTransformation == mxTransIdentity) { - continue; - } - // otherwise check if this is the root of the skeleton - bool end = false; - // is the mesh part of this node? - for (size_t i = 0; i < parent->mNumMeshes; ++i) { - if (parent->mMeshes[i] == mi) { - end = true; - break; - } - } - // is the mesh in one of the children of this node? - for (size_t j = 0; j < parent->mNumChildren; ++j) { - aiNode* child = parent->mChildren[j]; - for (size_t i = 0; i < child->mNumMeshes; ++i) { - if (child->mMeshes[i] == mi) { - end = true; - break; - } - } - if (end) { break; } - } - - // if it was the skeleton root we can finish here - if (end) { break; } - } - } - skeleton_by_mesh[mi] = skeleton; - } - - // we'll need the uids for the bone nodes, so generate them now - for (size_t i = 0; i < mScene->mNumMeshes; ++i) { - auto &s = skeleton_by_mesh[i]; - for (const aiNode* n : s) { - auto elem = node_uids.find(n); - if (elem == node_uids.end()) { - node_uids[n] = generate_uid(); - } - } - } - - // now, for each aiMesh, we need to export a deformer, - // and for each aiBone a subdeformer, - // which should have all the skinning info. - // these will need to be connected properly to the mesh, - // and we can do that all now. - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - const aiMesh* m = mScene->mMeshes[mi]; - if (!m->HasBones()) { - continue; - } - // make a deformer for this mesh - int64_t deformer_uid = generate_uid(); - FBX::Node dnode("Deformer"); - dnode.AddProperties(deformer_uid, FBX::SEPARATOR + "Deformer", "Skin"); - dnode.AddChild("Version", int32_t(101)); - // "acuracy"... this is not a typo.... - dnode.AddChild("Link_DeformAcuracy", double(50)); - dnode.AddChild("SkinningType", "Linear"); // TODO: other modes? - dnode.Dump(outstream, binary, indent); - - // connect it - connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); - - //computed before - std::vector& vertex_indices = vVertexIndice[mi]; - - // TODO, FIXME: this won't work if anything is not in the bind pose. - // for now if such a situation is detected, we throw an exception. - std::set not_in_bind_pose; - std::set no_offset_matrix; - - // first get this mesh's position in world space, - // as we'll need it for each subdeformer. - // - // ...of course taking the position of the MESH doesn't make sense, - // as it can be instanced to many nodes. - // All we can do is assume no instancing, - // and take the first node we find that contains the mesh. - aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode); - aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); - - // now make a subdeformer for each bone in the skeleton - const std::set skeleton= skeleton_by_mesh[mi]; - for (const aiNode* bone_node : skeleton) { - // if there's a bone for this node, find it - const aiBone* b = nullptr; - for (size_t bi = 0; bi < m->mNumBones; ++bi) { - // TODO: this probably should index by something else - const std::string name(m->mBones[bi]->mName.C_Str()); - if (node_by_bone[name] == bone_node) { - b = m->mBones[bi]; - break; - } - } - if (!b) { - no_offset_matrix.insert(bone_node); - } - - // start the subdeformer node - const int64_t subdeformer_uid = generate_uid(); - FBX::Node sdnode("Deformer"); - sdnode.AddProperties( - subdeformer_uid, FBX::SEPARATOR + "SubDeformer", "Cluster" - ); - sdnode.AddChild("Version", int32_t(100)); - sdnode.AddChild("UserData", "", ""); - - // add indices and weights, if any - if (b) { - std::vector subdef_indices; - std::vector subdef_weights; - int32_t last_index = -1; - for (size_t wi = 0; wi < b->mNumWeights; ++wi) { - int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; - if (vi == last_index) { - // only for vertices we exported to fbx - // TODO, FIXME: this assumes identically-located vertices - // will always deform in the same way. - // as assimp doesn't store a separate list of "positions", - // there's not much that can be done about this - // other than assuming that identical position means - // identical vertex. - continue; - } - subdef_indices.push_back(vi); - subdef_weights.push_back(b->mWeights[wi].mWeight); - last_index = vi; - } - // yes, "indexes" - sdnode.AddChild("Indexes", subdef_indices); - sdnode.AddChild("Weights", subdef_weights); - } - - // transform is the transform of the mesh, but in bone space. - // if the skeleton is in the bind pose, - // we can take the inverse of the world-space bone transform - // and multiply by the world-space transform of the mesh. - aiMatrix4x4 bone_xform = get_world_transform(bone_node, mScene); - aiMatrix4x4 inverse_bone_xform = bone_xform; - inverse_bone_xform.Inverse(); - aiMatrix4x4 tr = inverse_bone_xform * mesh_xform; - - sdnode.AddChild("Transform", tr); - - - sdnode.AddChild("TransformLink", bone_xform); - // note: this means we ALWAYS rely on the mesh node transform - // being unchanged from the time the skeleton was bound. - // there's not really any way around this at the moment. - - // done - sdnode.Dump(outstream, binary, indent); - - // lastly, connect to the parent deformer - connections.emplace_back( - "C", "OO", subdeformer_uid, deformer_uid - ); - - // we also need to connect the limb node to the subdeformer. - connections.emplace_back( - "C", "OO", node_uids[bone_node], subdeformer_uid - ); - } - - // if we cannot create a valid FBX file, simply die. - // this will both prevent unnecessary bug reports, - // and tell the user what they can do to fix the situation - // (i.e. export their model in the bind pose). - if (no_offset_matrix.size() && not_in_bind_pose.size()) { - std::stringstream err; - err << "Not enough information to construct bind pose"; - err << " for mesh " << mi << "!"; - err << " Transform matrix for bone \""; - err << (*not_in_bind_pose.begin())->mName.C_Str() << "\""; - if (not_in_bind_pose.size() > 1) { - err << " (and " << not_in_bind_pose.size() - 1 << " more)"; - } - err << " does not match mOffsetMatrix,"; - err << " and node \""; - err << (*no_offset_matrix.begin())->mName.C_Str() << "\""; - if (no_offset_matrix.size() > 1) { - err << " (and " << no_offset_matrix.size() - 1 << " more)"; - } - err << " has no offset matrix to rely on."; - err << " Please ensure bones are in the bind pose to export."; - throw DeadlyExportError(err.str()); - } - - } - - // BindPose - // - // This is a legacy system, which should be unnecessary. - // - // Somehow including it slows file loading by the official FBX SDK, - // and as it can reconstruct it from the deformers anyway, - // this is not currently included. - // - // The code is kept here in case it's useful in the future, - // but it's pretty much a hack anyway, - // as assimp doesn't store bindpose information for full skeletons. - // - /*for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - aiMesh* mesh = mScene->mMeshes[mi]; - if (! mesh->HasBones()) { continue; } - int64_t bindpose_uid = generate_uid(); - FBX::Node bpnode("Pose"); - bpnode.AddProperty(bindpose_uid); - // note: this uid is never linked or connected to anything. - bpnode.AddProperty(FBX::SEPARATOR + "Pose"); // blank name - bpnode.AddProperty("BindPose"); - - bpnode.AddChild("Type", "BindPose"); - bpnode.AddChild("Version", int32_t(100)); - - aiNode* mesh_node = get_node_for_mesh(mi, mScene->mRootNode); - - // next get the whole skeleton for this mesh. - // we need it all to define the bindpose section. - // the FBX SDK will complain if it's missing, - // and also if parents of used bones don't have a subdeformer. - // order shouldn't matter. - std::set skeleton; - for (size_t bi = 0; bi < mesh->mNumBones; ++bi) { - // bone node should have already been indexed - const aiBone* b = mesh->mBones[bi]; - const std::string bone_name(b->mName.C_Str()); - aiNode* parent = node_by_bone[bone_name]; - // insert all nodes down to the root or mesh node - while ( - parent - && parent != mScene->mRootNode - && parent != mesh_node - ) { - skeleton.insert(parent); - parent = parent->mParent; - } - } - - // number of pose nodes. includes one for the mesh itself. - bpnode.AddChild("NbPoseNodes", int32_t(1 + skeleton.size())); - - // the first pose node is always the mesh itself - FBX::Node pose("PoseNode"); - pose.AddChild("Node", mesh_uids[mi]); - aiMatrix4x4 mesh_node_xform = get_world_transform(mesh_node, mScene); - pose.AddChild("Matrix", mesh_node_xform); - bpnode.AddChild(pose); - - for (aiNode* bonenode : skeleton) { - // does this node have a uid yet? - int64_t node_uid; - auto node_uid_iter = node_uids.find(bonenode); - if (node_uid_iter != node_uids.end()) { - node_uid = node_uid_iter->second; - } else { - node_uid = generate_uid(); - node_uids[bonenode] = node_uid; - } - - // make a pose thingy - pose = FBX::Node("PoseNode"); - pose.AddChild("Node", node_uid); - aiMatrix4x4 node_xform = get_world_transform(bonenode, mScene); - pose.AddChild("Matrix", node_xform); - bpnode.AddChild(pose); - } - - // now write it - bpnode.Dump(outstream, binary, indent); - }*/ - - // TODO: cameras, lights - - // write nodes (i.e. model hierarchy) - // start at root node - WriteModelNodes( - outstream, mScene->mRootNode, 0, limbnodes - ); - - // animations - // - // in FBX there are: - // * AnimationStack - corresponds to an aiAnimation - // * AnimationLayer - a combinable animation component - // * AnimationCurveNode - links the property to be animated - // * AnimationCurve - defines animation data for a single property value - // - // the CurveNode also provides the default value for a property, - // such as the X, Y, Z coordinates for animatable translation. - // - // the Curve only specifies values for one component of the property, - // so there will be a separate AnimationCurve for X, Y, and Z. - // - // Assimp has: - // * aiAnimation - basically corresponds to an AnimationStack - // * aiNodeAnim - defines all animation for one aiNode - // * aiVectorKey/aiQuatKey - define the keyframe data for T/R/S - // - // assimp has no equivalent for AnimationLayer, - // and these are flattened on FBX import. - // we can assume there will be one per AnimationStack. - // - // the aiNodeAnim contains all animation data for a single aiNode, - // which will correspond to three AnimationCurveNode's: - // one each for translation, rotation and scale. - // The data for each of these will be put in 9 AnimationCurve's, - // T.X, T.Y, T.Z, R.X, R.Y, R.Z, etc. - - // AnimationStack / aiAnimation - std::vector animation_stack_uids(mScene->mNumAnimations); - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - int64_t animstack_uid = generate_uid(); - animation_stack_uids[ai] = animstack_uid; - const aiAnimation* anim = mScene->mAnimations[ai]; - - FBX::Node asnode("AnimationStack"); - std::string name = anim->mName.C_Str() + FBX::SEPARATOR + "AnimStack"; - asnode.AddProperties(animstack_uid, name, ""); - FBX::Node p("Properties70"); - p.AddP70time("LocalStart", 0); // assimp doesn't store this - p.AddP70time("LocalStop", to_ktime(anim->mDuration, anim)); - p.AddP70time("ReferenceStart", 0); - p.AddP70time("ReferenceStop", to_ktime(anim->mDuration, anim)); - asnode.AddChild(p); - - // this node absurdly always pretends it has children - // (in this case it does, but just in case...) - asnode.force_has_children = true; - asnode.Dump(outstream, binary, indent); - - // note: animation stacks are not connected to anything - } - - // AnimationLayer - one per aiAnimation - std::vector animation_layer_uids(mScene->mNumAnimations); - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - int64_t animlayer_uid = generate_uid(); - animation_layer_uids[ai] = animlayer_uid; - FBX::Node alnode("AnimationLayer"); - alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", ""); - - // this node absurdly always pretends it has children - alnode.force_has_children = true; - alnode.Dump(outstream, binary, indent); - - // connect to the relevant animstack - connections.emplace_back( - "C", "OO", animlayer_uid, animation_stack_uids[ai] - ); - } - - // AnimCurveNode - three per aiNodeAnim - std::vector>> curve_node_uids; - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - const aiAnimation* anim = mScene->mAnimations[ai]; - const int64_t layer_uid = animation_layer_uids[ai]; - std::vector> nodeanim_uids; - for (size_t nai = 0; nai < anim->mNumChannels; ++nai) { - const aiNodeAnim* na = anim->mChannels[nai]; - // get the corresponding aiNode - const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName); - // and its transform - const aiMatrix4x4 node_xfm = get_world_transform(node, mScene); - aiVector3D T, R, S; - node_xfm.Decompose(S, R, T); - - // AnimationCurveNode uids - std::array ids; - ids[0] = generate_uid(); // T - ids[1] = generate_uid(); // R - ids[2] = generate_uid(); // S - - // translation - WriteAnimationCurveNode(outstream, - ids[0], "T", T, "Lcl Translation", - layer_uid, node_uids[node] - ); - - // rotation - WriteAnimationCurveNode(outstream, - ids[1], "R", R, "Lcl Rotation", - layer_uid, node_uids[node] - ); - - // scale - WriteAnimationCurveNode(outstream, - ids[2], "S", S, "Lcl Scale", - layer_uid, node_uids[node] - ); - - // store the uids for later use - nodeanim_uids.push_back(ids); - } - curve_node_uids.push_back(nodeanim_uids); - } - - // AnimCurve - defines actual keyframe data. - // there's a separate curve for every component of every vector, - // for example a transform curvenode will have separate X/Y/Z AnimCurve's - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - const aiAnimation* anim = mScene->mAnimations[ai]; - for (size_t nai = 0; nai < anim->mNumChannels; ++nai) { - const aiNodeAnim* na = anim->mChannels[nai]; - // get the corresponding aiNode - const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName); - // and its transform - const aiMatrix4x4 node_xfm = get_world_transform(node, mScene); - aiVector3D T, R, S; - node_xfm.Decompose(S, R, T); - const std::array& ids = curve_node_uids[ai][nai]; - - std::vector times; - std::vector xval, yval, zval; - - // position/translation - for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) { - const aiVectorKey& k = na->mPositionKeys[ki]; - times.push_back(to_ktime(k.mTime)); - xval.push_back(k.mValue.x); - yval.push_back(k.mValue.y); - zval.push_back(k.mValue.z); - } - // one curve each for X, Y, Z - WriteAnimationCurve(outstream, T.x, times, xval, ids[0], "d|X"); - WriteAnimationCurve(outstream, T.y, times, yval, ids[0], "d|Y"); - WriteAnimationCurve(outstream, T.z, times, zval, ids[0], "d|Z"); - - // rotation - times.clear(); xval.clear(); yval.clear(); zval.clear(); - for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) { - const aiQuatKey& k = na->mRotationKeys[ki]; - times.push_back(to_ktime(k.mTime)); - // TODO: aiQuaternion method to convert to Euler... - aiMatrix4x4 m(k.mValue.GetMatrix()); - aiVector3D qs, qr, qt; - m.Decompose(qs, qr, qt); - qr *= DEG; - xval.push_back(qr.x); - yval.push_back(qr.y); - zval.push_back(qr.z); - } - WriteAnimationCurve(outstream, R.x, times, xval, ids[1], "d|X"); - WriteAnimationCurve(outstream, R.y, times, yval, ids[1], "d|Y"); - WriteAnimationCurve(outstream, R.z, times, zval, ids[1], "d|Z"); - - // scaling/scale - times.clear(); xval.clear(); yval.clear(); zval.clear(); - for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) { - const aiVectorKey& k = na->mScalingKeys[ki]; - times.push_back(to_ktime(k.mTime)); - xval.push_back(k.mValue.x); - yval.push_back(k.mValue.y); - zval.push_back(k.mValue.z); - } - WriteAnimationCurve(outstream, S.x, times, xval, ids[2], "d|X"); - WriteAnimationCurve(outstream, S.y, times, yval, ids[2], "d|Y"); - WriteAnimationCurve(outstream, S.z, times, zval, ids[2], "d|Z"); - } - } - - indent = 0; - object_node.End(outstream, binary, indent, true); -} - -// convenience map of magic node name strings to FBX properties, -// including the expected type of transform. -const std::map> transform_types = { - {"Translation", {"Lcl Translation", 't'}}, - {"RotationOffset", {"RotationOffset", 't'}}, - {"RotationPivot", {"RotationPivot", 't'}}, - {"PreRotation", {"PreRotation", 'r'}}, - {"Rotation", {"Lcl Rotation", 'r'}}, - {"PostRotation", {"PostRotation", 'r'}}, - {"RotationPivotInverse", {"RotationPivotInverse", 'i'}}, - {"ScalingOffset", {"ScalingOffset", 't'}}, - {"ScalingPivot", {"ScalingPivot", 't'}}, - {"Scaling", {"Lcl Scaling", 's'}}, - {"ScalingPivotInverse", {"ScalingPivotInverse", 'i'}}, - {"GeometricScaling", {"GeometricScaling", 's'}}, - {"GeometricRotation", {"GeometricRotation", 'r'}}, - {"GeometricTranslation", {"GeometricTranslation", 't'}}, - {"GeometricTranslationInverse", {"GeometricTranslationInverse", 'i'}}, - {"GeometricRotationInverse", {"GeometricRotationInverse", 'i'}}, - {"GeometricScalingInverse", {"GeometricScalingInverse", 'i'}} -}; - -// write a single model node to the stream -void FBXExporter::WriteModelNode( - StreamWriterLE& outstream, - bool binary, - const aiNode* node, - int64_t node_uid, - const std::string& type, - const std::vector>& transform_chain, - TransformInheritance inherit_type -){ - const aiVector3D zero = {0, 0, 0}; - const aiVector3D one = {1, 1, 1}; - FBX::Node m("Model"); - std::string name = node->mName.C_Str() + FBX::SEPARATOR + "Model"; - m.AddProperties(node_uid, name, type); - m.AddChild("Version", int32_t(232)); - FBX::Node p("Properties70"); - p.AddP70bool("RotationActive", 1); - p.AddP70int("DefaultAttributeIndex", 0); - p.AddP70enum("InheritType", inherit_type); - if (transform_chain.empty()) { - // decompose 4x4 transform matrix into TRS - aiVector3D t, r, s; - node->mTransformation.Decompose(s, r, t); - if (t != zero) { - p.AddP70( - "Lcl Translation", "Lcl Translation", "", "A", - double(t.x), double(t.y), double(t.z) - ); - } - if (r != zero) { - p.AddP70( - "Lcl Rotation", "Lcl Rotation", "", "A", - double(DEG*r.x), double(DEG*r.y), double(DEG*r.z) - ); - } - if (s != one) { - p.AddP70( - "Lcl Scaling", "Lcl Scaling", "", "A", - double(s.x), double(s.y), double(s.z) - ); - } - } else { - // apply the transformation chain. - // these transformation elements are created when importing FBX, - // which has a complex transformation hierarchy for each node. - // as such we can bake the hierarchy back into the node on export. - for (auto &item : transform_chain) { - auto elem = transform_types.find(item.first); - if (elem == transform_types.end()) { - // then this is a bug - std::stringstream err; - err << "unrecognized FBX transformation type: "; - err << item.first; - throw DeadlyExportError(err.str()); - } - const std::string &name = elem->second.first; - const aiVector3D &v = item.second; - if (name.compare(0, 4, "Lcl ") == 0) { - // special handling for animatable properties - p.AddP70( - name, name, "", "A", - double(v.x), double(v.y), double(v.z) - ); - } else { - p.AddP70vector(name, v.x, v.y, v.z); - } - } - } - m.AddChild(p); - - // not sure what these are for, - // but they seem to be omnipresent - m.AddChild("Shading", FBXExportProperty(true)); - m.AddChild("Culling", FBXExportProperty("CullingOff")); - - m.Dump(outstream, binary, 1); -} - -// wrapper for WriteModelNodes to create and pass a blank transform chain -void FBXExporter::WriteModelNodes( - StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set& limbnodes -) { - std::vector> chain; - WriteModelNodes(s, node, parent_uid, limbnodes, chain); -} - -void FBXExporter::WriteModelNodes( - StreamWriterLE& outstream, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set& limbnodes, - std::vector>& transform_chain -) { - // first collapse any expanded transformation chains created by FBX import. - std::string node_name(node->mName.C_Str()); - if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { - auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1; - std::string type_name = node_name.substr(pos); - auto elem = transform_types.find(type_name); - if (elem == transform_types.end()) { - // then this is a bug and should be fixed - std::stringstream err; - err << "unrecognized FBX transformation node"; - err << " of type " << type_name << " in node " << node_name; - throw DeadlyExportError(err.str()); - } - aiVector3D t, r, s; - node->mTransformation.Decompose(s, r, t); - switch (elem->second.second) { - case 'i': // inverse - // we don't need to worry about the inverse matrices - break; - case 't': // translation - transform_chain.emplace_back(elem->first, t); - break; - case 'r': // rotation - r *= float(DEG); - transform_chain.emplace_back(elem->first, r); - break; - case 's': // scale - transform_chain.emplace_back(elem->first, s); - break; - default: - // this should never happen - std::stringstream err; - err << "unrecognized FBX transformation type code: "; - err << elem->second.second; - throw DeadlyExportError(err.str()); - } - // now continue on to any child nodes - for (unsigned i = 0; i < node->mNumChildren; ++i) { - WriteModelNodes( - outstream, - node->mChildren[i], - parent_uid, - limbnodes, - transform_chain - ); - } - return; - } - - int64_t node_uid = 0; - // generate uid and connect to parent, if not the root node, - if (node != mScene->mRootNode) { - auto elem = node_uids.find(node); - if (elem != node_uids.end()) { - node_uid = elem->second; - } else { - node_uid = generate_uid(); - node_uids[node] = node_uid; - } - connections.emplace_back("C", "OO", node_uid, parent_uid); - } - - // what type of node is this? - if (node == mScene->mRootNode) { - // handled later - } else if (node->mNumMeshes == 1) { - // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[0]], node_uid - ); - // also connect to the material for the child mesh - connections.emplace_back( - "C", "OO", - material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex], - node_uid - ); - // write model node - WriteModelNode( - outstream, binary, node, node_uid, "Mesh", transform_chain - ); - } else if (limbnodes.count(node)) { - WriteModelNode( - outstream, binary, node, node_uid, "LimbNode", transform_chain - ); - // we also need to write a nodeattribute to mark it as a skeleton - int64_t node_attribute_uid = generate_uid(); - FBX::Node na("NodeAttribute"); - na.AddProperties( - node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode" - ); - na.AddChild("TypeFlags", FBXExportProperty("Skeleton")); - na.Dump(outstream, binary, 1); - // and connect them - connections.emplace_back("C", "OO", node_attribute_uid, node_uid); - } else { - // generate a null node so we can add children to it - WriteModelNode( - outstream, binary, node, node_uid, "Null", transform_chain - ); - } - - // if more than one child mesh, make nodes for each mesh - if (node->mNumMeshes > 1 || node == mScene->mRootNode) { - for (size_t i = 0; i < node->mNumMeshes; ++i) { - // make a new model node - int64_t new_node_uid = generate_uid(); - // connect to parent node - connections.emplace_back("C", "OO", new_node_uid, node_uid); - // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid - ); - // also connect to the material for the child mesh - connections.emplace_back( - "C", "OO", - material_uids[ - mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex - ], - new_node_uid - ); - // write model node - FBX::Node m("Model"); - // take name from mesh name, if it exists - std::string name = mScene->mMeshes[node->mMeshes[i]]->mName.C_Str(); - name += FBX::SEPARATOR + "Model"; - m.AddProperties(new_node_uid, name, "Mesh"); - m.AddChild("Version", int32_t(232)); - FBX::Node p("Properties70"); - p.AddP70enum("InheritType", 1); - m.AddChild(p); - m.Dump(outstream, binary, 1); - } - } - - // now recurse into children - for (size_t i = 0; i < node->mNumChildren; ++i) { - WriteModelNodes( - outstream, node->mChildren[i], node_uid, limbnodes - ); - } -} - - -void FBXExporter::WriteAnimationCurveNode( - StreamWriterLE& outstream, - int64_t uid, - const std::string& name, // "T", "R", or "S" - aiVector3D default_value, - std::string property_name, // "Lcl Translation" etc - int64_t layer_uid, - int64_t node_uid -) { - FBX::Node n("AnimationCurveNode"); - n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", ""); - FBX::Node p("Properties70"); - p.AddP70numberA("d|X", default_value.x); - p.AddP70numberA("d|Y", default_value.y); - p.AddP70numberA("d|Z", default_value.z); - n.AddChild(p); - n.Dump(outstream, binary, 1); - // connect to layer - this->connections.emplace_back("C", "OO", uid, layer_uid); - // connect to bone - this->connections.emplace_back("C", "OP", uid, node_uid, property_name); -} - - -void FBXExporter::WriteAnimationCurve( - StreamWriterLE& outstream, - double default_value, - const std::vector& times, - const std::vector& values, - int64_t curvenode_uid, - const std::string& property_link // "d|X", "d|Y", etc -) { - FBX::Node n("AnimationCurve"); - int64_t curve_uid = generate_uid(); - n.AddProperties(curve_uid, FBX::SEPARATOR + "AnimCurve", ""); - n.AddChild("Default", default_value); - n.AddChild("KeyVer", int32_t(4009)); - n.AddChild("KeyTime", times); - n.AddChild("KeyValueFloat", values); - // TODO: keyattr flags and data (STUB for now) - n.AddChild("KeyAttrFlags", std::vector{0}); - n.AddChild("KeyAttrDataFloat", std::vector{0,0,0,0}); - n.AddChild( - "KeyAttrRefCount", - std::vector{static_cast(times.size())} - ); - n.Dump(outstream, binary, 1); - this->connections.emplace_back( - "C", "OP", curve_uid, curvenode_uid, property_link - ); -} - - -void FBXExporter::WriteConnections () -{ - // we should have completed the connection graph already, - // so basically just dump it here - if (!binary) { - WriteAsciiSectionHeader("Object connections"); - } - // TODO: comments with names in the ascii version - FBX::Node conn("Connections"); - StreamWriterLE outstream(outfile); - conn.Begin(outstream, binary, 0); - conn.BeginChildren(outstream, binary, 0); - for (auto &n : connections) { - n.Dump(outstream, binary, 1); - } - conn.End(outstream, binary, 0, !connections.empty()); - connections.clear(); -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExporter.h b/thirdparty/assimp/code/FBX/FBXExporter.h deleted file mode 100644 index 1ae727eda953..000000000000 --- a/thirdparty/assimp/code/FBX/FBXExporter.h +++ /dev/null @@ -1,178 +0,0 @@ -/* -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 FBXExporter.h -* Declares the exporter class to write a scene to an fbx file -*/ -#ifndef AI_FBXEXPORTER_H_INC -#define AI_FBXEXPORTER_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportNode.h" // FBX::Node -#include "FBXCommon.h" // FBX::TransformInheritance - -#include -//#include -#include // StreamWriterLE -#include // DeadlyExportError - -#include -#include -#include -#include // shared_ptr -#include // stringstream - -struct aiScene; -struct aiNode; -//struct aiMaterial; - -namespace Assimp -{ - class IOSystem; - class IOStream; - class ExportProperties; - - // --------------------------------------------------------------------- - /** Helper class to export a given scene to an FBX file. */ - // --------------------------------------------------------------------- - class FBXExporter - { - public: - /// Constructor for a specific scene to export - FBXExporter(const aiScene* pScene, const ExportProperties* pProperties); - - // call one of these methods to export - void ExportBinary(const char* pFile, IOSystem* pIOSystem); - void ExportAscii(const char* pFile, IOSystem* pIOSystem); - - private: - bool binary; // whether current export is in binary or ascii format - const aiScene* mScene; // the scene to export - const ExportProperties* mProperties; // currently unused - std::shared_ptr outfile; // file to write to - - std::vector connections; // connection storage - - std::vector mesh_uids; - std::vector material_uids; - std::map node_uids; - - // this crude unique-ID system is actually fine - int64_t last_uid = 999999; - int64_t generate_uid() { return ++last_uid; } - - // binary files have a specific header and footer, - // in addition to the actual data - void WriteBinaryHeader(); - void WriteBinaryFooter(); - - // ascii files have a comment at the top - void WriteAsciiHeader(); - - // WriteAllNodes does the actual export. - // It just calls all the Write
methods below in order. - void WriteAllNodes(); - - // Methods to write individual sections. - // The order here matches the order inside an FBX file. - // Each method corresponds to a top-level FBX section, - // except WriteHeader which also includes some binary-only sections - // and WriteFooter which is binary data only. - void WriteHeaderExtension(); - // WriteFileId(); // binary-only, included in WriteHeader - // WriteCreationTime(); // binary-only, included in WriteHeader - // WriteCreator(); // binary-only, included in WriteHeader - void WriteGlobalSettings(); - void WriteDocuments(); - void WriteReferences(); - void WriteDefinitions(); - void WriteObjects(); - void WriteConnections(); - // WriteTakes(); // deprecated since at least 2015 (fbx 7.4) - - // helpers - void WriteAsciiSectionHeader(const std::string& title); - void WriteModelNodes( - Assimp::StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set& limbnodes - ); - void WriteModelNodes( // usually don't call this directly - StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set& limbnodes, - std::vector>& transform_chain - ); - void WriteModelNode( // nor this - StreamWriterLE& s, - bool binary, - const aiNode* node, - int64_t node_uid, - const std::string& type, - const std::vector>& xfm_chain, - FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs - ); - void WriteAnimationCurveNode( - StreamWriterLE& outstream, - int64_t uid, - const std::string& name, // "T", "R", or "S" - aiVector3D default_value, - std::string property_name, // "Lcl Translation" etc - int64_t animation_layer_uid, - int64_t node_uid - ); - void WriteAnimationCurve( - StreamWriterLE& outstream, - double default_value, - const std::vector& times, - const std::vector& values, - int64_t curvenode_id, - const std::string& property_link // "d|X", "d|Y", etc - ); - }; -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTER_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXImporter.cpp b/thirdparty/assimp/code/FBX/FBXImporter.cpp deleted file mode 100644 index afcc1ddc78c2..000000000000 --- a/thirdparty/assimp/code/FBX/FBXImporter.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* -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. -r -* 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 FBXImporter.cpp - * @brief Implementation of the FBX importer. - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXImporter.h" - -#include "FBXConverter.h" -#include "FBXDocument.h" -#include "FBXParser.h" -#include "FBXTokenizer.h" -#include "FBXUtil.h" - -#include -#include -#include -#include - -namespace Assimp { - -template <> -const char *LogFunctions::Prefix() { - static auto prefix = "FBX: "; - return prefix; -} - -} // namespace Assimp - -using namespace Assimp; -using namespace Assimp::Formatter; -using namespace Assimp::FBX; - -namespace { - -static const aiImporterDesc desc = { - "Autodesk FBX Importer", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "fbx" -}; -} - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by #Importer -FBXImporter::FBXImporter() { -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FBXImporter::~FBXImporter() { -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. -bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { - const std::string &extension = GetExtension(pFile); - if (extension == std::string(desc.mFileExtensions)) { - return true; - } - - else if ((!extension.length() || checkSig) && pIOHandler) { - // at least ASCII-FBX files usually have a 'FBX' somewhere in their head - const char *tokens[] = { "fbx" }; - return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// List all extensions handled by this loader -const aiImporterDesc *FBXImporter::GetInfo() const { - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties for the loader -void FBXImporter::SetupProperties(const Importer *pImp) { - settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); - settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); - settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); - settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); - settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); - settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); - settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); - settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); - settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); - settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); - settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); - settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); - settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { - std::unique_ptr stream(pIOHandler->Open(pFile, "rb")); - if (!stream) { - ThrowException("Could not open file for reading"); - } - - // read entire file into memory - no streaming for this, fbx - // files can grow large, but the assimp output data structure - // then becomes very large, too. Assimp doesn't support - // streaming for its output data structures so the net win with - // streaming input data would be very low. - std::vector contents; - contents.resize(stream->FileSize() + 1); - stream->Read(&*contents.begin(), 1, contents.size() - 1); - contents[contents.size() - 1] = 0; - const char *const begin = &*contents.begin(); - - // broadphase tokenizing pass in which we identify the core - // syntax elements of FBX (brackets, commas, key:value mappings) - TokenList tokens; - try { - - bool is_binary = false; - if (!strncmp(begin, "Kaydara FBX Binary", 18)) { - is_binary = true; - TokenizeBinary(tokens, begin, contents.size()); - } else { - Tokenize(tokens, begin); - } - - // use this information to construct a very rudimentary - // parse-tree representing the FBX scope structure - Parser parser(tokens, is_binary); - - // take the raw parse-tree and convert it to a FBX DOM - Document doc(parser, settings); - - // convert the FBX DOM to aiScene - ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); - - // size relative to cm - float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); - - // Set FBX file scale is relative to CM must be converted to M for - // assimp universal format (M) - SetFileScale(size_relative_to_cm * 0.01f); - - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun()); - } catch (std::exception &) { - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun()); - throw; - } -} - -#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/thirdparty/assimp/code/FBX/FBXImporter.h b/thirdparty/assimp/code/FBX/FBXImporter.h deleted file mode 100644 index c365b2cddfc1..000000000000 --- a/thirdparty/assimp/code/FBX/FBXImporter.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -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 FBXImporter.h - * @brief Declaration of the FBX main importer class - */ -#ifndef INCLUDED_AI_FBX_IMPORTER_H -#define INCLUDED_AI_FBX_IMPORTER_H - -#include -#include - -#include "FBXImportSettings.h" - -namespace Assimp { - -// TinyFormatter.h -namespace Formatter { - template class basic_formatter; - typedef class basic_formatter< char, std::char_traits, std::allocator > format; -} - -// ------------------------------------------------------------------------------------------- -/** Load the Autodesk FBX file format. - - See http://en.wikipedia.org/wiki/FBX -*/ -// ------------------------------------------------------------------------------------------- -class FBXImporter : public BaseImporter, public LogFunctions -{ -public: - FBXImporter(); - virtual ~FBXImporter(); - - // -------------------- - bool CanRead( const std::string& pFile, - IOSystem* pIOHandler, - bool checkSig - ) const; - -protected: - - // -------------------- - const aiImporterDesc* GetInfo () const; - - // -------------------- - void SetupProperties(const Importer* pImp); - - // -------------------- - void InternReadFile( const std::string& pFile, - aiScene* pScene, - IOSystem* pIOHandler - ); - -private: - FBX::ImportSettings settings; -}; // !class FBXImporter - -} // end of namespace Assimp -#endif // !INCLUDED_AI_FBX_IMPORTER_H - diff --git a/thirdparty/assimp/code/FBX/FBXMaterial.cpp b/thirdparty/assimp/code/FBX/FBXMaterial.cpp deleted file mode 100644 index f43a8b84b053..000000000000 --- a/thirdparty/assimp/code/FBX/FBXMaterial.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* -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 FBXMaterial.cpp - * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" -#include - -#include // std::transform -#include "FBXUtil.h" - -namespace Assimp { -namespace FBX { - - using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const ShadingModel = sc["ShadingModel"]; - const Element* const MultiLayer = sc["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; - - // lower-case shading because Blender (for example) writes "Phong" - std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower); - if(shading == "phong") { - templateName = "Material.FbxSurfacePhong"; - } - else if(shading == "lambert") { - templateName = "Material.FbxSurfaceLambert"; - } - else { - DOMWarning("shading mode not recognized: " + shading,&element); - } - - props = GetPropertyTable(doc,templateName,element,sc); - - // resolve texture links - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); - for(const Connection* con : conns) { - - // texture link to properties, not objects - if (!con->PropertyName().length()) { - continue; - } - - 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(ob); - if(!tex) { - const LayeredTexture* const layeredTexture = dynamic_cast(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*)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() -{ -} - - -// ------------------------------------------------------------------------------------------------ -Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -, uvScaling(1.0f,1.0f) -, media(0) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Type = sc["Type"]; - const Element* const FileName = sc["FileName"]; - const Element* const RelativeFilename = sc["RelativeFilename"]; - const Element* const ModelUVTranslation = sc["ModelUVTranslation"]; - const Element* const ModelUVScaling = sc["ModelUVScaling"]; - const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"]; - const Element* const Cropping = sc["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 = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)), - ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1)) - ); - } - - if(ModelUVScaling) { - uvScaling = aiVector2D(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 aiVector3D& scaling = PropertyGet(*props, "Scaling", ok); - if (ok) { - uvScaling.x = scaling.x; - uvScaling.y = scaling.y; - } - - const aiVector3D& trans = PropertyGet(*props, "Translation", ok); - if (ok) { - uvTrans.x = trans.x; - uvTrans.y = trans.y; - } - - // resolve video links - if(doc.Settings().readTextures) { - const std::vector& 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(ob); - if(video) { - media = video; - } - } - } -} - - -Texture::~Texture() -{ - -} - -LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name) -: Object(id,element,name) -,blendMode(BlendMode_Modulate) -,alpha(1) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const BlendModes = sc["BlendModes"]; - const Element* const Alphas = sc["Alphas"]; - - - if(BlendModes!=0) - { - blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0)); - } - if(Alphas!=0) - { - alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0)); - } -} - -LayeredTexture::~LayeredTexture() -{ - -} - -void LayeredTexture::fillTexture(const Document& doc) -{ - const std::vector& 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(ob); - - textures.push_back(tex); - } -} - - -// ------------------------------------------------------------------------------------------------ -Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -, contentLength(0) -, content(0) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Type = sc["Type"]; - const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows - const Element* const RelativeFilename = sc["RelativeFilename"]; - const Element* const Content = sc["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(targetLength); - size_t dst_offset = 0; - 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; - 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(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 (const runtime_error& runtimeError) - { - //we don't need the content data for contents that has already been loaded - ASSIMP_LOG_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; - } -} - -} //!FBX -} //!Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp b/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp deleted file mode 100644 index 1386e2383c11..000000000000 --- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp +++ /dev/null @@ -1,709 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include - -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" - - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) - : Object(id, element, name) - , skin() -{ - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); - for(const Connection* con : conns) { - const Skin* const sk = ProcessSimpleConnection(*con, false, "Skin -> Geometry", element); - if(sk) { - skin = sk; - } - const BlendShape* const bsp = ProcessSimpleConnection(*con, false, "BlendShape -> Geometry", element); - if (bsp) { - blendShapes.push_back(bsp); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Geometry::~Geometry() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& Geometry::GetBlendShapes() const { - return blendShapes; -} - -// ------------------------------------------------------------------------------------------------ -const Skin* Geometry::DeformerSkin() const { - return skin; -} - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Geometry(id, element,name, doc) -{ - const Scope* sc = element.Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Mesh), no data scope found"); - } - - // must have Mesh elements: - const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element); - const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element); - - // optional Mesh elements: - const ElementCollection& Layer = sc->GetCollection("Layer"); - - std::vector tempVerts; - ParseVectorDataArray(tempVerts,Vertices); - - if(tempVerts.empty()) { - FBXImporter::LogWarn("encountered mesh with no vertices"); - } - - std::vector tempFaces; - ParseVectorDataArray(tempFaces,PolygonVertexIndex); - - if(tempFaces.empty()) { - FBXImporter::LogWarn("encountered mesh with no faces"); - } - - m_vertices.reserve(tempFaces.size()); - m_faces.reserve(tempFaces.size() / 3); - - m_mapping_offsets.resize(tempVerts.size()); - m_mapping_counts.resize(tempVerts.size(),0); - m_mappings.resize(tempFaces.size()); - - const size_t vertex_count = tempVerts.size(); - - // generate output vertices, computing an adjacency table to - // preserve the mapping from fbx indices to *this* indexing. - unsigned int count = 0; - for(int index : tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - if(static_cast(absi) >= vertex_count) { - DOMError("polygon vertex index out of range",&PolygonVertexIndex); - } - - m_vertices.push_back(tempVerts[absi]); - ++count; - - ++m_mapping_counts[absi]; - - if (index < 0) { - m_faces.push_back(count); - count = 0; - } - } - - unsigned int cursor = 0; - for (size_t i = 0, e = tempVerts.size(); i < e; ++i) { - m_mapping_offsets[i] = cursor; - cursor += m_mapping_counts[i]; - - m_mapping_counts[i] = 0; - } - - cursor = 0; - for(int index : tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++; - } - - // if settings.readAllLayers is true: - // * read all layers, try to load as many vertex channels as possible - // if settings.readAllLayers is false: - // * read only the layer with index 0, but warn about any further layers - for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { - const TokenList& tokens = (*it).second->Tokens(); - - const char* err; - const int index = ParseTokenAsInt(*tokens[0], err); - if(err) { - DOMError(err,&element); - } - - if(doc.Settings().readAllLayers || index == 0) { - const Scope& layer = GetRequiredScope(*(*it).second); - ReadLayer(layer); - } - else { - FBXImporter::LogWarn("ignoring additional geometry layers"); - } - } -} - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::~MeshGeometry() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetVertices() const { - return m_vertices; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetNormals() const { - return m_normals; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetTangents() const { - return m_tangents; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetBinormals() const { - return m_binormals; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetFaceIndexCounts() const { - return m_faces; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector& MeshGeometry::GetTextureCoords( unsigned int index ) const { - static const std::vector empty; - return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ]; -} - -std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const { - return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ]; -} - -const std::vector& MeshGeometry::GetVertexColors( unsigned int index ) const { - static const std::vector empty; - return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ]; -} - -const MatIndexArray& MeshGeometry::GetMaterialIndices() const { - return m_materials; -} -// ------------------------------------------------------------------------------------------------ -const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const { - if ( in_index >= m_mapping_counts.size() ) { - return NULL; - } - - ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() ); - count = m_mapping_counts[ in_index ]; - - ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() ); - - return &m_mappings[ m_mapping_offsets[ in_index ] ]; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const { - ai_assert( in_index < m_vertices.size() ); - - // in the current conversion pattern this will only be needed if - // weights are present, so no need to always pre-compute this table - if ( m_facesVertexStartIndices.empty() ) { - m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 ); - - std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 ); - m_facesVertexStartIndices.pop_back(); - } - - ai_assert( m_facesVertexStartIndices.size() == m_faces.size() ); - const std::vector::iterator it = std::upper_bound( - m_facesVertexStartIndices.begin(), - m_facesVertexStartIndices.end(), - in_index - ); - - return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) ); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayer(const Scope& layer) -{ - const ElementCollection& LayerElement = layer.GetCollection("LayerElement"); - for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { - const Scope& elayer = GetRequiredScope(*(*eit).second); - - ReadLayerElement(elayer); - } -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayerElement(const Scope& layerElement) -{ - const Element& Type = GetRequiredElement(layerElement,"Type"); - const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex"); - - const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0)); - const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0)); - - const Scope& top = GetRequiredScope(element); - const ElementCollection candidates = top.GetCollection(type); - - for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) { - const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0)); - if(index == typedIndex) { - ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second)); - return; - } - } - - FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ") - << type << ", index: " << typedIndex); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) -{ - const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"MappingInformationType"),0) - ); - - const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"ReferenceInformationType"),0) - ); - - if (type == "LayerElementUV") { - if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { - FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" ); - return; - } - - const Element* Name = source["Name"]; - m_uvNames[index] = ""; - if(Name) { - m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0)); - } - - ReadVertexDataUV(m_uvs[index],source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementMaterial") { - if (m_materials.size() > 0) { - FBXImporter::LogError("ignoring additional material layer"); - return; - } - - std::vector temp_materials; - - ReadVertexDataMaterials(temp_materials,source, - MappingInformationType, - ReferenceInformationType - ); - - // sometimes, there will be only negative entries. Drop the material - // layer in such a case (I guess it means a default material should - // be used). This is what the converter would do anyway, and it - // avoids losing the material if there are more material layers - // coming of which at least one contains actual data (did observe - // that with one test file). - const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; }); - if(count_neg == temp_materials.size()) { - FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)"); - return; - } - - std::swap(temp_materials, m_materials); - } - else if (type == "LayerElementNormal") { - if (m_normals.size() > 0) { - FBXImporter::LogError("ignoring additional normal layer"); - return; - } - - ReadVertexDataNormals(m_normals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementTangent") { - if (m_tangents.size() > 0) { - FBXImporter::LogError("ignoring additional tangent layer"); - return; - } - - ReadVertexDataTangents(m_tangents,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementBinormal") { - if (m_binormals.size() > 0) { - FBXImporter::LogError("ignoring additional binormal layer"); - return; - } - - ReadVertexDataBinormals(m_binormals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementColor") { - if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) { - FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" ); - return; - } - - ReadVertexDataColors(m_colors[index],source, - MappingInformationType, - ReferenceInformationType - ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Lengthy utility function to read and resolve a FBX vertex data array - that is, the -// output is in polygon vertex order. This logic is used for reading normals, UVs, colors, -// tangents .. -template -void ResolveVertexDataArray(std::vector& data_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType, - const char* dataElementName, - const char* indexDataElementName, - size_t vertex_count, - const std::vector& mapping_counts, - const std::vector& mapping_offsets, - const std::vector& mappings) -{ - bool isDirect = ReferenceInformationType == "Direct"; - bool isIndexToDirect = ReferenceInformationType == "IndexToDirect"; - - // fall-back to direct data if there is no index data element - if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) { - isDirect = true; - isIndexToDirect = false; - } - - // handle permutations of Mapping and Reference type - it would be nice to - // deal with this more elegantly and with less redundancy, but right - // now it seems unavoidable. - if (MappingInformationType == "ByVertice" && isDirect) { - if (!HasElement(source, dataElementName)) { - return; - } - std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - for (size_t i = 0, e = tempData.size(); i < e; ++i) { - - const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; - for (unsigned int j = istart; j < iend; ++j) { - data_out[mappings[j]] = tempData[i]; - } - } - } - else if (MappingInformationType == "ByVertice" && isIndexToDirect) { - std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - - std::vector uvIndices; - ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - for (size_t i = 0, e = uvIndices.size(); i < e; ++i) { - - const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; - for (unsigned int j = istart; j < iend; ++j) { - if (static_cast(uvIndices[i]) >= tempData.size()) { - DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); - } - data_out[mappings[j]] = tempData[uvIndices[i]]; - } - } - } - else if (MappingInformationType == "ByPolygonVertex" && isDirect) { - std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - if (tempData.size() != vertex_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << tempData.size() << ", expected " << vertex_count - ); - return; - } - - data_out.swap(tempData); - } - else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) { - std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - - std::vector uvIndices; - ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - - if (uvIndices.size() != vertex_count) { - FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); - return; - } - - const T empty; - unsigned int next = 0; - for(int i : uvIndices) { - if ( -1 == i ) { - data_out[ next++ ] = empty; - continue; - } - if (static_cast(i) >= tempData.size()) { - DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); - } - - data_out[next++] = tempData[i]; - } - } - else { - FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataNormals(std::vector& normals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType, - "Normals", - "NormalsIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataUV(std::vector& uv_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType, - "UV", - "UVIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType, - "Colors", - "ColorIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -static const char *TangentIndexToken = "TangentIndex"; -static const char *TangentsIndexToken = "TangentsIndex"; - -void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; - const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken; - ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, - str, - strIdx, - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -static const std::string BinormalIndexToken = "BinormalIndex"; -static const std::string BinormalsIndexToken = "BinormalsIndex"; - -void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal"; - const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str(); - ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, - str, - strIdx, - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const size_t face_count = m_faces.size(); - if( 0 == face_count ) - { - return; - } - - // materials are handled separately. First of all, they are assigned per-face - // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect - // has a slightly different meaning for materials. - ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials")); - - if (MappingInformationType == "AllSame") { - // easy - same material for all faces - if (materials_out.empty()) { - FBXImporter::LogError(Formatter::format("expected material index, ignoring")); - return; - } else if (materials_out.size() > 1) { - FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one")); - materials_out.clear(); - } - - materials_out.resize(m_vertices.size()); - std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0)); - } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { - materials_out.resize(face_count); - - if(materials_out.size() != face_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << materials_out.size() << ", expected " << face_count - ); - return; - } - } else { - FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Geometry(id, element, name, doc) { - const Scope *sc = element.Compound(); - if (nullptr == sc) { - DOMError("failed to read Geometry object (class: Shape), no data scope found"); - } - const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); - const Element& Normals = GetRequiredElement(*sc, "Normals", &element); - const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element); - ParseVectorDataArray(m_indices, Indexes); - ParseVectorDataArray(m_vertices, Vertices); - ParseVectorDataArray(m_normals, Normals); -} - -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::~ShapeGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector& ShapeGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector& ShapeGeometry::GetNormals() const { - return m_normals; -} -// ------------------------------------------------------------------------------------------------ -const std::vector& ShapeGeometry::GetIndices() const { - return m_indices; -} -// ------------------------------------------------------------------------------------------------ -LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) - : Geometry(id, element, name, doc) -{ - const Scope* sc = element.Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Line), no data scope found"); - } - const Element& Points = GetRequiredElement(*sc, "Points", &element); - const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element); - ParseVectorDataArray(m_vertices, Points); - ParseVectorDataArray(m_indices, PointsIndex); -} - -// ------------------------------------------------------------------------------------------------ -LineGeometry::~LineGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector& LineGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector& LineGeometry::GetIndices() const { - return m_indices; -} -} // !FBX -} // !Assimp -#endif - diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h b/thirdparty/assimp/code/FBX/FBXMeshGeometry.h deleted file mode 100644 index d6d451217778..000000000000 --- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -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 FBXImporter.h -* @brief Declaration of the FBX main importer class -*/ -#ifndef INCLUDED_AI_FBX_MESHGEOMETRY_H -#define INCLUDED_AI_FBX_MESHGEOMETRY_H - -#include "FBXParser.h" -#include "FBXDocument.h" - -namespace Assimp { -namespace FBX { - -/** - * DOM base class for all kinds of FBX geometry - */ -class Geometry : public Object -{ -public: - Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); - virtual ~Geometry(); - - /** Get the Skin attached to this geometry or NULL */ - const Skin* DeformerSkin() const; - - /** Get the BlendShape attached to this geometry or NULL */ - const std::vector& GetBlendShapes() const; - -private: - const Skin* skin; - std::vector blendShapes; - -}; - -typedef std::vector MatIndexArray; - - -/** - * DOM class for FBX geometry of type "Mesh" - */ -class MeshGeometry : public Geometry -{ -public: - /** The class constructor */ - MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); - - /** The class destructor */ - virtual ~MeshGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector& GetVertices() const; - - /** Get a list of all vertex normals or an empty array if - * no normals are specified. */ - const std::vector& GetNormals() const; - - /** Get a list of all vertex tangents or an empty array - * if no tangents are specified */ - const std::vector& GetTangents() const; - - /** Get a list of all vertex bi-normals or an empty array - * if no bi-normals are specified */ - const std::vector& GetBinormals() const; - - /** Return list of faces - each entry denotes a face and specifies - * how many vertices it has. Vertices are taken from the - * vertex data arrays in sequential order. */ - const std::vector& GetFaceIndexCounts() const; - - /** Get a UV coordinate slot, returns an empty array if - * the requested slot does not exist. */ - const std::vector& GetTextureCoords( unsigned int index ) const; - - /** Get a UV coordinate slot, returns an empty array if - * the requested slot does not exist. */ - std::string GetTextureCoordChannelName( unsigned int index ) const; - - /** Get a vertex color coordinate slot, returns an empty array if - * the requested slot does not exist. */ - const std::vector& GetVertexColors( unsigned int index ) const; - - /** Get per-face-vertex material assignments */ - const MatIndexArray& GetMaterialIndices() const; - - /** Convert from a fbx file vertex index (for example from a #Cluster weight) or NULL - * if the vertex index is not valid. */ - const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const; - - /** Determine the face to which a particular output vertex index belongs. - * This mapping is always unique. */ - unsigned int FaceForVertexIndex( unsigned int in_index ) const; -private: - void ReadLayer( const Scope& layer ); - void ReadLayerElement( const Scope& layerElement ); - void ReadVertexData( const std::string& type, int index, const Scope& source ); - - void ReadVertexDataUV( std::vector& uv_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataNormals( std::vector& normals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataColors( std::vector& colors_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataTangents( std::vector& tangents_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataBinormals( std::vector& binormals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataMaterials( MatIndexArray& materials_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - -private: - // cached data arrays - MatIndexArray m_materials; - std::vector m_vertices; - std::vector m_faces; - mutable std::vector m_facesVertexStartIndices; - std::vector m_tangents; - std::vector m_binormals; - std::vector m_normals; - - std::string m_uvNames[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; - std::vector m_uvs[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; - std::vector m_colors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; - - std::vector m_mapping_counts; - std::vector m_mapping_offsets; - std::vector m_mappings; -}; - -/** -* DOM class for FBX geometry of type "Shape" -*/ -class ShapeGeometry : public Geometry -{ -public: - /** The class constructor */ - ShapeGeometry(uint64_t id, const Element& 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& GetVertices() const; - - /** Get a list of all vertex normals or an empty array if - * no normals are specified. */ - const std::vector& GetNormals() const; - - /** Return list of vertex indices. */ - const std::vector& GetIndices() const; - -private: - std::vector m_vertices; - std::vector m_normals; - std::vector m_indices; -}; -/** -* DOM class for FBX geometry of type "Line" -*/ -class LineGeometry : public Geometry -{ -public: - /** The class constructor */ - LineGeometry(uint64_t id, const Element& 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& GetVertices() const; - - /** Return list of vertex indices. */ - const std::vector& GetIndices() const; - -private: - std::vector m_vertices; - std::vector m_indices; -}; - -} -} - -#endif // INCLUDED_AI_FBX_MESHGEOMETRY_H - diff --git a/thirdparty/assimp/code/FBX/FBXParser.cpp b/thirdparty/assimp/code/FBX/FBXParser.cpp deleted file mode 100644 index 4a9346040d01..000000000000 --- a/thirdparty/assimp/code/FBX/FBXParser.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -/* -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.cpp - * @brief Implementation of the FBX parser and the rudimentary DOM that we use - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include "../contrib/zlib/zlib.h" -#endif - -#include "FBXTokenizer.h" -#include "FBXParser.h" -#include "FBXUtil.h" - -#include -#include -#include - -#include - -using namespace Assimp; -using namespace Assimp::FBX; - -namespace { - - // ------------------------------------------------------------------------------------------------ - // signal parse error, this is always unrecoverable. Throws DeadlyImportError. - AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; - AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) - { - throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); - } - - // ------------------------------------------------------------------------------------------------ - AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX; - AI_WONT_RETURN void ParseError(const std::string& message, const Element* element) - { - if(element) { - ParseError(message,element->KeyToken()); - } - throw DeadlyImportError("FBX-Parser " + message); - } - - - // ------------------------------------------------------------------------------------------------ - void ParseError(const std::string& message, TokenPtr token) - { - if(token) { - ParseError(message, *token); - } - ParseError(message); - } - - // Initially, we did reinterpret_cast, breaking strict aliasing rules. - // This actually caused trouble on Android, so let's be safe this time. - // https://github.com/assimp/assimp/issues/24 - template - T SafeParse(const char* data, const char* end) { - // Actual size validation happens during Tokenization so - // this is valid as an assertion. - (void)(end); - ai_assert(static_cast(end - data) >= sizeof(T)); - T result = static_cast(0); - ::memcpy(&result, data, sizeof(T)); - return result; - } -} - -namespace Assimp { -namespace FBX { - -// ------------------------------------------------------------------------------------------------ -Element::Element(const Token& key_token, Parser& parser) -: key_token(key_token) -{ - TokenPtr n = nullptr; - do { - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected closing bracket",parser.LastToken()); - } - - if (n->Type() == TokenType_DATA) { - tokens.push_back(n); - TokenPtr prev = n; - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken()); - } - - const TokenType ty = n->Type(); - - // some exporters are missing a comma on the next line - if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) { - tokens.push_back(n); - continue; - } - - if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { - ParseError("unexpected token; expected bracket, comma or key",n); - } - } - - if (n->Type() == TokenType_OPEN_BRACKET) { - compound.reset(new Scope(parser)); - - // current token should be a TOK_CLOSE_BRACKET - n = parser.CurrentToken(); - ai_assert(n); - - if (n->Type() != TokenType_CLOSE_BRACKET) { - ParseError("expected closing bracket",n); - } - - parser.AdvanceToNextToken(); - return; - } - } - while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); -} - -// ------------------------------------------------------------------------------------------------ -Element::~Element() -{ - // no need to delete tokens, they are owned by the parser -} - -// ------------------------------------------------------------------------------------------------ -Scope::Scope(Parser& parser,bool topLevel) -{ - if(!topLevel) { - TokenPtr t = parser.CurrentToken(); - if (t->Type() != TokenType_OPEN_BRACKET) { - ParseError("expected open bracket",t); - } - } - - TokenPtr n = parser.AdvanceToNextToken(); - if(n == NULL) { - ParseError("unexpected end of file"); - } - - // note: empty scopes are allowed - while(n->Type() != TokenType_CLOSE_BRACKET) { - if (n->Type() != TokenType_KEY) { - ParseError("unexpected token, expected TOK_KEY",n); - } - - const std::string& str = n->StringContents(); - elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); - - // Element() should stop at the next Key token (or right after a Close token) - n = parser.CurrentToken(); - if(n == NULL) { - if (topLevel) { - return; - } - ParseError("unexpected end of file",parser.LastToken()); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Scope::~Scope() -{ - for(ElementMap::value_type& v : elements) { - delete v.second; - } -} - -// ------------------------------------------------------------------------------------------------ -Parser::Parser (const TokenList& tokens, bool is_binary) -: tokens(tokens) -, last() -, current() -, cursor(tokens.begin()) -, is_binary(is_binary) -{ - root.reset(new Scope(*this,true)); -} - -// ------------------------------------------------------------------------------------------------ -Parser::~Parser() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::AdvanceToNextToken() -{ - last = current; - if (cursor == tokens.end()) { - current = NULL; - } else { - current = *cursor++; - } - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::CurrentToken() const -{ - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::LastToken() const -{ - return last; -} - -// ------------------------------------------------------------------------------------------------ -uint64_t ParseTokenAsID(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0L; - } - - BE_NCONST uint64_t id = SafeParse(data+1, t.end()); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast(t.end() - t.begin()); - ai_assert(length > 0); - - const char* out = nullptr; - const uint64_t id = strtoul10_64(t.begin(),&out,&length); - if (out > t.end()) { - err_out = "failed to parse ID (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -size_t ParseTokenAsDim(const Token& t, const char*& err_out) -{ - // same as ID parsing, except there is a trailing asterisk - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0; - } - - BE_NCONST uint64_t id = SafeParse(data+1, t.end()); - AI_SWAP8(id); - return static_cast(id); - } - - if(*t.begin() != '*') { - err_out = "expected asterisk before array dimension"; - return 0; - } - - // XXX: should use size_t here - unsigned int length = static_cast(t.end() - t.begin()); - if(length == 0) { - err_out = "expected valid integer number after asterisk"; - return 0; - } - - const char* out = nullptr; - const size_t id = static_cast(strtoul10_64(t.begin() + 1,&out,&length)); - if (out > t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return id; -} - - -// ------------------------------------------------------------------------------------------------ -float ParseTokenAsFloat(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0.0f; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'F' && data[0] != 'D') { - err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)"; - return 0.0f; - } - - if (data[0] == 'F') { - return SafeParse(data+1, t.end()); - } - else { - return static_cast( SafeParse(data+1, t.end()) ); - } - } - - // need to copy the input string to a temporary buffer - // first - next in the fbx token stream comes ',', - // which fast_atof could interpret as decimal point. -#define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; - const size_t length = static_cast(t.end()-t.begin()); - std::copy(t.begin(),t.end(),temp); - temp[std::min(static_cast(MAX_FLOAT_LENGTH),length)] = '\0'; - - return fast_atof(temp); -} - - -// ------------------------------------------------------------------------------------------------ -int ParseTokenAsInt(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'I') { - err_out = "failed to parse I(nt), unexpected data type (binary)"; - return 0; - } - - BE_NCONST int32_t ival = SafeParse(data+1, t.end()); - AI_SWAP4(ival); - return static_cast(ival); - } - - ai_assert(static_cast(t.end() - t.begin()) > 0); - - const char* out; - const int intval = strtol10(t.begin(),&out); - if (out != t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return intval; -} - - -// ------------------------------------------------------------------------------------------------ -int64_t ParseTokenAsInt64(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if (t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse Int64, unexpected data type"; - return 0L; - } - - BE_NCONST int64_t id = SafeParse(data + 1, t.end()); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast(t.end() - t.begin()); - ai_assert(length > 0); - - const char* out = nullptr; - const int64_t id = strtol10_64(t.begin(), &out, &length); - if (out > t.end()) { - err_out = "failed to parse Int64 (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -std::string ParseTokenAsString(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return ""; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'S') { - err_out = "failed to parse S(tring), unexpected data type (binary)"; - return ""; - } - - // read string length - BE_NCONST int32_t len = SafeParse(data+1, t.end()); - AI_SWAP4(len); - - ai_assert(t.end() - data == 5 + len); - return std::string(data + 5, len); - } - - const size_t length = static_cast(t.end() - t.begin()); - if(length < 2) { - err_out = "token is too short to hold a string"; - return ""; - } - - const char* s = t.begin(), *e = t.end() - 1; - if (*s != '\"' || *e != '\"') { - err_out = "expected double quoted string"; - return ""; - } - - return std::string(s+1,length-2); -} - - -namespace { - -// ------------------------------------------------------------------------------------------------ -// read the type code and element count of a binary data array and stop there -void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count, - const Element& el) -{ - if (static_cast(end-data) < 5) { - ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el); - } - - // data type - type = *data; - - // read number of elements - BE_NCONST uint32_t len = SafeParse(data+1, end); - AI_SWAP4(len); - - count = len; - data += 5; -} - - -// ------------------------------------------------------------------------------------------------ -// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) -void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, - std::vector& buff, - const Element& /*el*/) -{ - BE_NCONST uint32_t encmode = SafeParse(data, end); - AI_SWAP4(encmode); - data += 4; - - // next comes the compressed length - BE_NCONST uint32_t comp_len = SafeParse(data, end); - AI_SWAP4(comp_len); - data += 4; - - ai_assert(data + comp_len == end); - - // determine the length of the uncompressed data by looking at the type signature - uint32_t stride = 0; - switch(type) - { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - - default: - ai_assert(false); - }; - - const uint32_t full_length = stride * count; - buff.resize(full_length); - - if(encmode == 0) { - ai_assert(full_length == comp_len); - - // plain data, no compression - std::copy(data, end, buff.begin()); - } - else if(encmode == 1) { - // zlib/deflate, next comes ZIP head (0x78 0x01) - // see http://www.ietf.org/rfc/rfc1950.txt - - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.data_type = Z_BINARY; - - // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib - if(Z_OK != inflateInit(&zstream)) { - ParseError("failure initializing zlib"); - } - - zstream.next_in = reinterpret_cast( const_cast(data) ); - zstream.avail_in = comp_len; - - zstream.avail_out = static_cast(buff.size()); - zstream.next_out = reinterpret_cast(&*buff.begin()); - const int ret = inflate(&zstream, Z_FINISH); - - if (ret != Z_STREAM_END && ret != Z_OK) { - ParseError("failure decompressing compressed data section"); - } - - // terminate zlib - inflateEnd(&zstream); - } -#ifdef ASSIMP_BUILD_DEBUG - else { - // runtime check for this happens at tokenization stage - ai_assert(false); - } -#endif - - data += comp_len; - ai_assert(data == end); -} - -} // !anon - - -// ------------------------------------------------------------------------------------------------ -// read an array of float3 tuples -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 3 != 0) { - ParseError("number of floats is not a multiple of three (3) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count3 = count / 3; - out.reserve(count3); - - if (type == 'd') { - const double* d = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.push_back(aiVector3D(static_cast(d[0]), - static_cast(d[1]), - static_cast(d[2]))); - } - // for debugging - /*for ( size_t i = 0; i < out.size(); i++ ) { - aiVector3D vec3( out[ i ] ); - std::stringstream stream; - stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl; - DefaultLogger::get()->info( stream.str() ); - }*/ - } - else if (type == 'f') { - const float* f = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, f += 3) { - out.push_back(aiVector3D(f[0],f[1],f[2])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // may throw bad_alloc if the input is rubbish, but this need - // not to be prevented - importing would fail but we wouldn't - // crash since assimp handles this case properly. - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 3 != 0) { - ParseError("number of floats is not a multiple of three (3)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector3D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - v.z = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of color4 tuples -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 4 != 0) { - ParseError("number of floats is not a multiple of four (4) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count4 = count / 4; - out.reserve(count4); - - if (type == 'd') { - const double* d = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, d += 4) { - out.push_back(aiColor4D(static_cast(d[0]), - static_cast(d[1]), - static_cast(d[2]), - static_cast(d[3]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, f += 4) { - out.push_back(aiColor4D(f[0],f[1],f[2],f[3])); - } - } - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 4 != 0) { - ParseError("number of floats is not a multiple of four (4)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiColor4D v; - v.r = ParseTokenAsFloat(**it++); - v.g = ParseTokenAsFloat(**it++); - v.b = ParseTokenAsFloat(**it++); - v.a = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of float2 tuples -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 2 != 0) { - ParseError("number of floats is not a multiple of two (2) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count2 = count / 2; - out.reserve(count2); - - if (type == 'd') { - const double* d = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, d += 2) { - out.push_back(aiVector2D(static_cast(d[0]), - static_cast(d[1]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, f += 2) { - out.push_back(aiVector2D(f[0],f[1])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 2 != 0) { - ParseError("number of floats is not a multiple of two (2)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector2D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of ints -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'i') { - ParseError("expected int array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t* ip = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - AI_SWAP4(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - out.push_back(ival); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of floats -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - if (type == 'd') { - const double* d = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++d) { - out.push_back(static_cast(*d)); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++f) { - out.push_back(*f); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const float ival = ParseTokenAsFloat(**it++); - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of uints -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'i') { - ParseError("expected (u)int array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t* ip = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - if(val < 0) { - ParseError("encountered negative integer index (binary)"); - } - - AI_SWAP4(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - if(ival < 0) { - ParseError("encountered negative integer index"); - } - out.push_back(static_cast(ival)); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of uint64_ts -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'l') { - ParseError("expected long array (binary)",&el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const uint64_t* ip = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST uint64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const uint64_t ival = ParseTokenAsID(**it++); - - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of int64_ts -void ParseVectorDataArray(std::vector& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if (tok.empty()) { - ParseError("unexpected empty element", &el); - } - - if (tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'l') { - ParseError("expected long array (binary)", &el); - } - - std::vector buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const int64_t* ip = reinterpret_cast(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope, "a", &el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) { - const int64_t ival = ParseTokenAsInt64(**it++); - - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -aiMatrix4x4 ReadMatrix(const Element& element) -{ - std::vector values; - ParseVectorDataArray(values,element); - - if(values.size() != 16) { - ParseError("expected 16 matrix elements"); - } - - aiMatrix4x4 result; - - - result.a1 = values[0]; - result.a2 = values[1]; - result.a3 = values[2]; - result.a4 = values[3]; - - result.b1 = values[4]; - result.b2 = values[5]; - result.b3 = values[6]; - result.b4 = values[7]; - - result.c1 = values[8]; - result.c2 = values[9]; - result.c3 = values[10]; - result.c4 = values[11]; - - result.d1 = values[12]; - result.d2 = values[13]; - result.d3 = values[14]; - result.d4 = values[15]; - - result.Transpose(); - return result; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsString() with ParseError handling -std::string ParseTokenAsString(const Token& t) -{ - const char* err; - const std::string& i = ParseTokenAsString(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -bool HasElement( const Scope& sc, const std::string& index ) { - const Element* el = sc[ index ]; - if ( nullptr == el ) { - return false; - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -// extract a required element from a scope, abort if the element cannot be found -const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) -{ - const Element* el = sc[index]; - if(!el) { - ParseError("did not find required element \"" + index + "\"",element); - } - return *el; -} - - -// ------------------------------------------------------------------------------------------------ -// extract required compound scope -const Scope& GetRequiredScope(const Element& el) -{ - const Scope* const s = el.Compound(); - if(!s) { - ParseError("expected compound scope",&el); - } - - return *s; -} - - -// ------------------------------------------------------------------------------------------------ -// get token at a particular index -const Token& GetRequiredToken(const Element& el, unsigned int index) -{ - const TokenList& t = el.Tokens(); - if(index >= t.size()) { - ParseError(Formatter::format( "missing token at index " ) << index,&el); - } - - return *t[index]; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsID() with ParseError handling -uint64_t ParseTokenAsID(const Token& t) -{ - const char* err; - const uint64_t i = ParseTokenAsID(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsDim() with ParseError handling -size_t ParseTokenAsDim(const Token& t) -{ - const char* err; - const size_t i = ParseTokenAsDim(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsFloat() with ParseError handling -float ParseTokenAsFloat(const Token& t) -{ - const char* err; - const float i = ParseTokenAsFloat(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt() with ParseError handling -int ParseTokenAsInt(const Token& t) -{ - const char* err; - const int i = ParseTokenAsInt(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt64() with ParseError handling -int64_t ParseTokenAsInt64(const Token& t) -{ - const char* err; - const int64_t i = ParseTokenAsInt64(t, err); - if (err) { - ParseError(err, t); - } - return i; -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXParser.h b/thirdparty/assimp/code/FBX/FBXParser.h deleted file mode 100644 index 7b0cf720396e..000000000000 --- a/thirdparty/assimp/code/FBX/FBXParser.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -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 INCLUDED_AI_FBX_PARSER_H -#define INCLUDED_AI_FBX_PARSER_H - -#include -#include -#include -#include -#include - -#include "FBXCompileConfig.h" -#include "FBXTokenizer.h" - -namespace Assimp { -namespace FBX { - -class Scope; -class Parser; -class Element; - -// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03 -typedef std::vector< Scope* > ScopeList; -typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; - -typedef std::pair 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(const Token& key_token, Parser& parser); - ~Element(); - - const Scope* Compound() const { - return compound.get(); - } - - const Token& KeyToken() const { - return key_token; - } - - const TokenList& Tokens() const { - return tokens; - } - -private: - const Token& key_token; - TokenList tokens; - std::unique_ptr compound; -}; - -/** 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(); - - const Element* operator[] (const std::string& index) const { - ElementMap::const_iterator it = elements.find(index); - return it == elements.end() ? NULL : (*it).second; - } - - const Element* FindElementCaseInsensitive(const std::string& elementName) const { - const char* elementNameCStr = elementName.c_str(); - for (auto element = elements.begin(); element != elements.end(); ++element) - { - if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) { - return element->second; - } - } - return NULL; - } - - 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(); - - const Scope& GetRootScope() const { - return *root.get(); - } - - bool IsBinary() const { - return is_binary; - } - -private: - friend class Scope; - friend class Element; - - TokenPtr AdvanceToNextToken(); - TokenPtr LastToken() const; - TokenPtr CurrentToken() const; - -private: - const TokenList& tokens; - - TokenPtr last, current; - TokenList::const_iterator cursor; - std::unique_ptr root; - - const bool is_binary; -}; - - -/* token parsing - this happens when building the DOM out of the parse-tree*/ -uint64_t ParseTokenAsID(const Token& t, const char*& err_out); -size_t ParseTokenAsDim(const Token& t, const char*& err_out); - -float ParseTokenAsFloat(const Token& t, const char*& err_out); -int ParseTokenAsInt(const Token& t, const char*& err_out); -int64_t ParseTokenAsInt64(const Token& t, const char*& err_out); -std::string ParseTokenAsString(const Token& t, const char*& err_out); - -/* wrapper around ParseTokenAsXXX() with DOMError handling */ -uint64_t ParseTokenAsID(const Token& t); -size_t ParseTokenAsDim(const Token& t); -float ParseTokenAsFloat(const Token& t); -int ParseTokenAsInt(const Token& t); -int64_t ParseTokenAsInt64(const Token& t); -std::string ParseTokenAsString(const Token& t); - -/* read data arrays */ -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& el); -void ParseVectorDataArray(std::vector& out, const Element& e); -void ParseVectorDataArray(std::vector& out, const Element& el); - -bool HasElement( const Scope& sc, const std::string& index ); - -// extract a required element from a scope, abort if the element cannot be found -const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL); - -// extract required compound scope -const Scope& GetRequiredScope(const Element& el); -// get token at a particular index -const Token& GetRequiredToken(const Element& el, unsigned int index); - -// read a 4x4 matrix from an array of 16 floats -aiMatrix4x4 ReadMatrix(const Element& element); - -} // ! FBX -} // ! Assimp - -#endif // ! INCLUDED_AI_FBX_PARSER_H diff --git a/thirdparty/assimp/code/FBX/FBXProperties.cpp b/thirdparty/assimp/code/FBX/FBXProperties.cpp deleted file mode 100644 index 8d7036b6a918..000000000000 --- a/thirdparty/assimp/code/FBX/FBXProperties.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXTokenizer.h" -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" - -namespace Assimp { -namespace FBX { - - 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. -Property* ReadTypedProperty(const Element& 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(ParseTokenAsString(*tok[4])); - } - else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) { - return new TypedProperty(ParseTokenAsInt(*tok[4]) != 0); - } - else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) { - return new TypedProperty(ParseTokenAsInt(*tok[4])); - } - else if (!strcmp(cs, "ULongLong")) { - return new TypedProperty(ParseTokenAsID(*tok[4])); - } - else if (!strcmp(cs, "KTime")) { - return new TypedProperty(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(aiVector3D( - ParseTokenAsFloat(*tok[4]), - ParseTokenAsFloat(*tok[5]), - ParseTokenAsFloat(*tok[6])) - ); - } - else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) { - return new TypedProperty(ParseTokenAsFloat(*tok[4])); - } - return NULL; -} - - -// ------------------------------------------------------------------------------------------------ -// 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]); -} - -} //! anon - - -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable() -: templateProps() -, element() -{ -} - -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const Element& element, std::shared_ptr templateProps) -: templateProps(templateProps) -, element(&element) -{ - const Scope& scope = GetRequiredScope(element); - 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; - } - - lazyProps[name] = v.second; - } -} - - -// ------------------------------------------------------------------------------------------------ -PropertyTable::~PropertyTable() -{ - for(PropertyMap::value_type& v : props) { - delete v.second; - } -} - - -// ------------------------------------------------------------------------------------------------ -const Property* 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 NULL; - } - } - - 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. - std::shared_ptr prop = std::shared_ptr(ReadTypedProperty(*element.second)); - - // Element could not be read. Skip it. - if (!prop) continue; - - // Add to result - result[element.first] = prop; - } - - return result; -} - -} //! FBX -} //! Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXTokenizer.cpp deleted file mode 100644 index 252cce3557f3..000000000000 --- a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -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 - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -// tab width for logging columns -#define ASSIMP_FBX_TAB_WIDTH 4 - -#include - -#include "FBXTokenizer.h" -#include "FBXUtil.h" -#include - -namespace Assimp { -namespace FBX { - -// ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column) - : -#ifdef DEBUG - contents(sbegin, static_cast(send-sbegin)), -#endif - sbegin(sbegin) - , send(send) - , type(type) - , line(line) - , column(column) -{ - ai_assert(sbegin); - ai_assert(send); - - // tokens must be of non-zero length - ai_assert(static_cast(send-sbegin) > 0); -} - -// ------------------------------------------------------------------------------------------------ -Token::~Token() -{ -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) -{ - throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,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 = NULL; -} - -} - -// ------------------------------------------------------------------------------------------------ -void Tokenize(TokenList& output_tokens, const char* input) -{ - ai_assert(input); - - // 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 = NULL, *token_end = NULL; - for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) { - const char c = *cur; - - 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; - } - } -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXUtil.cpp b/thirdparty/assimp/code/FBX/FBXUtil.cpp deleted file mode 100644 index c10e057c8c2d..000000000000 --- a/thirdparty/assimp/code/FBX/FBXUtil.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* -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 -#include -#include - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -namespace Assimp { -namespace FBX { -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 ""; -} - - -// ------------------------------------------------------------------------------------------------ -std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset) -{ - return static_cast( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) -{ - return static_cast( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) -{ - if(tok->IsBinary()) { - return static_cast( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", offset 0x" << std::hex << tok->Offset() << ") " << - text) ); - } - - return static_cast( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", line " << tok->Line() << - ", col " << tok->Column() << ") " << - text) ); -} - -// 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(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((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; -} - -} // !Util -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/Material/MaterialSystem.cpp b/thirdparty/assimp/code/Material/MaterialSystem.cpp deleted file mode 100644 index 0be6e9f7bbc6..000000000000 --- a/thirdparty/assimp/code/Material/MaterialSystem.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/* -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 MaterialSystem.cpp - * @brief Implementation of the material system of the library - */ - -#include -#include -#include -#include "MaterialSystem.h" -#include -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Get a specific property from a material -aiReturn aiGetMaterialProperty(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - const aiMaterialProperty** pPropOut) -{ - ai_assert( pMat != NULL ); - ai_assert( pKey != NULL ); - ai_assert( pPropOut != NULL ); - - /* Just search for a property with exactly this name .. - * could be improved by hashing, but it's possibly - * no worth the effort (we're bound to C structures, - * thus std::map or derivates are not applicable. */ - for ( unsigned int i = 0; i < pMat->mNumProperties; ++i ) { - aiMaterialProperty* prop = pMat->mProperties[i]; - - if (prop /* just for safety ... */ - && 0 == strcmp( prop->mKey.data, pKey ) - && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */ - && (UINT_MAX == index || prop->mIndex == index)) - { - *pPropOut = pMat->mProperties[i]; - return AI_SUCCESS; - } - } - *pPropOut = NULL; - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Get an array of floating-point values from the material. -aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - ai_real* pOut, - unsigned int* pMax) -{ - ai_assert( pOut != nullptr ); - ai_assert( pMat != nullptr ); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop); - if ( nullptr == prop) { - return AI_FAILURE; - } - - // data is given in floats, convert to ai_real - unsigned int iWrite = 0; - if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) { - iWrite = prop->mDataLength / sizeof(float); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - - for (unsigned int a = 0; a < iWrite; ++a) { - pOut[ a ] = static_cast ( reinterpret_cast(prop->mData)[a] ); - } - - if (pMax) { - *pMax = iWrite; - } - } - // data is given in doubles, convert to float - else if( aiPTI_Double == prop->mType) { - iWrite = prop->mDataLength / sizeof(double); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast ( reinterpret_cast(prop->mData)[a] ); - } - if (pMax) { - *pMax = iWrite; - } - } - // data is given in ints, convert to float - else if( aiPTI_Integer == prop->mType) { - iWrite = prop->mDataLength / sizeof(int32_t); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast ( reinterpret_cast(prop->mData)[a] ); - } - if (pMax) { - *pMax = iWrite; - } - } - // a string ... read floats separated by spaces - else { - if (pMax) { - iWrite = *pMax; - } - // strings are zero-terminated with a 32 bit length prefix, so this is safe - const char *cur = prop->mData + 4; - ai_assert( prop->mDataLength >= 5 ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - for ( unsigned int a = 0; ;++a) { - cur = fast_atoreal_move(cur,pOut[a]); - if ( a==iWrite-1 ) { - break; - } - if ( !IsSpace(*cur) ) { - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " is a string; failed to parse a float array out of it."); - return AI_FAILURE; - } - } - - if (pMax) { - *pMax = iWrite; - } - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get an array if integers from the material -aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - int* pOut, - unsigned int* pMax) -{ - ai_assert( pOut != NULL ); - ai_assert( pMat != NULL ); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop); - if (!prop) { - return AI_FAILURE; - } - - // data is given in ints, simply copy it - unsigned int iWrite = 0; - if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) { - iWrite = std::max(static_cast(prop->mDataLength / sizeof(int32_t)), 1u); - if (pMax) { - iWrite = std::min(*pMax,iWrite); - } - if (1 == prop->mDataLength) { - // bool type, 1 byte - *pOut = static_cast(*prop->mData); - } - else { - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); - } - } - if (pMax) { - *pMax = iWrite; - } - } - // data is given in floats convert to int - else if( aiPTI_Float == prop->mType) { - iWrite = prop->mDataLength / sizeof(float); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); - } - if (pMax) { - *pMax = iWrite; - } - } - // it is a string ... no way to read something out of this - else { - if (pMax) { - iWrite = *pMax; - } - // strings are zero-terminated with a 32 bit length prefix, so this is safe - const char *cur = prop->mData+4; - ai_assert( prop->mDataLength >= 5 ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - for (unsigned int a = 0; ;++a) { - pOut[a] = strtol10(cur,&cur); - if(a==iWrite-1) { - break; - } - if(!IsSpace(*cur)) { - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " is a string; failed to parse an integer array out of it."); - return AI_FAILURE; - } - } - - if (pMax) { - *pMax = iWrite; - } - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get a color (3 or 4 floats) from the material -aiReturn aiGetMaterialColor(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiColor4D* pOut) -{ - unsigned int iMax = 4; - const aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax); - - // if no alpha channel is defined: set it to 1.0 - if (3 == iMax) { - pOut->a = 1.0; - } - - return eRet; -} - -// ------------------------------------------------------------------------------------------------ -// Get a aiUVTransform (4 floats) from the material -aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiUVTransform* pOut) -{ - unsigned int iMax = 4; - return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax); -} - -// ------------------------------------------------------------------------------------------------ -// Get a string from the material -aiReturn aiGetMaterialString(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiString* pOut) -{ - ai_assert (pOut != NULL); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop); - if (!prop) { - return AI_FAILURE; - } - - if( aiPTI_String == prop->mType) { - ai_assert(prop->mDataLength>=5); - - // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data - pOut->length = static_cast(*reinterpret_cast(prop->mData)); - - ai_assert( pOut->length+1+4==prop->mDataLength ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - memcpy(pOut->data,prop->mData+4,pOut->length+1); - } - else { - // TODO - implement lexical cast as well - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " was found, but is no string" ); - return AI_FAILURE; - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get the number of textures on a particular texture stack -unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat, - C_ENUM aiTextureType type) -{ - ai_assert (pMat != NULL); - - // Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again) - unsigned int max = 0; - for (unsigned int i = 0; i < pMat->mNumProperties;++i) { - aiMaterialProperty* prop = pMat->mProperties[i]; - - if ( prop /* just a sanity check ... */ - && 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE ) - && prop->mSemantic == type) { - - max = std::max(max,prop->mIndex+1); - } - } - return max; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, - aiTextureType type, - unsigned int index, - C_STRUCT aiString* path, - aiTextureMapping* _mapping /*= NULL*/, - unsigned int* uvindex /*= NULL*/, - ai_real* blend /*= NULL*/, - aiTextureOp* op /*= NULL*/, - aiTextureMapMode* mapmode /*= NULL*/, - unsigned int* flags /*= NULL*/ - ) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != path ); - - // Get the path to the texture - if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path)) { - return AI_FAILURE; - } - - // Determine mapping type - int mapping_ = static_cast(aiTextureMapping_UV); - aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_); - aiTextureMapping mapping = static_cast(mapping_); - if (_mapping) - *_mapping = mapping; - - // Get UV index - if (aiTextureMapping_UV == mapping && uvindex) { - aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex); - } - // Get blend factor - if (blend) { - aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend); - } - // Get texture operation - if (op){ - aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op); - } - // Get texture mapping modes - if (mapmode) { - aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]); - aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]); - } - // Get texture flags - if (flags){ - aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags); - } - - return AI_SUCCESS; -} - - -static const unsigned int DefaultNumAllocated = 5; - -// ------------------------------------------------------------------------------------------------ -// Construction. Actually the one and only way to get an aiMaterial instance -aiMaterial::aiMaterial() -: mProperties( nullptr ) -, mNumProperties( 0 ) -, mNumAllocated( DefaultNumAllocated ) { - // Allocate 5 entries by default - mProperties = new aiMaterialProperty*[ DefaultNumAllocated ]; -} - -// ------------------------------------------------------------------------------------------------ -aiMaterial::~aiMaterial() -{ - Clear(); - - delete[] mProperties; -} - -// ------------------------------------------------------------------------------------------------ -aiString aiMaterial::GetName() { - aiString name; - Get(AI_MATKEY_NAME, name); - - return name; -} - -// ------------------------------------------------------------------------------------------------ -void aiMaterial::Clear() -{ - for ( unsigned int i = 0; i < mNumProperties; ++i ) { - // delete this entry - delete mProperties[ i ]; - AI_DEBUG_INVALIDATE_PTR(mProperties[i]); - } - mNumProperties = 0; - - // The array remains allocated, we just invalidated its contents -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::RemoveProperty ( const char* pKey,unsigned int type, unsigned int index ) -{ - ai_assert( nullptr != pKey ); - - for (unsigned int i = 0; i < mNumProperties;++i) { - aiMaterialProperty* prop = mProperties[i]; - - if (prop && !strcmp( prop->mKey.data, pKey ) && - prop->mSemantic == type && prop->mIndex == index) - { - // Delete this entry - delete mProperties[i]; - - // collapse the array behind --. - --mNumProperties; - for (unsigned int a = i; a < mNumProperties;++a) { - mProperties[a] = mProperties[a+1]; - } - return AI_SUCCESS; - } - } - - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::AddBinaryProperty (const void* pInput, - unsigned int pSizeInBytes, - const char* pKey, - unsigned int type, - unsigned int index, - aiPropertyTypeInfo pType - ) -{ - ai_assert( pInput != NULL ); - ai_assert( pKey != NULL ); - ai_assert( 0 != pSizeInBytes ); - - if ( 0 == pSizeInBytes ) { - - } - - // first search the list whether there is already an entry with this key - unsigned int iOutIndex( UINT_MAX ); - for ( unsigned int i = 0; i < mNumProperties; ++i ) { - aiMaterialProperty *prop( mProperties[ i ] ); - - if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) && - prop->mSemantic == type && prop->mIndex == index){ - - delete mProperties[i]; - iOutIndex = i; - } - } - - // Allocate a new material property - aiMaterialProperty* pcNew = new aiMaterialProperty(); - - // .. and fill it - pcNew->mType = pType; - pcNew->mSemantic = type; - pcNew->mIndex = index; - - pcNew->mDataLength = pSizeInBytes; - pcNew->mData = new char[pSizeInBytes]; - memcpy (pcNew->mData,pInput,pSizeInBytes); - - pcNew->mKey.length = ::strlen(pKey); - ai_assert ( MAXLEN > pcNew->mKey.length); - strcpy( pcNew->mKey.data, pKey ); - - if (UINT_MAX != iOutIndex) { - mProperties[iOutIndex] = pcNew; - return AI_SUCCESS; - } - - // resize the array ... double the storage allocated - if (mNumProperties == mNumAllocated) { - const unsigned int iOld = mNumAllocated; - mNumAllocated *= 2; - - aiMaterialProperty** ppTemp; - try { - ppTemp = new aiMaterialProperty*[mNumAllocated]; - } catch (std::bad_alloc&) { - delete pcNew; - return AI_OUTOFMEMORY; - } - - // just copy all items over; then replace the old array - memcpy (ppTemp,mProperties,iOld * sizeof(void*)); - - delete[] mProperties; - mProperties = ppTemp; - } - // push back ... - mProperties[mNumProperties++] = pcNew; - - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::AddProperty (const aiString* pInput, - const char* pKey, - unsigned int type, - unsigned int index) -{ - ai_assert(sizeof(ai_uint32)==4); - return AddBinaryProperty(pInput, - static_cast(pInput->length+1+4), - pKey, - type, - index, - aiPTI_String); -} - -// ------------------------------------------------------------------------------------------------ -uint32_t Assimp::ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/) -{ - uint32_t hash = 1503; // magic start value, chosen to be my birthday :-) - for ( unsigned int i = 0; i < mat->mNumProperties; ++i ) { - aiMaterialProperty* prop; - - // Exclude all properties whose first character is '?' from the hash - // See doc for aiMaterialProperty. - if ((prop = mat->mProperties[i]) && (includeMatName || prop->mKey.data[0] != '?')) { - - hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash); - hash = SuperFastHash(prop->mData,prop->mDataLength,hash); - - // Combine the semantic and the index with the hash - hash = SuperFastHash((const char*)&prop->mSemantic,sizeof(unsigned int),hash); - hash = SuperFastHash((const char*)&prop->mIndex,sizeof(unsigned int),hash); - } - } - return hash; -} - -// ------------------------------------------------------------------------------------------------ -void aiMaterial::CopyPropertyList(aiMaterial* pcDest, - const aiMaterial* pcSrc - ) -{ - ai_assert(NULL != pcDest); - ai_assert(NULL != pcSrc); - - unsigned int iOldNum = pcDest->mNumProperties; - pcDest->mNumAllocated += pcSrc->mNumAllocated; - pcDest->mNumProperties += pcSrc->mNumProperties; - - aiMaterialProperty** pcOld = pcDest->mProperties; - pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated]; - - if (iOldNum && pcOld) { - for (unsigned int i = 0; i < iOldNum;++i) { - pcDest->mProperties[i] = pcOld[i]; - } - } - - if ( pcOld ) { - delete[] pcOld; - } - - for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) { - aiMaterialProperty* propSrc = pcSrc->mProperties[i]; - - // search whether we have already a property with this name -> if yes, overwrite it - aiMaterialProperty* prop; - for ( unsigned int q = 0; q < iOldNum; ++q ) { - prop = pcDest->mProperties[q]; - if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic - && prop->mIndex == propSrc->mIndex) { - delete prop; - - // collapse the whole array ... - memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q); - i--; - pcDest->mNumProperties--; - } - } - - // Allocate the output property and copy the source property - prop = pcDest->mProperties[i] = new aiMaterialProperty(); - prop->mKey = propSrc->mKey; - prop->mDataLength = propSrc->mDataLength; - prop->mType = propSrc->mType; - prop->mSemantic = propSrc->mSemantic; - prop->mIndex = propSrc->mIndex; - - prop->mData = new char[propSrc->mDataLength]; - memcpy(prop->mData,propSrc->mData,prop->mDataLength); - } -} diff --git a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp b/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp deleted file mode 100644 index 75daeb6b5976..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ -#include "ArmaturePopulate.h" - -#include -#include -#include -#include -#include - -namespace Assimp { - -/// The default class constructor. -ArmaturePopulate::ArmaturePopulate() : BaseProcess() -{} - -/// The class destructor. -ArmaturePopulate::~ArmaturePopulate() -{} - -bool ArmaturePopulate::IsActive(unsigned int pFlags) const { - return (pFlags & aiProcess_PopulateArmatureData) != 0; -} - -void ArmaturePopulate::SetupProperties(const Importer *pImp) { - // do nothing -} - -void ArmaturePopulate::Execute(aiScene *out) { - - // Now convert all bone positions to the correct mOffsetMatrix - std::vector bones; - std::vector nodes; - std::map bone_stack; - BuildBoneList(out->mRootNode, out->mRootNode, out, bones); - BuildNodeList(out->mRootNode, nodes); - - BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes); - - ASSIMP_LOG_DEBUG_F("Bone stack size: ", bone_stack.size()); - - for (std::pair kvp : bone_stack) { - aiBone *bone = kvp.first; - aiNode *bone_node = kvp.second; - ASSIMP_LOG_DEBUG_F("active node lookup: ", bone->mName.C_Str()); - // lcl transform grab - done in generate_nodes :) - - // bone->mOffsetMatrix = bone_node->mTransformation; - aiNode *armature = GetArmatureRoot(bone_node, bones); - - ai_assert(armature); - - // set up bone armature id - bone->mArmature = armature; - - // set this bone node to be referenced properly - ai_assert(bone_node); - bone->mNode = bone_node; - } -} - - -/* Reprocess all nodes to calculate bone transforms properly based on the REAL - * mOffsetMatrix not the local. */ -/* Before this would use mesh transforms which is wrong for bone transforms */ -/* Before this would work for simple character skeletons but not complex meshes - * with multiple origins */ -/* Source: sketch fab log cutter fbx */ -void ArmaturePopulate::BuildBoneList(aiNode *current_node, - const aiNode *root_node, - const aiScene *scene, - std::vector &bones) { - ai_assert(scene); - for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) { - aiNode *child = current_node->mChildren[nodeId]; - ai_assert(child); - - // check for bones - for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) { - ai_assert(child->mMeshes); - unsigned int mesh_index = child->mMeshes[meshId]; - aiMesh *mesh = scene->mMeshes[mesh_index]; - ai_assert(mesh); - - for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) { - aiBone *bone = mesh->mBones[boneId]; - ai_assert(bone); - - // duplicate meshes exist with the same bones sometimes :) - // so this must be detected - if (std::find(bones.begin(), bones.end(), bone) == bones.end()) { - // add the element once - bones.push_back(bone); - } - } - - // find mesh and get bones - // then do recursive lookup for bones in root node hierarchy - } - - BuildBoneList(child, root_node, scene, bones); - } -} - -/* Prepare flat node list which can be used for non recursive lookups later */ -void ArmaturePopulate::BuildNodeList(const aiNode *current_node, - std::vector &nodes) { - ai_assert(current_node); - - for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) { - aiNode *child = current_node->mChildren[nodeId]; - ai_assert(child); - - nodes.push_back(child); - - BuildNodeList(child, nodes); - } -} - -/* A bone stack allows us to have multiple armatures, with the same bone names - * A bone stack allows us also to retrieve bones true transform even with - * duplicate names :) - */ -void ArmaturePopulate::BuildBoneStack(aiNode *current_node, - const aiNode *root_node, - const aiScene *scene, - const std::vector &bones, - std::map &bone_stack, - std::vector &node_stack) { - ai_assert(scene); - ai_assert(root_node); - ai_assert(!node_stack.empty()); - - for (aiBone *bone : bones) { - ai_assert(bone); - aiNode *node = GetNodeFromStack(bone->mName, node_stack); - if (node == nullptr) { - node_stack.clear(); - BuildNodeList(root_node, node_stack); - ASSIMP_LOG_DEBUG_F("Resetting bone stack: nullptr element ", bone->mName.C_Str()); - - node = GetNodeFromStack(bone->mName, node_stack); - - if (!node) { - ASSIMP_LOG_ERROR("serious import issue node for bone was not detected"); - continue; - } - } - - ASSIMP_LOG_DEBUG_F("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str()); - - bone_stack.insert(std::pair(bone, node)); - } -} - - -/* Returns the armature root node */ -/* This is required to be detected for a bone initially, it will recurse up - * until it cannot find another bone and return the node No known failure - * points. (yet) - */ -aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, - std::vector &bone_list) { - while (bone_node) { - if (!IsBoneNode(bone_node->mName, bone_list)) { - ASSIMP_LOG_DEBUG_F("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str()); - return bone_node; - } - - bone_node = bone_node->mParent; - } - - ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!"); - - return nullptr; -} - - - -/* Simple IsBoneNode check if this could be a bone */ -bool ArmaturePopulate::IsBoneNode(const aiString &bone_name, - std::vector &bones) { - for (aiBone *bone : bones) { - if (bone->mName == bone_name) { - return true; - } - } - - return false; -} - -/* Pop this node by name from the stack if found */ -/* Used in multiple armature situations with duplicate node / bone names */ -/* Known flaw: cannot have nodes with bone names, will be fixed in later release - */ -/* (serious to be fixed) Known flaw: nodes which have more than one bone could - * be prematurely dropped from stack */ -aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name, - std::vector &nodes) { - std::vector::iterator iter; - aiNode *found = nullptr; - for (iter = nodes.begin(); iter < nodes.end(); ++iter) { - aiNode *element = *iter; - ai_assert(element); - // node valid and node name matches - if (element->mName == node_name) { - found = element; - break; - } - } - - if (found != nullptr) { - ASSIMP_LOG_INFO_F("Removed node from stack: ", found->mName.C_Str()); - // now pop the element from the node list - nodes.erase(iter); - - return found; - } - - // unique names can cause this problem - ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!"); - - return nullptr; -} - - - - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h b/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h deleted file mode 100644 index aa1ad7c80c70..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -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 ARMATURE_POPULATE_H_ -#define ARMATURE_POPULATE_H_ - -#include "Common/BaseProcess.h" -#include -#include -#include - - -struct aiNode; -struct aiBone; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** Armature Populate: This is a post process designed - * To save you time when importing models into your game engines - * This was originally designed only for fbx but will work with other formats - * it is intended to auto populate aiBone data with armature and the aiNode - * This is very useful when dealing with skinned meshes - * or when dealing with many different skeletons - * It's off by default but recommend that you try it and use it - * It should reduce down any glue code you have in your - * importers - * You can contact RevoluPowered - * For more info about this -*/ -class ASSIMP_API ArmaturePopulate : public BaseProcess { -public: - /// The default class constructor. - ArmaturePopulate(); - - /// The class destructor. - virtual ~ArmaturePopulate(); - - /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); - - /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); - - static aiNode *GetArmatureRoot(aiNode *bone_node, - std::vector &bone_list); - - static bool IsBoneNode(const aiString &bone_name, - std::vector &bones); - - static aiNode *GetNodeFromStack(const aiString &node_name, - std::vector &nodes); - - static void BuildNodeList(const aiNode *current_node, - std::vector &nodes); - - static void BuildBoneList(aiNode *current_node, const aiNode *root_node, - const aiScene *scene, - std::vector &bones); - - static void BuildBoneStack(aiNode *current_node, const aiNode *root_node, - const aiScene *scene, - const std::vector &bones, - std::map &bone_stack, - std::vector &node_stack); -}; - -} // Namespace Assimp - - -#endif // SCALE_PROCESS_H_ \ No newline at end of file diff --git a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp b/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp deleted file mode 100644 index a3f7dd2557c3..000000000000 --- a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to calculate - * tangents and bitangents for all imported meshes - */ - -// internal headers -#include "CalcTangentsProcess.h" -#include "ProcessHelper.h" -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -CalcTangentsProcess::CalcTangentsProcess() -: configMaxAngle( AI_DEG_TO_RAD(45.f) ) -, configSourceUV( 0 ) { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -CalcTangentsProcess::~CalcTangentsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool CalcTangentsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_CalcTangentSpace) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void CalcTangentsProcess::SetupProperties(const Importer* pImp) -{ - ai_assert( NULL != pImp ); - - // get the current value of the property - configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f); - configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f); - configMaxAngle = AI_DEG_TO_RAD(configMaxAngle); - - configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void CalcTangentsProcess::Execute( aiScene* pScene) -{ - ai_assert( NULL != pScene ); - - ASSIMP_LOG_DEBUG("CalcTangentsProcess begin"); - - bool bHas = false; - for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) { - if(ProcessMesh( pScene->mMeshes[a],a))bHas = true; - } - - if ( bHas ) { - ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated"); - } else { - ASSIMP_LOG_DEBUG("CalcTangentsProcess finished"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Calculates tangents and bi-tangents for the given mesh -bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) -{ - // we assume that the mesh is still in the verbose vertex format where each face has its own set - // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to - // assert() it here. - // assert( must be verbose, dammit); - - if (pMesh->mTangents) // this implies that mBitangents is also there - return false; - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) - { - ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes"); - return false; - } - - // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement - if( pMesh->mNormals == NULL) - { - ASSIMP_LOG_ERROR("Failed to compute tangents; need normals"); - return false; - } - if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] ) - { - ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV)); - return false; - } - - const float angleEpsilon = 0.9999f; - - std::vector vertexDone( pMesh->mNumVertices, false); - const float qnan = get_qnan(); - - // create space for the tangents and bitangents - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - - const aiVector3D* meshPos = pMesh->mVertices; - const aiVector3D* meshNorm = pMesh->mNormals; - const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV]; - aiVector3D* meshTang = pMesh->mTangents; - aiVector3D* meshBitang = pMesh->mBitangents; - - // calculate the tangent and bitangent for every face - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) - { - // There are less than three indices, thus the tangent vector - // is not defined. We are finished with these vertices now, - // their tangent vectors are set to qnan. - for (unsigned int i = 0; i < face.mNumIndices;++i) - { - unsigned int idx = face.mIndices[i]; - vertexDone [idx] = true; - meshTang [idx] = aiVector3D(qnan); - meshBitang [idx] = aiVector3D(qnan); - } - - continue; - } - - // triangle or polygon... we always use only the first three indices. A polygon - // is supposed to be planar anyways.... - // FIXME: (thom) create correct calculation for multi-vertex polygons maybe? - const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2]; - - // position differences p1->p2 and p1->p3 - aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0]; - - // texture offset p1->p2 and p1->p3 - float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y; - float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y; - float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f; - // when t1, t2, t3 in same position in UV space, just use default UV direction. - if ( sx * ty == sy * tx ) { - sx = 0.0; sy = 1.0; - tx = 1.0; ty = 0.0; - } - - // tangent points in the direction where to positive X axis of the texture coord's would point in model space - // bitangent's points along the positive Y axis of the texture coord's, respectively - aiVector3D tangent, bitangent; - tangent.x = (w.x * sy - v.x * ty) * dirCorrection; - tangent.y = (w.y * sy - v.y * ty) * dirCorrection; - tangent.z = (w.z * sy - v.z * ty) * dirCorrection; - bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; - bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; - bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; - - // store for every vertex of that face - for( unsigned int b = 0; b < face.mNumIndices; ++b ) { - unsigned int p = face.mIndices[b]; - - // project tangent and bitangent into the plane formed by the vertex' normal - aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); - aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); - localTangent.NormalizeSafe(); localBitangent.NormalizeSafe(); - - // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN. - bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z); - bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z); - if (invalid_tangent != invalid_bitangent) { - if (invalid_tangent) { - localTangent = meshNorm[p] ^ localBitangent; - localTangent.NormalizeSafe(); - } else { - localBitangent = localTangent ^ meshNorm[p]; - localBitangent.NormalizeSafe(); - } - } - - // and write it into the mesh. - meshTang[ p ] = localTangent; - meshBitang[ p ] = localBitangent; - } - } - - - // create a helper to quickly find locally close vertices among the vertex array - // FIX: check whether we can reuse the SpatialSort of a previous step - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - float posEpsilon; - if (shared) - { - std::vector >* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) - { - std::pair& blubb = avf->operator [] (meshIndex); - vertexFinder = &blubb.first; - posEpsilon = blubb.second;; - } - } - if (!vertexFinder) - { - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - posEpsilon = ComputePositionEpsilon(pMesh); - } - std::vector verticesFound; - - const float fLimit = std::cos(configMaxAngle); - std::vector closeVertices; - - // in the second pass we now smooth out all tangents and bitangents at the same local position - // if they are not too far off. - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - { - if( vertexDone[a]) - continue; - - const aiVector3D& origPos = pMesh->mVertices[a]; - const aiVector3D& origNorm = pMesh->mNormals[a]; - const aiVector3D& origTang = pMesh->mTangents[a]; - const aiVector3D& origBitang = pMesh->mBitangents[a]; - closeVertices.resize( 0 ); - - // find all vertices close to that position - vertexFinder->FindPositions( origPos, posEpsilon, verticesFound); - - closeVertices.reserve (verticesFound.size()+5); - closeVertices.push_back( a); - - // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent - for( unsigned int b = 0; b < verticesFound.size(); b++) - { - unsigned int idx = verticesFound[b]; - if( vertexDone[idx]) - continue; - if( meshNorm[idx] * origNorm < angleEpsilon) - continue; - if( meshTang[idx] * origTang < fLimit) - continue; - if( meshBitang[idx] * origBitang < fLimit) - continue; - - // it's similar enough -> add it to the smoothing group - closeVertices.push_back( idx); - vertexDone[idx] = true; - } - - // smooth the tangents and bitangents of all vertices that were found to be close enough - aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0); - for( unsigned int b = 0; b < closeVertices.size(); ++b) - { - smoothTangent += meshTang[ closeVertices[b] ]; - smoothBitangent += meshBitang[ closeVertices[b] ]; - } - smoothTangent.Normalize(); - smoothBitangent.Normalize(); - - // and write it back into all affected tangents - for( unsigned int b = 0; b < closeVertices.size(); ++b) - { - meshTang[ closeVertices[b] ] = smoothTangent; - meshBitang[ closeVertices[b] ] = smoothBitangent; - } - } - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h b/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h deleted file mode 100644 index 3568a624f866..000000000000 --- a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -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 Defines a post processing step to calculate tangents and - bi-tangents on all imported meshes.*/ -#ifndef AI_CALCTANGENTSPROCESS_H_INC -#define AI_CALCTANGENTSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The CalcTangentsProcess calculates the tangent and bitangent for any vertex - * of all meshes. It is expected to be run before the JoinVerticesProcess runs - * because the joining of vertices also considers tangents and bitangents for - * uniqueness. - */ -class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess -{ -public: - - CalcTangentsProcess(); - ~CalcTangentsProcess(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - - // setter for configMaxAngle - inline void SetMaxSmoothAngle(float f) - { - configMaxAngle =f; - } - -protected: - - // ------------------------------------------------------------------- - /** Calculates tangents and bitangents for a specific mesh. - * @param pMesh The mesh to process. - * @param meshIndex Index of the mesh - */ - bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -private: - - /** Configuration option: maximum smoothing angle, in radians*/ - float configMaxAngle; - unsigned int configSourceUV; -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp b/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp deleted file mode 100644 index df4d44337d1d..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp +++ /dev/null @@ -1,506 +0,0 @@ -/* -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 GenUVCoords step */ - - -#include "ComputeUVMappingProcess.h" -#include "ProcessHelper.h" -#include - -using namespace Assimp; - -namespace { - - const static aiVector3D base_axis_y(0.0,1.0,0.0); - const static aiVector3D base_axis_x(1.0,0.0,0.0); - const static aiVector3D base_axis_z(0.0,0.0,1.0); - const static ai_real angle_epsilon = ai_real( 0.95 ); -} - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ComputeUVMappingProcess::ComputeUVMappingProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ComputeUVMappingProcess::~ComputeUVMappingProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_GenUVCoords) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a ray intersects a plane and find the intersection point -inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, - const aiVector3D& planeNormal, aiVector3D& pos) -{ - const ai_real b = planeNormal * (planePos - ray.pos); - ai_real h = ray.dir * planeNormal; - if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0) - return false; - - pos = ray.pos + (ray.dir * h); - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Find the first empty UV channel in a mesh -inline unsigned int FindEmptyUVChannel (aiMesh* mesh) -{ - for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) - if (!mesh->mTextureCoords[m])return m; - - ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found"); - return UINT_MAX; -} - -// ------------------------------------------------------------------------------------------------ -// Try to remove UV seams -void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) -{ - // TODO: just a very rough algorithm. I think it could be done - // much easier, but I don't know how and am currently too tired to - // to think about a better solution. - - const static ai_real LOWER_LIMIT = ai_real( 0.1 ); - const static ai_real UPPER_LIMIT = ai_real( 0.9 ); - - const static ai_real LOWER_EPSILON = ai_real( 10e-3 ); - const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 ); - - for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) - { - const aiFace& face = mesh->mFaces[fidx]; - if (face.mNumIndices < 3) continue; // triangles and polygons only, please - - unsigned int small = face.mNumIndices, large = small; - bool zero = false, one = false, round_to_zero = false; - - // Check whether this face lies on a UV seam. We can just guess, - // but the assumption that a face with at least one very small - // on the one side and one very large U coord on the other side - // lies on a UV seam should work for most cases. - for (unsigned int n = 0; n < face.mNumIndices;++n) - { - if (out[face.mIndices[n]].x < LOWER_LIMIT) - { - small = n; - - // If we have a U value very close to 0 we can't - // round the others to 0, too. - if (out[face.mIndices[n]].x <= LOWER_EPSILON) - zero = true; - else round_to_zero = true; - } - if (out[face.mIndices[n]].x > UPPER_LIMIT) - { - large = n; - - // If we have a U value very close to 1 we can't - // round the others to 1, too. - if (out[face.mIndices[n]].x >= UPPER_EPSILON) - one = true; - } - } - if (small != face.mNumIndices && large != face.mNumIndices) - { - for (unsigned int n = 0; n < face.mNumIndices;++n) - { - // If the u value is over the upper limit and no other u - // value of that face is 0, round it to 0 - if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) - out[face.mIndices[n]].x = 0.0; - - // If the u value is below the lower limit and no other u - // value of that face is 1, round it to 1 - else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one) - out[face.mIndices[n]].x = 1.0; - - // The face contains both 0 and 1 as UV coords. This can occur - // for faces which have an edge that lies directly on the seam. - // Due to numerical inaccuracies one U coord becomes 0, the - // other 1. But we do still have a third UV coord to determine - // to which side we must round to. - else if (one && zero) - { - if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) - out[face.mIndices[n]].x = 0.0; - else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) - out[face.mIndices[n]].x = 1.0; - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - aiVector3D center, min, max; - FindMeshCenter(mesh, center, min, max); - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - - // For each point get a normalized projection vector in the sphere, - // get its longitude and latitude and map them to their respective - // UV axes. Problems occur around the poles ... unsolvable. - // - // The spherical coordinate system looks like this: - // x = cos(lon)*cos(lat) - // y = sin(lon)*cos(lat) - // z = sin(lat) - // - // Thus we can derive: - // lat = arcsin (z) - // lon = arctan (y/x) - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - else if (axis * base_axis_y >= angle_epsilon) { - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - else if (axis * base_axis_z >= angle_epsilon) { - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - - - // Now find and remove UV seams. A seam occurs if a face has a tcoord - // close to zero on the one side, and a tcoord close to one on the - // other side. - RemoveUVSeams(mesh,out); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - aiVector3D center, min, max; - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.x - min.x; - - // If the main axis is 'z', the z coordinate of a point 'p' is mapped - // directly to the texture V axis. The other axis is derived from - // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where - // 'c' is the center point of the mesh. - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.x - min.x) / diff; - uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - else if (axis * base_axis_y >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.y - min.y; - - // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - else if (axis * base_axis_z >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.z - min.z; - - // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.z - min.z) / diff; - uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); - const ai_real diff = max.y - min.y; - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ - const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - - // Now find and remove UV seams. A seam occurs if a face has a tcoord - // close to zero on the one side, and a tcoord close to one on the - // other side. - RemoveUVSeams(mesh,out); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - ai_real diffu,diffv; - aiVector3D center, min, max; - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.z - min.z; - diffv = max.y - min.y; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0); - } - } - else if (axis * base_axis_y >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.x - min.x; - diffv = max.z - min.z; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); - } - } - else if (axis * base_axis_z >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.x - min.x; - diffv = max.y - min.y; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0); - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else - { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); - diffu = max.x - min.x; - diffv = max.z - min.z; - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); - } - } - - // shouldn't be necessary to remove UV seams ... -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) -{ - ASSIMP_LOG_ERROR("Mapping type currently not implemented"); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); - char buffer[1024]; - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - - std::list mappingStack; - - /* Iterate through all materials and search for non-UV mapped textures - */ - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { - mappingStack.clear(); - aiMaterial* mat = pScene->mMaterials[i]; - for (unsigned int a = 0; a < mat->mNumProperties;++a) - { - aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.mapping")) - { - aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); - if (aiTextureMapping_UV != mapping) - { - if (!DefaultLogger::isNullLogger()) - { - ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", - TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, - MappingTypeToString(mapping)); - - ASSIMP_LOG_INFO(buffer); - } - - if (aiTextureMapping_OTHER == mapping) - continue; - - MappingInfo info (mapping); - - // Get further properties - currently only the major axis - for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) - { - aiMaterialProperty* prop2 = mat->mProperties[a2]; - if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) - continue; - - if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { - info.axis = *((aiVector3D*)prop2->mData); - break; - } - } - - unsigned int idx( 99999999 ); - - // Check whether we have this mapping mode already - std::list::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); - if (mappingStack.end() != it) - { - idx = (*it).uv; - } - else - { - /* We have found a non-UV mapped texture. Now - * we need to find all meshes using this material - * that we can compute UV channels for them. - */ - for (unsigned int m = 0; m < pScene->mNumMeshes;++m) - { - aiMesh* mesh = pScene->mMeshes[m]; - unsigned int outIdx = 0; - if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || - !mesh->mNumVertices) - { - continue; - } - - // Allocate output storage - aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; - - switch (mapping) - { - case aiTextureMapping_SPHERE: - ComputeSphereMapping(mesh,info.axis,p); - break; - case aiTextureMapping_CYLINDER: - ComputeCylinderMapping(mesh,info.axis,p); - break; - case aiTextureMapping_PLANE: - ComputePlaneMapping(mesh,info.axis,p); - break; - case aiTextureMapping_BOX: - ComputeBoxMapping(mesh,p); - break; - default: - ai_assert(false); - } - if (m && idx != outIdx) - { - ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to " - "this material have equal numbers of UV channels. The UV index stored in " - "the material structure does therefore not apply for all meshes. "); - } - idx = outIdx; - } - info.uv = idx; - mappingStack.push_back(info); - } - - // Update the material property list - mapping = aiTextureMapping_UV; - ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); - } - } - } - } - ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished"); -} diff --git a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h b/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h deleted file mode 100644 index a6d36e06ea9b..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -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 Defines a post processing step to compute UV coordinates - from abstract mappings, such as box or spherical*/ -#ifndef AI_COMPUTEUVMAPPING_H_INC -#define AI_COMPUTEUVMAPPING_H_INC - -#include "Common/BaseProcess.h" - -#include -#include -#include - -class ComputeUVMappingTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** ComputeUVMappingProcess - converts special mappings, such as spherical, - * cylindrical or boxed to proper UV coordinates for rendering. -*/ -class ComputeUVMappingProcess : public BaseProcess -{ -public: - ComputeUVMappingProcess(); - ~ComputeUVMappingProcess(); - -public: - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Computes spherical UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes cylindrical UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes planar UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes cubic UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param out Receives output UV coordinates - */ - void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out); - -private: - - // temporary structure to describe a mapping - struct MappingInfo - { - explicit MappingInfo(aiTextureMapping _type) - : type (_type) - , axis (0.f,1.f,0.f) - , uv (0u) - {} - - aiTextureMapping type; - aiVector3D axis; - unsigned int uv; - - bool operator== (const MappingInfo& other) - { - return type == other.type && axis == other.axis; - } - }; -}; - -} // end of namespace Assimp - -#endif // AI_COMPUTEUVMAPPING_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp b/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp deleted file mode 100644 index b7cd4f0bc68f..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 MakeLeftHandedProcess.cpp - * @brief Implementation of the post processing step to convert all - * imported data to a left-handed coordinate system. - * - * Face order & UV flip are also implemented here, for the sake of a - * better location. - */ - - -#include "ConvertToLHProcess.h" -#include -#include -#include - -using namespace Assimp; - -#ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS - -namespace { - -template -void flipUVs(aiMeshType* pMesh) { - if (pMesh == nullptr) { return; } - // mirror texture y coordinate - for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) { - if (!pMesh->HasTextureCoords(tcIdx)) { - break; - } - - for (unsigned int vIdx = 0; vIdx < pMesh->mNumVertices; vIdx++) { - pMesh->mTextureCoords[tcIdx][vIdx].y = 1.0f - pMesh->mTextureCoords[tcIdx][vIdx].y; - } - } -} - -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -MakeLeftHandedProcess::MakeLeftHandedProcess() -: BaseProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -MakeLeftHandedProcess::~MakeLeftHandedProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_MakeLeftHanded); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void MakeLeftHandedProcess::Execute( aiScene* pScene) -{ - // Check for an existent root node to proceed - ai_assert(pScene->mRootNode != NULL); - ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin"); - - // recursively convert all the nodes - ProcessNode( pScene->mRootNode, aiMatrix4x4()); - - // process the meshes accordingly - for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh( pScene->mMeshes[ a ] ); - } - - // process the materials accordingly - for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) { - ProcessMaterial( pScene->mMaterials[ a ] ); - } - - // transform all animation channels as well - for( unsigned int a = 0; a < pScene->mNumAnimations; a++) - { - aiAnimation* anim = pScene->mAnimations[a]; - for( unsigned int b = 0; b < anim->mNumChannels; b++) - { - aiNodeAnim* nodeAnim = anim->mChannels[b]; - ProcessAnimation( nodeAnim); - } - } - ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Recursively converts a node, all of its children and all of its meshes -void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation) -{ - // mirror all base vectors at the local Z axis - pNode->mTransformation.c1 = -pNode->mTransformation.c1; - pNode->mTransformation.c2 = -pNode->mTransformation.c2; - pNode->mTransformation.c3 = -pNode->mTransformation.c3; - pNode->mTransformation.c4 = -pNode->mTransformation.c4; - - // now invert the Z axis again to keep the matrix determinant positive. - // The local meshes will be inverted accordingly so that the result should look just fine again. - pNode->mTransformation.a3 = -pNode->mTransformation.a3; - pNode->mTransformation.b3 = -pNode->mTransformation.b3; - pNode->mTransformation.c3 = -pNode->mTransformation.c3; - pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways... - - // continue for all children - for( size_t a = 0; a < pNode->mNumChildren; ++a ) { - ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh to left handed coordinates. -void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) { - if ( nullptr == pMesh ) { - ASSIMP_LOG_ERROR( "Nullptr to mesh found." ); - return; - } - // mirror positions, normals and stuff along the Z axis - for( size_t a = 0; a < pMesh->mNumVertices; ++a) - { - pMesh->mVertices[a].z *= -1.0f; - if (pMesh->HasNormals()) { - pMesh->mNormals[a].z *= -1.0f; - } - if( pMesh->HasTangentsAndBitangents()) - { - pMesh->mTangents[a].z *= -1.0f; - pMesh->mBitangents[a].z *= -1.0f; - } - } - - // mirror anim meshes positions, normals and stuff along the Z axis - for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) - { - for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) - { - pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f; - if (pMesh->mAnimMeshes[m]->HasNormals()) { - pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f; - } - if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents()) - { - pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f; - pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f; - } - } - } - - // mirror offset matrices of all bones - for( size_t a = 0; a < pMesh->mNumBones; ++a) - { - aiBone* bone = pMesh->mBones[a]; - bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3; - bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3; - bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3; - bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1; - bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2; - bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4; - } - - // mirror bitangents as well as they're derived from the texture coords - if( pMesh->HasTangentsAndBitangents()) - { - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - pMesh->mBitangents[a] *= -1.0f; - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single material to left handed coordinates. -void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) { - if ( nullptr == _mat ) { - ASSIMP_LOG_ERROR( "Nullptr to aiMaterial found." ); - return; - } - - aiMaterial* mat = (aiMaterial*)_mat; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - aiMaterialProperty* prop = mat->mProperties[a]; - - // Mapping axis for UV mappings? - if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) { - ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */ - aiVector3D* pff = (aiVector3D*)prop->mData; - pff->z *= -1.f; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts the given animation to LH coordinates. -void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim) -{ - // position keys - for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++) - pAnim->mPositionKeys[a].mValue.z *= -1.0f; - - // rotation keys - for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) - { - /* That's the safe version, but the float errors add up. So we try the short version instead - aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix(); - rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3; - rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2; - aiQuaternion rotquat( rotmat); - pAnim->mRotationKeys[a].mValue = rotquat; - */ - pAnim->mRotationKeys[a].mValue.x *= -1.0f; - pAnim->mRotationKeys[a].mValue.y *= -1.0f; - } -} - -#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS -#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS -// # FlipUVsProcess - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FlipUVsProcess::FlipUVsProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FlipUVsProcess::~FlipUVsProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FlipUVsProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_FlipUVs); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FlipUVsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FlipUVsProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - ProcessMesh(pScene->mMeshes[i]); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - ProcessMaterial(pScene->mMaterials[i]); - ASSIMP_LOG_DEBUG("FlipUVsProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single material -void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat) -{ - aiMaterial* mat = (aiMaterial*)_mat; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - aiMaterialProperty* prop = mat->mProperties[a]; - if( !prop ) { - ASSIMP_LOG_DEBUG( "Property is null" ); - continue; - } - - // UV transformation key? - if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) { - ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */ - aiUVTransform* uv = (aiUVTransform*)prop->mData; - - // just flip it, that's everything - uv->mTranslation.y *= -1.f; - uv->mRotation *= -1.f; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh -void FlipUVsProcess::ProcessMesh( aiMesh* pMesh) -{ - flipUVs(pMesh); - for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) { - flipUVs(pMesh->mAnimMeshes[idx]); - } -} - -#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS -#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS -// # FlipWindingOrderProcess - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FlipWindingOrderProcess::FlipWindingOrderProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FlipWindingOrderProcess::~FlipWindingOrderProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_FlipWindingOrder); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FlipWindingOrderProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - ProcessMesh(pScene->mMeshes[i]); - ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh -void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh) -{ - // invert the order of all faces in this mesh - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for (unsigned int b = 0; b < face.mNumIndices / 2; b++) { - std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]); - } - } - - // invert the order of all components in this mesh anim meshes - for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) { - aiAnimMesh* animMesh = pMesh->mAnimMeshes[m]; - unsigned int numVertices = animMesh->mNumVertices; - if (animMesh->HasPositions()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]); - } - } - if (animMesh->HasNormals()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]); - } - } - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) { - if (animMesh->HasTextureCoords(i)) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]); - } - } - } - if (animMesh->HasTangentsAndBitangents()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]); - std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]); - } - } - for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) { - if (animMesh->HasVertexColors(v)) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]); - } - } - } - } -} - -#endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h b/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h deleted file mode 100644 index f32b91fc3952..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -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 MakeLeftHandedProcess.h - * @brief Defines a bunch of post-processing steps to handle - * coordinate system conversions. - * - * - LH to RH - * - UV origin upper-left to lower-left - * - face order cw to ccw - */ -#ifndef AI_CONVERTTOLHPROCESS_H_INC -#define AI_CONVERTTOLHPROCESS_H_INC - -#include - -#include "Common/BaseProcess.h" - -struct aiMesh; -struct aiNodeAnim; -struct aiNode; -struct aiMaterial; - -namespace Assimp { - -// ----------------------------------------------------------------------------------- -/** @brief The MakeLeftHandedProcess converts all imported data to a left-handed - * coordinate system. - * - * This implies a mirroring of the Z axis of the coordinate system. But to keep - * transformation matrices free from reflections we shift the reflection to other - * places. We mirror the meshes and adapt the rotations. - * - * @note RH-LH and LH-RH is the same, so this class can be used for both - */ -class MakeLeftHandedProcess : public BaseProcess -{ - - -public: - MakeLeftHandedProcess(); - ~MakeLeftHandedProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Recursively converts a node and all of its children - */ - void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation); - - // ------------------------------------------------------------------- - /** Converts a single mesh to left handed coordinates. - * This means that positions, normals and tangents are mirrored at - * the local Z axis and the order of all faces are inverted. - * @param pMesh The mesh to convert. - */ - void ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Converts a single material to left-handed coordinates - * @param pMat Material to convert - */ - void ProcessMaterial( aiMaterial* pMat); - - // ------------------------------------------------------------------- - /** Converts the given animation to LH coordinates. - * The rotation and translation keys are transformed, the scale keys - * work in local space and can therefore be left untouched. - * @param pAnim The bone animation to transform - */ - void ProcessAnimation( aiNodeAnim* pAnim); -}; - - -// --------------------------------------------------------------------------- -/** Postprocessing step to flip the face order of the imported data - */ -class FlipWindingOrderProcess : public BaseProcess -{ - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - FlipWindingOrderProcess(); - - /** Destructor, private as well */ - ~FlipWindingOrderProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - void ProcessMesh( aiMesh* pMesh); -}; - -// --------------------------------------------------------------------------- -/** Postprocessing step to flip the UV coordinate system of the import data - */ -class FlipUVsProcess : public BaseProcess -{ - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - FlipUVsProcess(); - - /** Destructor, private as well */ - ~FlipUVsProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - void ProcessMesh( aiMesh* pMesh); - void ProcessMaterial( aiMaterial* mat); -}; - -} // end of namespace Assimp - -#endif // AI_CONVERTTOLHPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp b/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp deleted file mode 100644 index 83b8336bc9fa..000000000000 --- a/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -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 DeboneProcess.cpp -/** Implementation of the DeboneProcess post processing step */ - - - -// internal headers of the post-processing framework -#include "ProcessHelper.h" -#include "DeboneProcess.h" -#include - - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -DeboneProcess::DeboneProcess() -{ - mNumBones = 0; - mNumBonesCanDoWithout = 0; - - mThreshold = AI_DEBONE_THRESHOLD; - mAllOrNone = false; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DeboneProcess::~DeboneProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool DeboneProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_Debone) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DeboneProcess::SetupProperties(const Importer* pImp) -{ - // get the current value of the property - mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false; - mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DeboneProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("DeboneProcess begin"); - - if(!pScene->mNumMeshes) { - return; - } - - std::vector splitList(pScene->mNumMeshes); - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - splitList[a] = ConsiderMesh( pScene->mMeshes[a] ); - } - - int numSplits = 0; - - if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) { - for(unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if(splitList[a]) { - numSplits++; - } - } - } - - if(numSplits) { - // we need to do something. Let's go. - //mSubMeshIndices.clear(); // really needed? - mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway - - // build a new array of meshes for the scene - std::vector meshes; - - for(unsigned int a=0;amNumMeshes;a++) - { - aiMesh* srcMesh = pScene->mMeshes[a]; - - std::vector > newMeshes; - - if(splitList[a]) { - SplitMesh(srcMesh,newMeshes); - } - - // mesh was split - if(!newMeshes.empty()) { - unsigned int out = 0, in = srcMesh->mNumBones; - - // store new meshes and indices of the new meshes - for(unsigned int b=0;bmName:0; - - aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0; - std::pair push_pair(static_cast(meshes.size()),theNode); - - mSubMeshIndices[a].push_back(push_pair); - meshes.push_back(newMeshes[b].first); - - out+=newMeshes[b].first->mNumBones; - } - - if(!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed %u bones. Input bones:", in - out, ". Output bones: ", out); - } - - // and destroy the source mesh. It should be completely contained inside the new submeshes - delete srcMesh; - } - else { - // Mesh is kept unchanged - store it's new place in the mesh array - mSubMeshIndices[a].push_back(std::pair(static_cast(meshes.size()),(aiNode*)0)); - meshes.push_back(srcMesh); - } - } - - // rebuild the scene's mesh array - pScene->mNumMeshes = static_cast(meshes.size()); - delete [] pScene->mMeshes; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - std::copy( meshes.begin(), meshes.end(), pScene->mMeshes); - - // recurse through all nodes and translate the node's mesh indices to fit the new mesh array - UpdateNode( pScene->mRootNode); - } - - ASSIMP_LOG_DEBUG("DeboneProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -// Counts bones total/removable in a given mesh. -bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) -{ - if(!pMesh->HasBones()) { - return false; - } - - bool split = false; - - //interstitial faces not permitted - bool isInterstitialRequired = false; - - std::vector isBoneNecessary(pMesh->mNumBones,false); - std::vector vertexBones(pMesh->mNumVertices,UINT_MAX); - - const unsigned int cUnowned = UINT_MAX; - const unsigned int cCoowned = UINT_MAX-1; - - for(unsigned int i=0;imNumBones;i++) { - for(unsigned int j=0;jmBones[i]->mNumWeights;j++) { - float w = pMesh->mBones[i]->mWeights[j].mWeight; - - if(w==0.0f) { - continue; - } - - unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; - if(w>=mThreshold) { - - if(vertexBones[vid]!=cUnowned) { - if(vertexBones[vid]==i) //double entry - { - ASSIMP_LOG_WARN("Encountered double entry in bone weights"); - } - else //TODO: track attraction in order to break tie - { - vertexBones[vid] = cCoowned; - } - } - else vertexBones[vid] = i; - } - - if(!isBoneNecessary[i]) { - isBoneNecessary[i] = wmNumFaces;i++) { - unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; - - for(unsigned int j=1;jmFaces[i].mNumIndices;j++) { - unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; - - if(v!=w) { - if(vmNumBones) isBoneNecessary[v] = true; - if(wmNumBones) isBoneNecessary[w] = true; - } - } - } - } - - for(unsigned int i=0;imNumBones;i++) { - if(!isBoneNecessary[i]) { - mNumBonesCanDoWithout++; - split = true; - } - - mNumBones++; - } - return split; -} - -// ------------------------------------------------------------------------------------------------ -// Splits the given mesh by bone count. -void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const -{ - // same deal here as ConsiderMesh basically - - std::vector isBoneNecessary(pMesh->mNumBones,false); - std::vector vertexBones(pMesh->mNumVertices,UINT_MAX); - - const unsigned int cUnowned = UINT_MAX; - const unsigned int cCoowned = UINT_MAX-1; - - for(unsigned int i=0;imNumBones;i++) { - for(unsigned int j=0;jmBones[i]->mNumWeights;j++) { - float w = pMesh->mBones[i]->mWeights[j].mWeight; - - if(w==0.0f) { - continue; - } - - unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; - - if(w>=mThreshold) { - if(vertexBones[vid]!=cUnowned) { - if(vertexBones[vid]==i) //double entry - { - ASSIMP_LOG_WARN("Encountered double entry in bone weights"); - } - else //TODO: track attraction in order to break tie - { - vertexBones[vid] = cCoowned; - } - } - else vertexBones[vid] = i; - } - - if(!isBoneNecessary[i]) { - isBoneNecessary[i] = w faceBones(pMesh->mNumFaces,UINT_MAX); - std::vector facesPerBone(pMesh->mNumBones,0); - - for(unsigned int i=0;imNumFaces;i++) { - unsigned int nInterstitial = 1; - - unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; - - for(unsigned int j=1;jmFaces[i].mNumIndices;j++) { - unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; - - if(v!=w) { - if(vmNumBones) isBoneNecessary[v] = true; - if(wmNumBones) isBoneNecessary[w] = true; - } - else nInterstitial++; - } - - if(vmNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) { - faceBones[i] = v; //primitive belongs to bone #v - facesPerBone[v]++; - } - else nFacesUnowned++; - } - - // invalidate any "cojoined" faces - for(unsigned int i=0;imNumFaces;i++) { - if(faceBones[i]mNumBones&&isBoneNecessary[faceBones[i]]) - { - ai_assert(facesPerBone[faceBones[i]]>0); - facesPerBone[faceBones[i]]--; - - nFacesUnowned++; - faceBones[i] = cUnowned; - } - } - - if(nFacesUnowned) { - std::vector subFaces; - - for(unsigned int i=0;imNumFaces;i++) { - if(faceBones[i]==cUnowned) { - subFaces.push_back(i); - } - } - - aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0); - std::pair push_pair(baseMesh,(const aiBone*)0); - - poNewMeshes.push_back(push_pair); - } - - for(unsigned int i=0;imNumBones;i++) { - - if(!isBoneNecessary[i]&&facesPerBone[i]>0) { - std::vector subFaces; - - for(unsigned int j=0;jmNumFaces;j++) { - if(faceBones[j]==i) { - subFaces.push_back(j); - } - } - - unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES; - aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f); - - //Lifted from PretransformVertices.cpp - ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix); - std::pair push_pair(subMesh,pMesh->mBones[i]); - - poNewMeshes.push_back(push_pair); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively updates the node's mesh list to account for the changed mesh list -void DeboneProcess::UpdateNode(aiNode* pNode) const -{ - // rebuild the node's mesh index list - - std::vector newMeshList; - - // this will require two passes - - unsigned int m = static_cast(pNode->mNumMeshes), n = static_cast(mSubMeshIndices.size()); - - // first pass, look for meshes which have not moved - - for(unsigned int a=0;amMeshes[a]; - const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex]; - unsigned int nSubmeshes = static_cast(subMeshes.size()); - - for(unsigned int b=0;b > &subMeshes = mSubMeshIndices[a]; - unsigned int nSubmeshes = static_cast(subMeshes.size()); - - for(unsigned int b=0;bmNumMeshes > 0 ) { - delete [] pNode->mMeshes; pNode->mMeshes = NULL; - } - - pNode->mNumMeshes = static_cast(newMeshList.size()); - - if(pNode->mNumMeshes) { - pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; - std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes); - } - - // do that also recursively for all children - for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) { - UpdateNode( pNode->mChildren[a]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the node transformation to a mesh -void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const -{ - // Check whether we need to transform the coordinates at all - if (!mat.IsIdentity()) { - - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - aiMatrix4x4 mWorldIT = mat; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } - } - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/DeboneProcess.h b/thirdparty/assimp/code/PostProcessing/DeboneProcess.h deleted file mode 100644 index 8b64c2acc670..000000000000 --- a/thirdparty/assimp/code/PostProcessing/DeboneProcess.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -/** Defines a post processing step to limit the number of bones affecting a single vertex. */ -#ifndef AI_DEBONEPROCESS_H_INC -#define AI_DEBONEPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include -#include - -#include -#include - -#// Forward declarations -class DeboneTest; - -namespace Assimp { - -#if (!defined AI_DEBONE_THRESHOLD) -# define AI_DEBONE_THRESHOLD 1.0f -#endif // !! AI_DEBONE_THRESHOLD - -// --------------------------------------------------------------------------- -/** This post processing step removes bones nearly losslessly or according to -* a configured threshold. In order to remove the bone, the primitives affected by -* the bone are split from the mesh. The split off (new) mesh is boneless. At any -* point in time, bones without affect upon a given mesh are to be removed. -*/ -class DeboneProcess : public BaseProcess { -public: - DeboneProcess(); - ~DeboneProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - -protected: - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Counts bones total/removable in a given mesh. - * @param pMesh The mesh to process. - */ - bool ConsiderMesh( const aiMesh* pMesh); - - /// Splits the given mesh by bone count. - /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. - /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary. - void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const; - - /// Recursively updates the node's mesh list to account for the changed mesh list - void UpdateNode(aiNode* pNode) const; - - // ------------------------------------------------------------------- - // Apply transformation to a mesh - void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const; - -public: - /** Number of bones present in the scene. */ - unsigned int mNumBones; - unsigned int mNumBonesCanDoWithout; - - float mThreshold; - bool mAllOrNone; - - /// Per mesh index: Array of indices of the new submeshes. - std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices; -}; - -} // end of namespace Assimp - -#endif // AI_DEBONEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp deleted file mode 100644 index b11615bb82c3..000000000000 --- a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to drop face -* normals for all imported faces. -*/ - - -#include "DropFaceNormalsProcess.h" -#include -#include -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -DropFaceNormalsProcess::DropFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DropFaceNormalsProcess::~DropFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_DropNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DropFaceNormalsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]); - } - if (bHas) { - ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. " - "Face normals have been removed"); - } else { - ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. " - "No normals were present"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* pMesh) { - if (NULL == pMesh->mNormals) { - return false; - } - - delete[] pMesh->mNormals; - pMesh->mNormals = nullptr; - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h deleted file mode 100644 index c710c5a5ee41..000000000000 --- a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -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 Defines a post processing step to compute face normals for all loaded faces*/ -#ifndef AI_DROPFACENORMALPROCESS_H_INC -#define AI_DROPFACENORMALPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The DropFaceNormalsProcess computes face normals for all faces of all meshes -*/ -class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { -public: - DropFaceNormalsProcess(); - ~DropFaceNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - -private: - bool DropMeshFaceNormals(aiMesh* pcMesh); -}; - -} // end of namespace Assimp - -#endif // !!AI_DROPFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp b/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp deleted file mode 100644 index 739382a057ca..000000000000 --- a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#include "EmbedTexturesProcess.h" -#include -#include "ProcessHelper.h" - -#include - -using namespace Assimp; - -EmbedTexturesProcess::EmbedTexturesProcess() -: BaseProcess() { -} - -EmbedTexturesProcess::~EmbedTexturesProcess() { -} - -bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { - return (pFlags & aiProcess_EmbedTextures) != 0; -} - -void EmbedTexturesProcess::SetupProperties(const Importer* pImp) { - mRootPath = pImp->GetPropertyString("sourceFilePath"); - mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u); -} - -void EmbedTexturesProcess::Execute(aiScene* pScene) { - if (pScene == nullptr || pScene->mRootNode == nullptr) return; - - aiString path; - - uint32_t embeddedTexturesCount = 0u; - - for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) { - auto material = pScene->mMaterials[matId]; - - for (auto ttId = 1u; ttId < AI_TEXTURE_TYPE_MAX; ++ttId) { - auto tt = static_cast(ttId); - auto texturesCount = material->GetTextureCount(tt); - - for (auto texId = 0u; texId < texturesCount; ++texId) { - material->GetTexture(tt, texId, &path); - if (path.data[0] == '*') continue; // Already embedded - - // Indeed embed - if (addTexture(pScene, path.data)) { - auto embeddedTextureId = pScene->mNumTextures - 1u; - ::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId); - material->AddProperty(&path, AI_MATKEY_TEXTURE(tt, texId)); - embeddedTexturesCount++; - } - } - } - } - - ASSIMP_LOG_INFO_F("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." ); -} - -bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { - std::streampos imageSize = 0; - std::string imagePath = path; - - // Test path directly - std::ifstream file(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - ASSIMP_LOG_WARN_F("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder."); - - // Test path in root path - imagePath = mRootPath + path; - file.open(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - // Test path basename in root path - imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); - file.open(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - ASSIMP_LOG_ERROR_F("EmbedTexturesProcess: Unable to embed texture: ", path, "."); - return false; - } - } - } - - aiTexel* imageContent = new aiTexel[ 1ul + static_cast( imageSize ) / sizeof(aiTexel)]; - file.seekg(0, std::ios::beg); - file.read(reinterpret_cast(imageContent), imageSize); - - // Enlarging the textures table - unsigned int textureId = pScene->mNumTextures++; - auto oldTextures = pScene->mTextures; - pScene->mTextures = new aiTexture*[pScene->mNumTextures]; - ::memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u)); - - // Add the new texture - auto pTexture = new aiTexture; - pTexture->mHeight = 0; // Means that this is still compressed - pTexture->mWidth = static_cast(imageSize); - pTexture->pcData = imageContent; - - auto extension = path.substr(path.find_last_of('.') + 1u); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if (extension == "jpeg") { - extension = "jpg"; - } - - size_t len = extension.size(); - if (len > HINTMAXTEXTURELEN -1 ) { - len = HINTMAXTEXTURELEN - 1; - } - ::strncpy(pTexture->achFormatHint, extension.c_str(), len); - pScene->mTextures[textureId] = pTexture; - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h b/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h deleted file mode 100644 index 3c4b2eab4e9d..000000000000 --- a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#pragma once - -#include "Common/BaseProcess.h" - -#include - -struct aiNode; - -namespace Assimp { - -/** - * Force embedding of textures (using the path = "*1" convention). - * If a texture's file does not exist at the specified path - * (due, for instance, to an absolute path generated on another system), - * it will check if a file with the same name exists at the root folder - * of the imported model. And if so, it uses that. - */ -class ASSIMP_API EmbedTexturesProcess : public BaseProcess { -public: - /// The default class constructor. - EmbedTexturesProcess(); - - /// The class destructor. - virtual ~EmbedTexturesProcess(); - - /// Overwritten, @see BaseProcess - virtual bool IsActive(unsigned int pFlags) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties(const Importer* pImp); - - /// Overwritten, @see BaseProcess - virtual void Execute(aiScene* pScene); - -private: - // Resolve the path and add the file content to the scene as a texture. - bool addTexture(aiScene* pScene, std::string path) const; - -private: - std::string mRootPath; -}; - -} // namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp b/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp deleted file mode 100644 index 50fac46dbabb..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 FindDegenerates.cpp - * @brief Implementation of the FindDegenerates post-process step. -*/ - - - -// internal headers -#include "ProcessHelper.h" -#include "FindDegenerates.h" -#include - -using namespace Assimp; - -//remove mesh at position 'index' from the scene -static void removeMesh(aiScene* pScene, unsigned const index); -//correct node indices to meshes and remove references to deleted mesh -static void updateSceneGraph(aiNode* pNode, unsigned const index); - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindDegeneratesProcess::FindDegeneratesProcess() -: mConfigRemoveDegenerates( false ) -, mConfigCheckAreaOfTriangle( false ){ - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindDegeneratesProcess::~FindDegeneratesProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { - return 0 != (pFlags & aiProcess_FindDegenerates); -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void FindDegeneratesProcess::SetupProperties(const Importer* pImp) { - // Get the current value of AI_CONFIG_PP_FD_REMOVE - mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); - mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) ); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindDegeneratesProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - //Do not process point cloud, ExecuteOnMesh works only with faces data - if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) { - removeMesh(pScene, i); - --i; //the current i is removed, do not skip the next one - } - } - ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished"); -} - -static void removeMesh(aiScene* pScene, unsigned const index) { - //we start at index and copy the pointers one position forward - //save the mesh pointer to delete it later - auto delete_me = pScene->mMeshes[index]; - for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) { - pScene->mMeshes[i] = pScene->mMeshes[i+1]; - } - pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr; - --(pScene->mNumMeshes); - delete delete_me; - - //removing a mesh also requires updating all references to it in the scene graph - updateSceneGraph(pScene->mRootNode, index); -} - -static void updateSceneGraph(aiNode* pNode, unsigned const index) { - for (unsigned i = 0; i < pNode->mNumMeshes; ++i) { - if (pNode->mMeshes[i] > index) { - --(pNode->mMeshes[i]); - continue; - } - if (pNode->mMeshes[i] == index) { - for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) { - pNode->mMeshes[j] = pNode->mMeshes[j+1]; - } - --(pNode->mNumMeshes); - --i; - continue; - } - } - //recurse to all children - for (unsigned i = 0; i < pNode->mNumChildren; ++i) { - updateSceneGraph(pNode->mChildren[i], index); - } -} - -static ai_real heron( ai_real a, ai_real b, ai_real c ) { - ai_real s = (a + b + c) / 2; - ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 ); - return area; -} - -static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) { - const ai_real lx = ( vB.x - vA.x ); - const ai_real ly = ( vB.y - vA.y ); - const ai_real lz = ( vB.z - vA.z ); - ai_real a = lx*lx + ly*ly + lz*lz; - ai_real d = pow( a, (ai_real)0.5 ); - - return d; -} - -static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) { - ai_real area = 0; - - aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] ); - aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); - aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] ); - - ai_real a( distance3D( vA, vB ) ); - ai_real b( distance3D( vB, vC ) ); - ai_real c( distance3D( vC, vA ) ); - area = heron( a, b, c ); - - return area; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported mesh -bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { - mesh->mPrimitiveTypes = 0; - - std::vector remove_me; - if (mConfigRemoveDegenerates) { - remove_me.resize( mesh->mNumFaces, false ); - } - - unsigned int deg = 0, limit; - for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) { - aiFace& face = mesh->mFaces[a]; - bool first = true; - - // check whether the face contains degenerated entries - for (unsigned int i = 0; i < face.mNumIndices; ++i) { - // Polygons with more than 4 points are allowed to have double points, that is - // simulating polygons with holes just with concave polygons. However, - // double points may not come directly after another. - limit = face.mNumIndices; - if (face.mNumIndices > 4) { - limit = std::min( limit, i+2 ); - } - - for (unsigned int t = i+1; t < limit; ++t) { - if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) { - // we have found a matching vertex position - // remove the corresponding index from the array - --face.mNumIndices; - --limit; - for (unsigned int m = t; m < face.mNumIndices; ++m) { - face.mIndices[ m ] = face.mIndices[ m+1 ]; - } - --t; - - // NOTE: we set the removed vertex index to an unique value - // to make sure the developer gets notified when his - // application attempts to access this data. - face.mIndices[ face.mNumIndices ] = 0xdeadbeef; - - if(first) { - ++deg; - first = false; - } - - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; - goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! - } - } - } - - if ( mConfigCheckAreaOfTriangle ) { - if ( face.mNumIndices == 3 ) { - ai_real area = calculateAreaOfTriangle( face, mesh ); - if ( area < 1e-6 ) { - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; - ++deg; - goto evil_jump_outside; - } - - // todo: check for index which is corrupt. - } - } - } - } - - // We need to update the primitive flags array of the mesh. - switch (face.mNumIndices) - { - case 1u: - mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2u: - mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3u: - mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; -evil_jump_outside: - continue; - } - - // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import - if (mConfigRemoveDegenerates && deg) { - unsigned int n = 0; - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) - { - aiFace& face_src = mesh->mFaces[a]; - if (!remove_me[a]) { - aiFace& face_dest = mesh->mFaces[n++]; - - // Do a manual copy, keep the index array - face_dest.mNumIndices = face_src.mNumIndices; - face_dest.mIndices = face_src.mIndices; - - if (&face_src != &face_dest) { - // clear source - face_src.mNumIndices = 0; - face_src.mIndices = nullptr; - } - } - else { - // Otherwise delete it if we don't need this face - delete[] face_src.mIndices; - face_src.mIndices = nullptr; - face_src.mNumIndices = 0; - } - } - // Just leave the rest of the array unreferenced, we don't care for now - mesh->mNumFaces = n; - if (!mesh->mNumFaces) { - //The whole mesh consists of degenerated faces - //signal upward, that this mesh should be deleted. - ASSIMP_LOG_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives"); - return true; - } - } - - if (deg && !DefaultLogger::isNullLogger()) { - ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives"); - } - return false; -} diff --git a/thirdparty/assimp/code/PostProcessing/FindDegenerates.h b/thirdparty/assimp/code/PostProcessing/FindDegenerates.h deleted file mode 100644 index 7a15e77cf137..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindDegenerates.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -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 Defines a post processing step to search all meshes for - degenerated faces */ -#ifndef AI_FINDDEGENERATESPROCESS_H_INC -#define AI_FINDDEGENERATESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include - -class FindDegeneratesProcessTest; -namespace Assimp { - - -// --------------------------------------------------------------------------- -/** FindDegeneratesProcess: Searches a mesh for degenerated triangles. -*/ -class ASSIMP_API FindDegeneratesProcess : public BaseProcess { -public: - FindDegeneratesProcess(); - ~FindDegeneratesProcess(); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - // Execute step on a given mesh - ///@returns true if the current mesh should be deleted, false otherwise - bool ExecuteOnMesh( aiMesh* mesh); - - // ------------------------------------------------------------------- - /// @brief Enable the instant removal of degenerated primitives - /// @param enabled true for enabled. - void EnableInstantRemoval(bool enabled); - - // ------------------------------------------------------------------- - /// @brief Check whether instant removal is currently enabled - /// @return The instant removal state. - bool IsInstantRemoval() const; - - // ------------------------------------------------------------------- - /// @brief Enable the area check for triangles. - /// @param enabled true for enabled. - void EnableAreaCheck( bool enabled ); - - // ------------------------------------------------------------------- - /// @brief Check whether the area check is enabled. - /// @return The area check state. - bool isAreaCheckEnabled() const; - -private: - //! Configuration option: remove degenerates faces immediately - bool mConfigRemoveDegenerates; - //! Configuration option: check for area - bool mConfigCheckAreaOfTriangle; -}; - -inline -void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) { - mConfigRemoveDegenerates = enabled; -} - -inline -bool FindDegeneratesProcess::IsInstantRemoval() const { - return mConfigRemoveDegenerates; -} - -inline -void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) { - mConfigCheckAreaOfTriangle = enabled; -} - -inline -bool FindDegeneratesProcess::isAreaCheckEnabled() const { - return mConfigCheckAreaOfTriangle; -} - -} // Namespace Assimp - -#endif // !! AI_FINDDEGENERATESPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp b/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp deleted file mode 100644 index 64907458a14f..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 FindInstancesProcess.cpp - * @brief Implementation of the aiProcess_FindInstances postprocessing step -*/ - - -#include "FindInstancesProcess.h" -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindInstancesProcess::FindInstancesProcess() -: configSpeedFlag (false) -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInstancesProcess::~FindInstancesProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindInstancesProcess::IsActive( unsigned int pFlags) const -{ - // FindInstances makes absolutely no sense together with PreTransformVertices - // fixme: spawn error message somewhere else? - return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices); -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the step -void FindInstancesProcess::SetupProperties(const Importer* pImp) -{ - // AI_CONFIG_FAVOUR_SPEED - configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); -} - -// ------------------------------------------------------------------------------------------------ -// Compare the bones of two meshes -bool CompareBones(const aiMesh* orig, const aiMesh* inst) -{ - for (unsigned int i = 0; i < orig->mNumBones;++i) { - aiBone* aha = orig->mBones[i]; - aiBone* oha = inst->mBones[i]; - - if (aha->mNumWeights != oha->mNumWeights || - aha->mOffsetMatrix != oha->mOffsetMatrix) { - return false; - } - - // compare weight per weight --- - for (unsigned int n = 0; n < aha->mNumWeights;++n) { - if (aha->mWeights[n].mVertexId != oha->mWeights[n].mVertexId || - (aha->mWeights[n].mWeight - oha->mWeights[n].mWeight) < 10e-3f) { - return false; - } - } - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Update mesh indices in the node graph -void UpdateMeshIndices(aiNode* node, unsigned int* lookup) -{ - for (unsigned int n = 0; n < node->mNumMeshes;++n) - node->mMeshes[n] = lookup[node->mMeshes[n]]; - - for (unsigned int n = 0; n < node->mNumChildren;++n) - UpdateMeshIndices(node->mChildren[n],lookup); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindInstancesProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FindInstancesProcess begin"); - if (pScene->mNumMeshes) { - - // use a pseudo hash for all meshes in the scene to quickly find - // the ones which are possibly equal. This step is executed early - // in the pipeline, so we could, depending on the file format, - // have several thousand small meshes. That's too much for a brute - // everyone-against-everyone check involving up to 10 comparisons - // each. - std::unique_ptr hashes (new uint64_t[pScene->mNumMeshes]); - std::unique_ptr remapping (new unsigned int[pScene->mNumMeshes]); - - unsigned int numMeshesOut = 0; - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - - aiMesh* inst = pScene->mMeshes[i]; - hashes[i] = GetMeshHash(inst); - - // Find an appropriate epsilon - // to compare position differences against - float epsilon = ComputePositionEpsilon(inst); - epsilon *= epsilon; - - for (int a = i-1; a >= 0; --a) { - if (hashes[i] == hashes[a]) - { - aiMesh* orig = pScene->mMeshes[a]; - if (!orig) - continue; - - // check for hash collision .. we needn't check - // the vertex format, it *must* match due to the - // (brilliant) construction of the hash - if (orig->mNumBones != inst->mNumBones || - orig->mNumFaces != inst->mNumFaces || - orig->mNumVertices != inst->mNumVertices || - orig->mMaterialIndex != inst->mMaterialIndex || - orig->mPrimitiveTypes != inst->mPrimitiveTypes) - continue; - - // up to now the meshes are equal. Now compare vertex positions, normals, - // tangents and bitangents using this epsilon. - if (orig->HasPositions()) { - if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon)) - continue; - } - if (orig->HasNormals()) { - if(!CompareArrays(orig->mNormals,inst->mNormals,orig->mNumVertices,epsilon)) - continue; - } - if (orig->HasTangentsAndBitangents()) { - if (!CompareArrays(orig->mTangents,inst->mTangents,orig->mNumVertices,epsilon) || - !CompareArrays(orig->mBitangents,inst->mBitangents,orig->mNumVertices,epsilon)) - continue; - } - - // use a constant epsilon for colors and UV coordinates - static const float uvEpsilon = 10e-4f; - { - unsigned int j, end = orig->GetNumUVChannels(); - for(j = 0; j < end; ++j) { - if (!orig->mTextureCoords[j]) { - continue; - } - if(!CompareArrays(orig->mTextureCoords[j],inst->mTextureCoords[j],orig->mNumVertices,uvEpsilon)) { - break; - } - } - if (j != end) { - continue; - } - } - { - unsigned int j, end = orig->GetNumColorChannels(); - for(j = 0; j < end; ++j) { - if (!orig->mColors[j]) { - continue; - } - if(!CompareArrays(orig->mColors[j],inst->mColors[j],orig->mNumVertices,uvEpsilon)) { - break; - } - } - if (j != end) { - continue; - } - } - - // These two checks are actually quite expensive and almost *never* required. - // Almost. That's why they're still here. But there's no reason to do them - // in speed-targeted imports. - if (!configSpeedFlag) { - - // It seems to be strange, but we really need to check whether the - // bones are identical too. Although it's extremely unprobable - // that they're not if control reaches here, we need to deal - // with unprobable cases, too. It could still be that there are - // equal shapes which are deformed differently. - if (!CompareBones(orig,inst)) - continue; - - // For completeness ... compare even the index buffers for equality - // face order & winding order doesn't care. Input data is in verbose format. - std::unique_ptr ftbl_orig(new unsigned int[orig->mNumVertices]); - std::unique_ptr ftbl_inst(new unsigned int[orig->mNumVertices]); - - for (unsigned int tt = 0; tt < orig->mNumFaces;++tt) { - aiFace& f = orig->mFaces[tt]; - for (unsigned int nn = 0; nn < f.mNumIndices;++nn) - ftbl_orig[f.mIndices[nn]] = tt; - - aiFace& f2 = inst->mFaces[tt]; - for (unsigned int nn = 0; nn < f2.mNumIndices;++nn) - ftbl_inst[f2.mIndices[nn]] = tt; - } - if (0 != ::memcmp(ftbl_inst.get(),ftbl_orig.get(),orig->mNumVertices*sizeof(unsigned int))) - continue; - } - - // We're still here. Or in other words: 'inst' is an instance of 'orig'. - // Place a marker in our list that we can easily update mesh indices. - remapping[i] = remapping[a]; - - // Delete the instanced mesh, we don't need it anymore - delete inst; - pScene->mMeshes[i] = NULL; - break; - } - } - - // If we didn't find a match for the current mesh: keep it - if (pScene->mMeshes[i]) { - remapping[i] = numMeshesOut++; - } - } - ai_assert(0 != numMeshesOut); - if (numMeshesOut != pScene->mNumMeshes) { - - // Collapse the meshes array by removing all NULL entries - for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) { - if (pScene->mMeshes[i]) - pScene->mMeshes[real++] = pScene->mMeshes[i]; - } - - // And update the node graph with our nice lookup table - UpdateMeshIndices(pScene->mRootNode,remapping.get()); - - // write to log - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F( "FindInstancesProcess finished. Found ", (pScene->mNumMeshes - numMeshesOut), " instances" ); - } - pScene->mNumMeshes = numMeshesOut; - } else { - ASSIMP_LOG_DEBUG("FindInstancesProcess finished. No instanced meshes found"); - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h b/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h deleted file mode 100644 index 64b838d7cc4f..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -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 FindInstancesProcess.h - * @brief Declares the aiProcess_FindInstances post-process step - */ -#ifndef AI_FINDINSTANCES_H_INC -#define AI_FINDINSTANCES_H_INC - -#include "Common/BaseProcess.h" -#include "PostProcessing/ProcessHelper.h" - -class FindInstancesProcessTest; -namespace Assimp { - -// ------------------------------------------------------------------------------- -/** @brief Get a pseudo(!)-hash representing a mesh. - * - * The hash is built from number of vertices, faces, primitive types, - * .... but *not* from the real mesh data. The funcction is not a perfect hash. - * @param in Input mesh - * @return Hash. - */ -inline -uint64_t GetMeshHash(aiMesh* in) { - ai_assert(nullptr != in); - - // ... get an unique value representing the vertex format of the mesh - const unsigned int fhash = GetMeshVFormatUnique(in); - - // and bake it with number of vertices/faces/bones/matidx/ptypes - return ((uint64_t)fhash << 32u) | (( - (in->mNumBones << 16u) ^ (in->mNumVertices) ^ - (in->mNumFaces<<4u) ^ (in->mMaterialIndex<<15) ^ - (in->mPrimitiveTypes<<28)) & 0xffffffff ); -} - -// ------------------------------------------------------------------------------- -/** @brief Perform a component-wise comparison of two arrays - * - * @param first First array - * @param second Second array - * @param size Size of both arrays - * @param e Epsilon - * @return true if the arrays are identical - */ -inline -bool CompareArrays(const aiVector3D* first, const aiVector3D* second, - unsigned int size, float e) { - for (const aiVector3D* end = first+size; first != end; ++first,++second) { - if ( (*first - *second).SquareLength() >= e) - return false; - } - return true; -} - -// and the same for colors ... -inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second, - unsigned int size, float e) -{ - for (const aiColor4D* end = first+size; first != end; ++first,++second) { - if ( GetColorDifference(*first,*second) >= e) - return false; - } - return true; -} - -// --------------------------------------------------------------------------- -/** @brief A post-processing steps to search for instanced meshes -*/ -class FindInstancesProcess : public BaseProcess -{ -public: - - FindInstancesProcess(); - ~FindInstancesProcess(); - -public: - // ------------------------------------------------------------------- - // Check whether step is active in given flags combination - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup properties prior to executing the process - void SetupProperties(const Importer* pImp); - -private: - - bool configSpeedFlag; - -}; // ! end class FindInstancesProcess -} // ! end namespace Assimp - -#endif // !! AI_FINDINSTANCES_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp b/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp deleted file mode 100644 index 016884c6e766..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Defines a post processing step to search an importer's output - for data that is obviously invalid */ - - - -#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS - -// internal headers -#include "FindInvalidDataProcess.h" -#include "ProcessHelper.h" - -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindInvalidDataProcess::FindInvalidDataProcess() -: configEpsilon(0.0) -, mIgnoreTexCoods( false ){ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInvalidDataProcess::~FindInvalidDataProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const { - return 0 != (pFlags & aiProcess_FindInvalidData); -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void FindInvalidDataProcess::SetupProperties(const Importer* pImp) { - // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY - configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f)); - mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false); -} - -// ------------------------------------------------------------------------------------------------ -// Update mesh references in the node graph -void UpdateMeshReferences(aiNode* node, const std::vector& meshMapping) { - if (node->mNumMeshes) { - unsigned int out = 0; - for (unsigned int a = 0; a < node->mNumMeshes;++a) { - - unsigned int ref = node->mMeshes[a]; - if (UINT_MAX != (ref = meshMapping[ref])) { - node->mMeshes[out++] = ref; - } - } - // just let the members that are unused, that's much cheaper - // than a full array realloc'n'copy party ... - if(!(node->mNumMeshes = out)) { - - delete[] node->mMeshes; - node->mMeshes = NULL; - } - } - // recursively update all children - for (unsigned int i = 0; i < node->mNumChildren;++i) { - UpdateMeshReferences(node->mChildren[i],meshMapping); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindInvalidDataProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin"); - - bool out = false; - std::vector meshMapping(pScene->mNumMeshes); - unsigned int real = 0; - - // Process meshes - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - - int result; - if ((result = ProcessMesh( pScene->mMeshes[a]))) { - out = true; - - if (2 == result) { - // remove this mesh - delete pScene->mMeshes[a]; - AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]); - - meshMapping[a] = UINT_MAX; - continue; - } - } - pScene->mMeshes[real] = pScene->mMeshes[a]; - meshMapping[a] = real++; - } - - // Process animations - for (unsigned int a = 0; a < pScene->mNumAnimations;++a) { - ProcessAnimation( pScene->mAnimations[a]); - } - - - if (out) { - if ( real != pScene->mNumMeshes) { - if (!real) { - throw DeadlyImportError("No meshes remaining"); - } - - // we need to remove some meshes. - // therefore we'll also need to remove all references - // to them from the scenegraph - UpdateMeshReferences(pScene->mRootNode,meshMapping); - pScene->mNumMeshes = real; - } - - ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ..."); - } else { - ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK."); - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline -const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/, - const std::vector& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/) -{ - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -template <> -inline -const char* ValidateArrayContents(const aiVector3D* arr, unsigned int size, - const std::vector& dirtyMask, bool mayBeIdentical , bool mayBeZero ) { - bool b = false; - unsigned int cnt = 0; - for (unsigned int i = 0; i < size;++i) { - - if (dirtyMask.size() && dirtyMask[i]) { - continue; - } - ++cnt; - - const aiVector3D& v = arr[i]; - if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) { - return "INF/NAN was found in a vector component"; - } - if (!mayBeZero && !v.x && !v.y && !v.z ) { - return "Found zero-length vector"; - } - if (i && v != arr[i-1])b = true; - } - if (cnt > 1 && !b && !mayBeIdentical) { - return "All vectors are identical"; - } - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -template -inline -bool ProcessArray(T*& in, unsigned int num,const char* name, - const std::vector& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) { - const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero); - if (err) { - ASSIMP_LOG_ERROR_F( "FindInvalidDataProcess fails on mesh ", name, ": ", err); - delete[] in; - in = NULL; - return true; - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -template -AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, ai_real epsilon); - -// ------------------------------------------------------------------------------------------------ -AI_FORCE_INLINE bool EpsilonCompare(ai_real n, ai_real s, ai_real epsilon) { - return std::fabs(n-s)>epsilon; -} - -// ------------------------------------------------------------------------------------------------ -template <> -bool EpsilonCompare(const aiVectorKey& n, const aiVectorKey& s, ai_real epsilon) { - return - EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && - EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && - EpsilonCompare(n.mValue.z,s.mValue.z,epsilon); -} - -// ------------------------------------------------------------------------------------------------ -template <> -bool EpsilonCompare(const aiQuatKey& n, const aiQuatKey& s, ai_real epsilon) { - return - EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && - EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && - EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) && - EpsilonCompare(n.mValue.w,s.mValue.w,epsilon); -} - -// ------------------------------------------------------------------------------------------------ -template -inline -bool AllIdentical(T* in, unsigned int num, ai_real epsilon) { - if (num <= 1) { - return true; - } - - if (fabs(epsilon) > 0.f) { - for (unsigned int i = 0; i < num-1;++i) { - if (!EpsilonCompare(in[i],in[i+1],epsilon)) { - return false; - } - } - } else { - for (unsigned int i = 0; i < num-1;++i) { - if (in[i] != in[i+1]) { - return false; - } - } - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Search an animation for invalid content -void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) { - // Process all animation channels - for ( unsigned int a = 0; a < anim->mNumChannels; ++a ) { - ProcessAnimationChannel( anim->mChannels[a]); - } -} - -// ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) { - ai_assert( nullptr != anim ); - if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) { - ai_assert_entry(); - return; - } - - // Check whether all values in a tracks are identical - in this case - // we can remove al keys except one. - // POSITIONS - int i = 0; - if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) { - aiVectorKey v = anim->mPositionKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mPositionKeys; - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1]; - anim->mPositionKeys[0] = v; - i = 1; - } - - // ROTATIONS - if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) { - aiQuatKey v = anim->mRotationKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mRotationKeys; - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1]; - anim->mRotationKeys[0] = v; - i = 1; - } - - // SCALINGS - if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) { - aiVectorKey v = anim->mScalingKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mScalingKeys; - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1]; - anim->mScalingKeys[0] = v; - i = 1; - } - if ( 1 == i ) { - ASSIMP_LOG_WARN("Simplified dummy tracks with just one key"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Search a mesh for invalid contents -int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh) -{ - bool ret = false; - std::vector dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0); - - // Ignore elements that are not referenced by vertices. - // (they are, for example, caused by the FindDegenerates step) - for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) { - const aiFace& f = pMesh->mFaces[m]; - - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - dirtyMask[f.mIndices[i]] = false; - } - } - - // Process vertex positions - if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) { - ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions"); - - return 2; - } - - // process texture coordinates - if (!mIgnoreTexCoods) { - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) { - if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) { - pMesh->mNumUVComponents[i] = 0; - - // delete all subsequent texture coordinate sets. - for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - delete[] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = NULL; - pMesh->mNumUVComponents[a] = 0; - } - - ret = true; - } - } - } - - // -- we don't validate vertex colors, it's difficult to say whether - // they are invalid or not. - - // Normals and tangents are undefined for point and line faces. - if (pMesh->mNormals || pMesh->mTangents) { - - if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes || - aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) - { - if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes || - aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) - { - // We need to update the lookup-table - for (unsigned int m = 0; m < pMesh->mNumFaces;++m) { - const aiFace& f = pMesh->mFaces[ m ]; - - if (f.mNumIndices < 3) { - dirtyMask[f.mIndices[0]] = true; - if (f.mNumIndices == 2) { - dirtyMask[f.mIndices[1]] = true; - } - } - } - } - // Normals, tangents and bitangents are undefined for - // the whole mesh (and should not even be there) - else { - return ret; - } - } - - // Process mesh normals - if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices, - "normals",dirtyMask,true,false)) - ret = true; - - // Process mesh tangents - if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) { - delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; - ret = true; - } - - // Process mesh bitangents - if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) { - delete[] pMesh->mTangents; pMesh->mTangents = NULL; - ret = true; - } - } - return ret ? 1 : 0; -} - -#endif // !! ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h b/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h deleted file mode 100644 index ce7375f34fd8..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -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 Defines a post processing step to search an importer's output - * for data that is obviously invalid - */ -#ifndef AI_FINDINVALIDDATA_H_INC -#define AI_FINDINVALIDDATA_H_INC - -#include "Common/BaseProcess.h" - -#include -#include - -struct aiMesh; - -class FindInvalidDataProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The FindInvalidData post-processing step. It searches the mesh data - * for parts that are obviously invalid and removes them. - * - * Originally this was a workaround for some models written by Blender - * which have zero normal vectors. */ -class ASSIMP_API FindInvalidDataProcess : public BaseProcess { -public: - FindInvalidDataProcess(); - ~FindInvalidDataProcess(); - - // ------------------------------------------------------------------- - // - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - // Run the step - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given mesh - * @param pMesh The mesh to process. - * @return 0 - nothing, 1 - removed sth, 2 - please delete me */ - int ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given animation - * @param anim The animation to process. */ - void ProcessAnimation (aiAnimation* anim); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given anim channel - * @param anim The animation channel to process.*/ - void ProcessAnimationChannel (aiNodeAnim* anim); - -private: - ai_real configEpsilon; - bool mIgnoreTexCoods; -}; - -} // end of namespace Assimp - -#endif // AI_AI_FINDINVALIDDATA_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp b/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp deleted file mode 100644 index bbbe6899b46b..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to invert - * all normals in meshes with infacing normals. - */ - -// internal headers -#include "FixNormalsStep.h" -#include -#include -#include -#include -#include - - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FixInfacingNormalsProcess::FixInfacingNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FixInfacingNormalsProcess::~FixInfacingNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_FixInfacingNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FixInfacingNormalsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin"); - - bool bHas( false ); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - if (ProcessMesh(pScene->mMeshes[a], a)) { - bHas = true; - } - } - - if (bHas) { - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. Found issues."); - } else { - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. No changes to the scene."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the step to the mesh -bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index) -{ - ai_assert(nullptr != pcMesh); - - // Nothing to do if there are no model normals - if (!pcMesh->HasNormals()) { - return false; - } - - // Compute the bounding box of both the model vertices + normals and - // the unmodified model vertices. Then check whether the first BB - // is smaller than the second. In this case we can assume that the - // normals need to be flipped, although there are a few special cases .. - // convex, concave, planar models ... - - aiVector3D vMin0 (1e10f,1e10f,1e10f); - aiVector3D vMin1 (1e10f,1e10f,1e10f); - aiVector3D vMax0 (-1e10f,-1e10f,-1e10f); - aiVector3D vMax1 (-1e10f,-1e10f,-1e10f); - - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { - vMin1.x = std::min(vMin1.x,pcMesh->mVertices[i].x); - vMin1.y = std::min(vMin1.y,pcMesh->mVertices[i].y); - vMin1.z = std::min(vMin1.z,pcMesh->mVertices[i].z); - - vMax1.x = std::max(vMax1.x,pcMesh->mVertices[i].x); - vMax1.y = std::max(vMax1.y,pcMesh->mVertices[i].y); - vMax1.z = std::max(vMax1.z,pcMesh->mVertices[i].z); - - const aiVector3D vWithNormal = pcMesh->mVertices[i] + pcMesh->mNormals[i]; - - vMin0.x = std::min(vMin0.x,vWithNormal.x); - vMin0.y = std::min(vMin0.y,vWithNormal.y); - vMin0.z = std::min(vMin0.z,vWithNormal.z); - - vMax0.x = std::max(vMax0.x,vWithNormal.x); - vMax0.y = std::max(vMax0.y,vWithNormal.y); - vMax0.z = std::max(vMax0.z,vWithNormal.z); - } - - const float fDelta0_x = (vMax0.x - vMin0.x); - const float fDelta0_y = (vMax0.y - vMin0.y); - const float fDelta0_z = (vMax0.z - vMin0.z); - - const float fDelta1_x = (vMax1.x - vMin1.x); - const float fDelta1_y = (vMax1.y - vMin1.y); - const float fDelta1_z = (vMax1.z - vMin1.z); - - // Check whether the boxes are overlapping - if ((fDelta0_x > 0.0f) != (fDelta1_x > 0.0f))return false; - if ((fDelta0_y > 0.0f) != (fDelta1_y > 0.0f))return false; - if ((fDelta0_z > 0.0f) != (fDelta1_z > 0.0f))return false; - - // Check whether this is a planar surface - const float fDelta1_yz = fDelta1_y * fDelta1_z; - - if (fDelta1_x < 0.05f * std::sqrt( fDelta1_yz ))return false; - if (fDelta1_y < 0.05f * std::sqrt( fDelta1_z * fDelta1_x ))return false; - if (fDelta1_z < 0.05f * std::sqrt( fDelta1_y * fDelta1_x ))return false; - - // now compare the volumes of the bounding boxes - if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < std::fabs(fDelta1_x * fDelta1_yz)) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Mesh ", index, ": Normals are facing inwards (or the mesh is planar)", index); - } - - // Invert normals - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - pcMesh->mNormals[i] *= -1.0f; - - // ... and flip faces - for (unsigned int i = 0; i < pcMesh->mNumFaces;++i) - { - aiFace& face = pcMesh->mFaces[i]; - for( unsigned int b = 0; b < face.mNumIndices / 2; b++) - std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); - } - return true; - } - return false; -} diff --git a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h b/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h deleted file mode 100644 index f60ce596a498..000000000000 --- a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -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 Defines a post processing step to fix infacing normals */ -#ifndef AI_FIXNORMALSPROCESS_H_INC -#define AI_FIXNORMALSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The FixInfacingNormalsProcess tries to determine whether the normal - * vectors of an object are facing inwards. In this case they will be - * flipped. - */ -class FixInfacingNormalsProcess : public BaseProcess { -public: - FixInfacingNormalsProcess(); - ~FixInfacingNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Executes the step on the given mesh - * @param pMesh The mesh to process. - */ - bool ProcessMesh( aiMesh* pMesh, unsigned int index); -}; - -} // end of namespace Assimp - -#endif // AI_FIXNORMALSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp deleted file mode 100644 index c013454fc315..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#include "PostProcessing/GenBoundingBoxesProcess.h" - -#include -#include - -namespace Assimp { - -GenBoundingBoxesProcess::GenBoundingBoxesProcess() -: BaseProcess() { - -} - -GenBoundingBoxesProcess::~GenBoundingBoxesProcess() { - // empty -} - -bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const { - return 0 != ( pFlags & aiProcess_GenBoundingBoxes ); -} - -void checkMesh(aiMesh* mesh, aiVector3D& min, aiVector3D& max) { - ai_assert(nullptr != mesh); - - if (0 == mesh->mNumVertices) { - return; - } - - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - const aiVector3D &pos = mesh->mVertices[i]; - if (pos.x < min.x) { - min.x = pos.x; - } - if (pos.y < min.y) { - min.y = pos.y; - } - if (pos.z < min.z) { - min.z = pos.z; - } - - if (pos.x > max.x) { - max.x = pos.x; - } - if (pos.y > max.y) { - max.y = pos.y; - } - if (pos.z > max.z) { - max.z = pos.z; - } - } -} - -void GenBoundingBoxesProcess::Execute(aiScene* pScene) { - if (nullptr == pScene) { - return; - } - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - aiMesh* mesh = pScene->mMeshes[i]; - if (nullptr == mesh) { - continue; - } - - aiVector3D min(999999, 999999, 999999), max(-999999, -999999, -999999); - checkMesh(mesh, min, max); - mesh->mAABB.mMin = min; - mesh->mAABB.mMax = max; - } -} - -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h b/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h deleted file mode 100644 index 4b43c82a42e5..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h +++ /dev/null @@ -1,76 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Defines a post-processing step to generate Axis-aligned bounding - * volumes for all meshes. - */ - -#pragma once - -#ifndef AI_GENBOUNDINGBOXESPROCESS_H_INC -#define AI_GENBOUNDINGBOXESPROCESS_H_INC - -#ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#include "Common/BaseProcess.h" - -namespace Assimp { - -/** Post-processing process to find axis-aligned bounding volumes for amm meshes - * used in a scene - */ -class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess { -public: - /// The class constructor. - GenBoundingBoxesProcess(); - /// The class destructor. - ~GenBoundingBoxesProcess(); - /// Will return true, if aiProcess_GenBoundingBoxes is defined. - bool IsActive(unsigned int pFlags) const override; - /// The execution callback. - void Execute(aiScene* pScene) override; -}; - -} // Namespace Assimp - -#endif // #ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#endif // AI_GENBOUNDINGBOXESPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp deleted file mode 100644 index 028334dec79b..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to generate face -* normals for all imported faces. -*/ - - -#include "GenFaceNormalsProcess.h" -#include -#include -#include -#include -#include - - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -GenFaceNormalsProcess::GenFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenFaceNormalsProcess::~GenFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const { - force_ = (pFlags & aiProcess_ForceGenNormals) != 0; - return (pFlags & aiProcess_GenNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenFaceNormalsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("GenFaceNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if(this->GenMeshFaceNormals( pScene->mMeshes[a])) { - bHas = true; - } - } - if (bHas) { - ASSIMP_LOG_INFO("GenFaceNormalsProcess finished. " - "Face normals have been calculated"); - } else { - ASSIMP_LOG_DEBUG("GenFaceNormalsProcess finished. " - "Normals are already there"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh) -{ - if (NULL != pMesh->mNormals) { - if (force_) delete[] pMesh->mNormals; - else return false; - } - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) { - ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes"); - return false; - } - - // allocate an array to hold the output normals - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - const float qnan = get_qnan(); - - // iterate through all faces and compute per-face normals but store them per-vertex. - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) { - // either a point or a line -> no well-defined normal vector - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); - } - continue; - } - - const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; - const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; - const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; - const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); - - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = vNor; - } - } - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h deleted file mode 100644 index c641fd635392..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -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 Defines a post processing step to compute face normals for all loaded faces*/ -#ifndef AI_GENFACENORMALPROCESS_H_INC -#define AI_GENFACENORMALPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes face normals for all faces of all meshes -*/ -class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess -{ -public: - - GenFaceNormalsProcess(); - ~GenFaceNormalsProcess(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - -private: - bool GenMeshFaceNormals(aiMesh* pcMesh); - mutable bool force_ = false; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp deleted file mode 100644 index 3f6c2f86bd51..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to generate face -* normals for all imported faces. -*/ - - - -// internal headers -#include "GenVertexNormalsProcess.h" -#include "ProcessHelper.h" -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -GenVertexNormalsProcess::GenVertexNormalsProcess() -: configMaxAngle( AI_DEG_TO_RAD( 175.f ) ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenVertexNormalsProcess::~GenVertexNormalsProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const -{ - force_ = (pFlags & aiProcess_ForceGenNormals) != 0; - return (pFlags & aiProcess_GenSmoothNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenVertexNormalsProcess::SetupProperties(const Importer* pImp) -{ - // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property - configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,(ai_real)175.0); - configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle,(ai_real)175.0),(ai_real)0.0)); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenVertexNormalsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - if(GenMeshVertexNormals( pScene->mMeshes[a],a)) - bHas = true; - } - - if (bHas) { - ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. " - "Vertex normals have been calculated"); - } else { - ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. " - "Normals are already there"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex) -{ - if (NULL != pMesh->mNormals) { - if (force_) delete[] pMesh->mNormals; - else return false; - } - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) - { - ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes"); - return false; - } - - // Allocate the array to hold the output normals - const float qnan = std::numeric_limits::quiet_NaN(); - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - - // Compute per-face normals but store them per-vertex - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) - { - // either a point or a line -> no normal vector - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); - } - - continue; - } - - const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; - const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; - const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; - const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); - - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = vNor; - } - } - - // Set up a SpatialSort to quickly find all vertices close to a given position - // check whether we can reuse the SpatialSort of a previous step. - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - ai_real posEpsilon = ai_real( 1e-5 ); - if (shared) { - std::vector >* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) - { - std::pair& blubb = avf->operator [] (meshIndex); - vertexFinder = &blubb.first; - posEpsilon = blubb.second; - } - } - if (!vertexFinder) { - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - posEpsilon = ComputePositionEpsilon(pMesh); - } - std::vector verticesFound; - aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; - - if (configMaxAngle >= AI_DEG_TO_RAD( 175.f )) { - // There is no angle limit. Thus all vertices with positions close - // to each other will receive the same vertex normal. This allows us - // to optimize the whole algorithm a little bit ... - std::vector abHad(pMesh->mNumVertices,false); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (abHad[i]) { - continue; - } - - // Get all vertices that share this one ... - vertexFinder->FindPositions( pMesh->mVertices[i], posEpsilon, verticesFound); - - aiVector3D pcNor; - for (unsigned int a = 0; a < verticesFound.size(); ++a) { - const aiVector3D& v = pMesh->mNormals[verticesFound[a]]; - if (is_not_qnan(v.x))pcNor += v; - } - pcNor.NormalizeSafe(); - - // Write the smoothed normal back to all affected normals - for (unsigned int a = 0; a < verticesFound.size(); ++a) - { - unsigned int vidx = verticesFound[a]; - pcNew[vidx] = pcNor; - abHad[vidx] = true; - } - } - } - // Slower code path if a smooth angle is set. There are many ways to achieve - // the effect, this one is the most straightforward one. - else { - const ai_real fLimit = std::cos(configMaxAngle); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - // Get all vertices that share this one ... - vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound); - - aiVector3D vr = pMesh->mNormals[i]; - - aiVector3D pcNor; - for (unsigned int a = 0; a < verticesFound.size(); ++a) { - aiVector3D v = pMesh->mNormals[verticesFound[a]]; - - // Check whether the angle between the two normals is not too large. - // Skip the angle check on our own normal to avoid false negatives - // (v*v is not guaranteed to be 1.0 for all unit vectors v) - if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit))) - pcNor += v; - } - pcNew[i] = pcNor.NormalizeSafe(); - } - } - - delete[] pMesh->mNormals; - pMesh->mNormals = pcNew; - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h deleted file mode 100644 index 2ceee17e854a..000000000000 --- a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -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 Defines a post processing step to compute vertex normals - for all loaded vertizes */ -#ifndef AI_GENVERTEXNORMALPROCESS_H_INC -#define AI_GENVERTEXNORMALPROCESS_H_INC - -#include "Common/assbin_chunks.h" -#include "Common/BaseProcess.h" - -#include - -// Forward declarations -class GenNormalsTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes vertex normals for all vertices -*/ -class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { -public: - GenVertexNormalsProcess(); - ~GenVertexNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - - // setter for configMaxAngle - inline void SetMaxSmoothAngle(ai_real f) { - configMaxAngle =f; - } - - // ------------------------------------------------------------------- - /** Computes normals for a specific mesh - * @param pcMesh Mesh - * @param meshIndex Index of the mesh - * @return true if vertex normals have been computed - */ - bool GenMeshVertexNormals (aiMesh* pcMesh, unsigned int meshIndex); - -private: - /** Configuration option: maximum smoothing angle, in radians*/ - ai_real configMaxAngle; - mutable bool force_ = false; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENVERTEXNORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp b/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp deleted file mode 100644 index d0a016fa4230..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to improve the cache locality of a mesh. - *
- * The algorithm is roughly basing on this paper: - * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf - * .. although overdraw reduction isn't implemented yet ... - */ - -// internal headers -#include "PostProcessing/ImproveCacheLocality.h" -#include "Common/VertexTriangleAdjacency.h" - -#include -#include -#include -#include -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() -: mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_ImproveCacheLocality) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration -void ImproveCacheLocalityProcess::SetupProperties(const Importer* pImp) { - // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer - mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE,PP_ICL_PTCACHE_SIZE); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void ImproveCacheLocalityProcess::Execute( aiScene* pScene) { - if (!pScene->mNumMeshes) { - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes"); - return; - } - - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess begin"); - - float out = 0.f; - unsigned int numf = 0, numm = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ){ - const float res = ProcessMesh( pScene->mMeshes[a],a); - if (res) { - numf += pScene->mMeshes[a]->mNumFaces; - out += res; - ++numm; - } - } - if (!DefaultLogger::isNullLogger()) { - if (numf > 0) { - ASSIMP_LOG_INFO_F("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf); - } - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. "); - } -} - -// ------------------------------------------------------------------------------------------------ -// Improves the cache coherency of a specific mesh -ai_real ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) { - // TODO: rewrite this to use std::vector or boost::shared_array - ai_assert(nullptr != pMesh); - - // Check whether the input data is valid - // - there must be vertices and faces - // - all faces must be triangulated or we can't operate on them - if (!pMesh->HasFaces() || !pMesh->HasPositions()) - return static_cast(0.f); - - if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { - ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only"); - return static_cast(0.f); - } - - if(pMesh->mNumVertices <= mConfigCacheDepth) { - return static_cast(0.f); - } - - ai_real fACMR = 3.f; - const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces; - - // Input ACMR is for logging purposes only - if (!DefaultLogger::isNullLogger()) { - - unsigned int* piFIFOStack = new unsigned int[mConfigCacheDepth]; - memset(piFIFOStack,0xff,mConfigCacheDepth*sizeof(unsigned int)); - unsigned int* piCur = piFIFOStack; - const unsigned int* const piCurEnd = piFIFOStack + mConfigCacheDepth; - - // count the number of cache misses - unsigned int iCacheMisses = 0; - for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) { - for (unsigned int qq = 0; qq < 3;++qq) { - bool bInCache = false; - for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp) { - if (*pp == pcFace->mIndices[qq]) { - // the vertex is in cache - bInCache = true; - break; - } - } - if (!bInCache) { - ++iCacheMisses; - if (piCurEnd == piCur) { - piCur = piFIFOStack; - } - *piCur++ = pcFace->mIndices[qq]; - } - } - } - delete[] piFIFOStack; - fACMR = (ai_real) iCacheMisses / pMesh->mNumFaces; - if (3.0 == fACMR) { - char szBuff[128]; // should be sufficiently large in every case - - // the JoinIdenticalVertices process has not been executed on this - // mesh, otherwise this value would normally be at least minimally - // smaller than 3.0 ... - ai_snprintf(szBuff,128,"Mesh %u: Not suitable for vcache optimization",meshNum); - ASSIMP_LOG_WARN(szBuff); - return static_cast(0.f); - } - } - - // first we need to build a vertex-triangle adjacency list - VertexTriangleAdjacency adj(pMesh->mFaces,pMesh->mNumFaces, pMesh->mNumVertices,true); - - // build a list to store per-vertex caching time stamps - unsigned int* const piCachingStamps = new unsigned int[pMesh->mNumVertices]; - memset(piCachingStamps,0x0,pMesh->mNumVertices*sizeof(unsigned int)); - - // allocate an empty output index buffer. We store the output indices in one large array. - // Since the number of triangles won't change the input faces can be reused. This is how - // we save thousands of redundant mini allocations for aiFace::mIndices - const unsigned int iIdxCnt = pMesh->mNumFaces*3; - unsigned int* const piIBOutput = new unsigned int[iIdxCnt]; - unsigned int* piCSIter = piIBOutput; - - // allocate the flag array to hold the information - // whether a face has already been emitted or not - std::vector abEmitted(pMesh->mNumFaces,false); - - // dead-end vertex index stack - std::stack > sDeadEndVStack; - - // create a copy of the piNumTriPtr buffer - unsigned int* const piNumTriPtr = adj.mLiveTriangles; - const std::vector piNumTriPtrNoModify(piNumTriPtr, piNumTriPtr + pMesh->mNumVertices); - - // get the largest number of referenced triangles and allocate the "candidate buffer" - unsigned int iMaxRefTris = 0; { - const unsigned int* piCur = adj.mLiveTriangles; - const unsigned int* const piCurEnd = adj.mLiveTriangles+pMesh->mNumVertices; - for (;piCur != piCurEnd;++piCur) { - iMaxRefTris = std::max(iMaxRefTris,*piCur); - } - } - ai_assert(iMaxRefTris > 0); - unsigned int* piCandidates = new unsigned int[iMaxRefTris*3]; - unsigned int iCacheMisses = 0; - - // ................................................................................... - /** PSEUDOCODE for the algorithm - - A = Build-Adjacency(I) Vertex-triangle adjacency - L = Get-Triangle-Counts(A) Per-vertex live triangle counts - C = Zero(Vertex-Count(I)) Per-vertex caching time stamps - D = Empty-Stack() Dead-end vertex stack - E = False(Triangle-Count(I)) Per triangle emitted flag - O = Empty-Index-Buffer() Empty output buffer - f = 0 Arbitrary starting vertex - s = k+1, i = 1 Time stamp and cursor - while f >= 0 For all valid fanning vertices - N = Empty-Set() 1-ring of next candidates - for each Triangle t in Neighbors(A, f) - if !Emitted(E,t) - for each Vertex v in t - Append(O,v) Output vertex - Push(D,v) Add to dead-end stack - Insert(N,v) Register as candidate - L[v] = L[v]-1 Decrease live triangle count - if s-C[v] > k If not in cache - C[v] = s Set time stamp - s = s+1 Increment time stamp - E[t] = true Flag triangle as emitted - Select next fanning vertex - f = Get-Next-Vertex(I,i,k,N,C,s,L,D) - return O - */ - // ................................................................................... - - int ivdx = 0; - int ics = 1; - int iStampCnt = mConfigCacheDepth+1; - while (ivdx >= 0) { - - unsigned int icnt = piNumTriPtrNoModify[ivdx]; - unsigned int* piList = adj.GetAdjacentTriangles(ivdx); - unsigned int* piCurCandidate = piCandidates; - - // get all triangles in the neighborhood - for (unsigned int tri = 0; tri < icnt;++tri) { - - // if they have not yet been emitted, add them to the output IB - const unsigned int fidx = *piList++; - if (!abEmitted[fidx]) { - - // so iterate through all vertices of the current triangle - const aiFace* pcFace = &pMesh->mFaces[ fidx ]; - unsigned nind = pcFace->mNumIndices; - for (unsigned ind = 0; ind < nind; ind++) { - unsigned dp = pcFace->mIndices[ind]; - - // the current vertex won't have any free triangles after this step - if (ivdx != (int)dp) { - // append the vertex to the dead-end stack - sDeadEndVStack.push(dp); - - // register as candidate for the next step - *piCurCandidate++ = dp; - - // decrease the per-vertex triangle counts - piNumTriPtr[dp]--; - } - - // append the vertex to the output index buffer - *piCSIter++ = dp; - - // if the vertex is not yet in cache, set its cache count - if (iStampCnt-piCachingStamps[dp] > mConfigCacheDepth) { - piCachingStamps[dp] = iStampCnt++; - ++iCacheMisses; - } - } - // flag triangle as emitted - abEmitted[fidx] = true; - } - } - - // the vertex has now no living adjacent triangles anymore - piNumTriPtr[ivdx] = 0; - - // get next fanning vertex - ivdx = -1; - int max_priority = -1; - for (unsigned int* piCur = piCandidates;piCur != piCurCandidate;++piCur) { - const unsigned int dp = *piCur; - - // must have live triangles - if (piNumTriPtr[dp] > 0) { - int priority = 0; - - // will the vertex be in cache, even after fanning occurs? - unsigned int tmp; - if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= mConfigCacheDepth) { - priority = tmp; - } - - // keep best candidate - if (priority > max_priority) { - max_priority = priority; - ivdx = dp; - } - } - } - // did we reach a dead end? - if (-1 == ivdx) { - // need to get a non-local vertex for which we have a good chance that it is still - // in the cache ... - while (!sDeadEndVStack.empty()) { - unsigned int iCachedIdx = sDeadEndVStack.top(); - sDeadEndVStack.pop(); - if (piNumTriPtr[ iCachedIdx ] > 0) { - ivdx = iCachedIdx; - break; - } - } - - if (-1 == ivdx) { - // well, there isn't such a vertex. Simply get the next vertex in input order and - // hope it is not too bad ... - while (ics < (int)pMesh->mNumVertices) { - ++ics; - if (piNumTriPtr[ics] > 0) { - ivdx = ics; - break; - } - } - } - } - } - ai_real fACMR2 = 0.0f; - if (!DefaultLogger::isNullLogger()) { - fACMR2 = (float)iCacheMisses / pMesh->mNumFaces; - - // very intense verbose logging ... prepare for much text if there are many meshes - if ( DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { - ASSIMP_LOG_DEBUG_F("Mesh %u | ACMR in: ", meshNum, " out: ", fACMR, " | ~", fACMR2, ((fACMR - fACMR2) / fACMR) * 100.f); - } - - fACMR2 *= pMesh->mNumFaces; - } - // sort the output index buffer back to the input array - piCSIter = piIBOutput; - for (aiFace* pcFace = pMesh->mFaces; pcFace != pcEnd;++pcFace) { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - if (nind > 0) ind[0] = *piCSIter++; - if (nind > 1) ind[1] = *piCSIter++; - if (nind > 2) ind[2] = *piCSIter++; - } - - // delete temporary storage - delete[] piCachingStamps; - delete[] piIBOutput; - delete[] piCandidates; - - return fACMR2; -} diff --git a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h b/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h deleted file mode 100644 index de25ecd9fb12..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -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 Defines a post processing step to reorder faces for - better cache locality*/ -#ifndef AI_IMPROVECACHELOCALITY_H_INC -#define AI_IMPROVECACHELOCALITY_H_INC - -#include "Common/BaseProcess.h" - -#include - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The ImproveCacheLocalityProcess reorders all faces for improved vertex - * cache locality. It tries to arrange all faces to fans and to render - * faces which share vertices directly one after the other. - * - * @note This step expects triagulated input data. - */ -class ImproveCacheLocalityProcess : public BaseProcess -{ -public: - - ImproveCacheLocalityProcess(); - ~ImproveCacheLocalityProcess(); - -public: - - // ------------------------------------------------------------------- - // Check whether the pp step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Executes the pp step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Configures the pp step - void SetupProperties(const Importer* pImp); - -protected: - // ------------------------------------------------------------------- - /** Executes the postprocessing step on the given mesh - * @param pMesh The mesh to process. - * @param meshNum Index of the mesh to process - */ - ai_real ProcessMesh( aiMesh* pMesh, unsigned int meshNum); - -private: - //! Configuration parameter: specifies the size of the cache to - //! optimize the vertex data for. - unsigned int mConfigCacheDepth; -}; - -} // end of namespace Assimp - -#endif // AI_IMPROVECACHELOCALITY_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp b/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp deleted file mode 100644 index f121fc60d386..000000000000 --- a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to join identical vertices - * for all imported meshes - */ - - -#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS - -#include "JoinVerticesProcess.h" -#include "ProcessHelper.h" -#include -#include -#include -#include - -using namespace Assimp; -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -JoinVerticesProcess::JoinVerticesProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -JoinVerticesProcess::~JoinVerticesProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool JoinVerticesProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_JoinIdenticalVertices) != 0; -} -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void JoinVerticesProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("JoinVerticesProcess begin"); - - // get the total number of vertices BEFORE the step is executed - int iNumOldVertices = 0; - if (!DefaultLogger::isNullLogger()) { - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - iNumOldVertices += pScene->mMeshes[a]->mNumVertices; - } - } - - // execute the step - int iNumVertices = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - iNumVertices += ProcessMesh( pScene->mMeshes[a],a); - - // if logging is active, print detailed statistics - if (!DefaultLogger::isNullLogger()) { - if (iNumOldVertices == iNumVertices) { - ASSIMP_LOG_DEBUG("JoinVerticesProcess finished "); - } else { - ASSIMP_LOG_INFO_F("JoinVerticesProcess finished | Verts in: ", iNumOldVertices, - " out: ", iNumVertices, " | ~", - ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f ); - } - } - - pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; -} - -namespace { - -bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) -{ - // A little helper to find locally close vertices faster. - // Try to reuse the lookup table from the last step. - const static float epsilon = 1e-5f; - // Squared because we check against squared length of the vector difference - static const float squareEpsilon = epsilon * epsilon; - - // Square compare is useful for animeshes vertices compare - if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) { - return false; - } - - // We just test the other attributes even if they're not present in the mesh. - // In this case they're initialized to 0 so the comparison succeeds. - // By this method the non-present attributes are effectively ignored in the comparison. - if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.texcoords[0] - rhs.texcoords[0]).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) { - return false; - } - - // Usually we won't have vertex colors or multiple UVs, so we can skip from here - // Actually this increases runtime performance slightly, at least if branch - // prediction is on our side. - if (complex) { - for (int i = 0; i < 8; i++) { - if (i > 0 && (lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) { - return false; - } - if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) { - return false; - } - } - } - return true; -} - -template -void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { - // replace vertex data with the unique data sets - pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); - - // ---------------------------------------------------------------------------- - // NOTE - we're *not* calling Vertex::SortBack() because it would check for - // presence of every single vertex component once PER VERTEX. And our CPU - // dislikes branches, even if they're easily predictable. - // ---------------------------------------------------------------------------- - - // Position, if present (check made for aiAnimMesh) - if (pMesh->mVertices) - { - delete [] pMesh->mVertices; - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mVertices[a] = uniqueVertices[a].position; - } - } - - // Normals, if present - if (pMesh->mNormals) - { - delete [] pMesh->mNormals; - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mNormals[a] = uniqueVertices[a].normal; - } - } - // Tangents, if present - if (pMesh->mTangents) - { - delete [] pMesh->mTangents; - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mTangents[a] = uniqueVertices[a].tangent; - } - } - // Bitangents as well - if (pMesh->mBitangents) - { - delete [] pMesh->mBitangents; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mBitangents[a] = uniqueVertices[a].bitangent; - } - } - // Vertex colors - for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) - { - delete [] pMesh->mColors[a]; - pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; - } - } - // Texture coords - for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) - { - delete [] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; - } - } -} -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) -{ - static_assert( AI_MAX_NUMBER_OF_COLOR_SETS == 8, "AI_MAX_NUMBER_OF_COLOR_SETS == 8"); - static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8"); - - // Return early if we don't have any positions - if (!pMesh->HasPositions() || !pMesh->HasFaces()) { - return 0; - } - - // We should care only about used vertices, not all of them - // (this can happen due to original file vertices buffer being used by - // multiple meshes) - std::unordered_set usedVertexIndices; - usedVertexIndices.reserve(pMesh->mNumVertices); - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices; b++) { - usedVertexIndices.insert(face.mIndices[b]); - } - } - - // We'll never have more vertices afterwards. - std::vector uniqueVertices; - uniqueVertices.reserve( pMesh->mNumVertices); - - // For each vertex the index of the vertex it was replaced by. - // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark - // whether a new vertex was created for the index (true) or if it was replaced by an existing - // unique vertex (false). This saves an additional std::vector and greatly enhances - // branching performance. - static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); - std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); - - // float posEpsilonSqr; - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - - typedef std::pair SpatPair; - if (shared) { - std::vector* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) { - SpatPair& blubb = (*avf)[meshIndex]; - vertexFinder = &blubb.first; - // posEpsilonSqr = blubb.second; - } - } - if (!vertexFinder) { - // bad, need to compute it. - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - // posEpsilonSqr = ComputePositionEpsilon(pMesh); - } - - // Again, better waste some bytes than a realloc ... - std::vector verticesFound; - verticesFound.reserve(10); - - // Run an optimized code path if we don't have multiple UVs or vertex colors. - // This should yield false in more than 99% of all imports ... - const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1); - const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0; - - // We'll never have more vertices afterwards. - std::vector> uniqueAnimatedVertices; - if (hasAnimMeshes) { - uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes); - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices); - } - } - - // Now check each vertex if it brings something new to the table - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - if (usedVertexIndices.find(a) == usedVertexIndices.end()) { - continue; - } - - // collect the vertex data - Vertex v(pMesh,a); - - // collect all vertices that are close enough to the given position - vertexFinder->FindIdenticalPositions( v.position, verticesFound); - unsigned int matchIndex = 0xffffffff; - - // check all unique vertices close to the position if this vertex is already present among them - for( unsigned int b = 0; b < verticesFound.size(); b++) { - const unsigned int vidx = verticesFound[b]; - const unsigned int uidx = replaceIndex[ vidx]; - if( uidx & 0x80000000) - continue; - - const Vertex& uv = uniqueVertices[ uidx]; - - if (!areVerticesEqual(v, uv, complex)) { - continue; - } - - if (hasAnimMeshes) { - // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology) - // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces) - bool breaksAnimMesh = false; - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx]; - Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); - if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) { - breaksAnimMesh = true; - break; - } - } - if (breaksAnimMesh) { - continue; - } - } - - // we're still here -> this vertex perfectly matches our given vertex - matchIndex = uidx; - break; - } - - // found a replacement vertex among the uniques? - if( matchIndex != 0xffffffff) - { - // store where to found the matching unique vertex - replaceIndex[a] = matchIndex | 0x80000000; - } - else - { - // no unique vertex matches it up to now -> so add it - replaceIndex[a] = (unsigned int)uniqueVertices.size(); - uniqueVertices.push_back( v); - if (hasAnimMeshes) { - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); - uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex); - } - } - } - } - - if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { - ASSIMP_LOG_DEBUG_F( - "Mesh ",meshIndex, - " (", - (pMesh->mName.length ? pMesh->mName.data : "unnamed"), - ") | Verts in: ",pMesh->mNumVertices, - " out: ", - uniqueVertices.size(), - " | ~", - ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f, - "%" - ); - } - - updateXMeshVertices(pMesh, uniqueVertices); - if (hasAnimMeshes) { - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]); - } - } - - // adjust the indices in all faces - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices; b++) { - face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000; - } - } - - // adjust bone vertex weights. - for( int a = 0; a < (int)pMesh->mNumBones; a++) { - aiBone* bone = pMesh->mBones[a]; - std::vector newWeights; - newWeights.reserve( bone->mNumWeights); - - if ( NULL != bone->mWeights ) { - for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) { - const aiVertexWeight& ow = bone->mWeights[ b ]; - // if the vertex is a unique one, translate it - if ( !( replaceIndex[ ow.mVertexId ] & 0x80000000 ) ) { - aiVertexWeight nw; - nw.mVertexId = replaceIndex[ ow.mVertexId ]; - nw.mWeight = ow.mWeight; - newWeights.push_back( nw ); - } - } - } else { - ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is NULL." ); - } - - if (newWeights.size() > 0) { - // kill the old and replace them with the translated weights - delete [] bone->mWeights; - bone->mNumWeights = (unsigned int)newWeights.size(); - - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight)); - } - } - return pMesh->mNumVertices; -} - -#endif // !! ASSIMP_BUILD_NO_JOINVERTICES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h b/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h deleted file mode 100644 index e017ae62dbd2..000000000000 --- a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -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 Defines a post processing step to join identical vertices - on all imported meshes.*/ -#ifndef AI_JOINVERTICESPROCESS_H_INC -#define AI_JOINVERTICESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The JoinVerticesProcess unites identical vertices in all imported meshes. - * By default the importer returns meshes where each face addressed its own - * set of vertices even if that means that identical vertices are stored multiple - * times. The JoinVerticesProcess finds these identical vertices and - * erases all but one of the copies. This usually reduces the number of vertices - * in a mesh by a serious amount and is the standard form to render a mesh. - */ -class ASSIMP_API JoinVerticesProcess : public BaseProcess { -public: - JoinVerticesProcess(); - ~JoinVerticesProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Unites identical vertices in the given mesh. - * @param pMesh The mesh to process. - * @param meshIndex Index of the mesh to process - */ - int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp b/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp deleted file mode 100644 index d560f192879f..000000000000 --- a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -/** Implementation of the LimitBoneWeightsProcess post processing step */ - - -#include "LimitBoneWeightsProcess.h" -#include -#include -#include -#include -#include - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -LimitBoneWeightsProcess::LimitBoneWeightsProcess() -{ - mMaxWeights = AI_LMW_MAX_WEIGHTS; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -LimitBoneWeightsProcess::~LimitBoneWeightsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_LimitBoneWeights) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh(pScene->mMeshes[a]); - } - - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) -{ - // get the current value of the property - this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); -} - -// ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) -{ - if( !pMesh->HasBones()) - return; - - // collect all bone weights per vertex - typedef std::vector< std::vector< Weight > > WeightsPerVertex; - WeightsPerVertex vertexWeights( pMesh->mNumVertices); - - // collect all weights per vertex - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; b++) - { - const aiVertexWeight& w = bone->mWeights[b]; - vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight)); - } - } - - unsigned int removed = 0, old_bones = pMesh->mNumBones; - - // now cut the weight count if it exceeds the maximum - bool bChanged = false; - for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) - { - if( vit->size() <= mMaxWeights) - continue; - - bChanged = true; - - // more than the defined maximum -> first sort by weight in descending order. That's - // why we defined the < operator in such a weird way. - std::sort( vit->begin(), vit->end()); - - // now kill everything beyond the maximum count - unsigned int m = static_cast(vit->size()); - vit->erase( vit->begin() + mMaxWeights, vit->end()); - removed += static_cast(m-vit->size()); - - // and renormalize the weights - float sum = 0.0f; - for( std::vector::const_iterator it = vit->begin(); it != vit->end(); ++it ) { - sum += it->mWeight; - } - if( 0.0f != sum ) { - const float invSum = 1.0f / sum; - for( std::vector::iterator it = vit->begin(); it != vit->end(); ++it ) { - it->mWeight *= invSum; - } - } - } - - if (bChanged) { - // rebuild the vertex weight array for all bones - typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone; - WeightsPerBone boneWeights( pMesh->mNumBones); - for( unsigned int a = 0; a < vertexWeights.size(); a++) - { - const std::vector& vw = vertexWeights[a]; - for( std::vector::const_iterator it = vw.begin(); it != vw.end(); ++it) - boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight)); - } - - // and finally copy the vertex weight list over to the mesh's bones - std::vector abNoNeed(pMesh->mNumBones,false); - bChanged = false; - - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const std::vector& bw = boneWeights[a]; - aiBone* bone = pMesh->mBones[a]; - - if ( bw.empty() ) - { - abNoNeed[a] = bChanged = true; - continue; - } - - // copy the weight list. should always be less weights than before, so we don't need a new allocation - ai_assert( bw.size() <= bone->mNumWeights); - bone->mNumWeights = static_cast( bw.size() ); - ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight)); - } - - if (bChanged) { - // the number of new bones is smaller than before, so we can reuse the old array - aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur; - - for (std::vector::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) { - if (*iter) { - delete *ppcSrc; - --pMesh->mNumBones; - } - else *ppcCur++ = *ppcSrc; - ++ppcSrc; - } - } - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones ); - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h b/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h deleted file mode 100644 index 73c2a68d537c..000000000000 --- a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -/** Defines a post processing step to limit the number of bones affecting a single vertex. */ -#ifndef AI_LIMITBONEWEIGHTSPROCESS_H_INC -#define AI_LIMITBONEWEIGHTSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -// Forward declarations -struct aiMesh; - -class LimitBoneWeightsTest; - -namespace Assimp { - -// NOTE: If you change these limits, don't forget to change the -// corresponding values in all Assimp ports - -// ********************************************************** -// Java: ConfigProperty.java, -// ConfigProperty.DEFAULT_BONE_WEIGHT_LIMIT -// ********************************************************** - -#if (!defined AI_LMW_MAX_WEIGHTS) -# define AI_LMW_MAX_WEIGHTS 0x4 -#endif // !! AI_LMW_MAX_WEIGHTS - -// --------------------------------------------------------------------------- -/** This post processing step limits the number of bones affecting a vertex -* to a certain maximum value. If a vertex is affected by more than that number -* of bones, the bone weight with the least influence on this vertex are removed. -* The other weights on this bone are then renormalized to assure the sum weight -* to be 1. -*/ -class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess { -public: - LimitBoneWeightsProcess(); - ~LimitBoneWeightsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Limits the bone weight count for all vertices in the given mesh. - * @param pMesh The mesh to process. - */ - void ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Describes a bone weight on a vertex */ - struct Weight { - unsigned int mBone; ///< Index of the bone - float mWeight; ///< Weight of that bone on this vertex - Weight() AI_NO_EXCEPT - : mBone(0) - , mWeight(0.0f) { - // empty - } - - Weight( unsigned int pBone, float pWeight) - : mBone(pBone) - , mWeight(pWeight) { - // empty - } - - /** Comparison operator to sort bone weights by descending weight */ - bool operator < (const Weight& pWeight) const { - return mWeight > pWeight.mWeight; - } - }; - - /** Maximum number of bones influencing any single vertex. */ - unsigned int mMaxWeights; -}; - -} // end of namespace Assimp - -#endif // AI_LIMITBONEWEIGHTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp b/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp deleted file mode 100644 index 41f50a5ba593..000000000000 --- a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step "MakeVerboseFormat" -*/ - - -#include "MakeVerboseFormat.h" -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::MakeVerboseFormatProcess() -{ - // nothing to do here -} -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::~MakeVerboseFormatProcess() -{ - // nothing to do here -} -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void MakeVerboseFormatProcess::Execute( aiScene* pScene) -{ - ai_assert(NULL != pScene); - ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess begin"); - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if( MakeVerboseFormat( pScene->mMeshes[a])) - bHas = true; - } - if (bHas) { - ASSIMP_LOG_INFO("MakeVerboseFormatProcess finished. There was much work to do ..."); - } else { - ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess. There was nothing to do."); - } - - pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) -{ - ai_assert(NULL != pcMesh); - - unsigned int iOldNumVertices = pcMesh->mNumVertices; - const unsigned int iNumVerts = pcMesh->mNumFaces*3; - - aiVector3D* pvPositions = new aiVector3D[ iNumVerts ]; - - aiVector3D* pvNormals = NULL; - if (pcMesh->HasNormals()) - { - pvNormals = new aiVector3D[iNumVerts]; - } - aiVector3D* pvTangents = NULL, *pvBitangents = NULL; - if (pcMesh->HasTangentsAndBitangents()) - { - pvTangents = new aiVector3D[iNumVerts]; - pvBitangents = new aiVector3D[iNumVerts]; - } - - aiVector3D* apvTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS] = {0}; - aiColor4D* apvColorSets[AI_MAX_NUMBER_OF_COLOR_SETS] = {0}; - - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - apvTextureCoords[p++] = new aiVector3D[iNumVerts]; - - p = 0; - while (pcMesh->HasVertexColors(p)) - apvColorSets[p++] = new aiColor4D[iNumVerts]; - - // allocate enough memory to hold output bones and vertex weights ... - std::vector* newWeights = new std::vector[pcMesh->mNumBones]; - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) { - newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights*3); - } - - // iterate through all faces and build a clean list - unsigned int iIndex = 0; - for (unsigned int a = 0; a< pcMesh->mNumFaces;++a) - { - aiFace* pcFace = &pcMesh->mFaces[a]; - for (unsigned int q = 0; q < pcFace->mNumIndices;++q,++iIndex) - { - // need to build a clean list of bones, too - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) - { - for (unsigned int a = 0; a < pcMesh->mBones[i]->mNumWeights;a++) - { - const aiVertexWeight& w = pcMesh->mBones[i]->mWeights[a]; - if(pcFace->mIndices[q] == w.mVertexId) - { - aiVertexWeight wNew; - wNew.mVertexId = iIndex; - wNew.mWeight = w.mWeight; - newWeights[i].push_back(wNew); - } - } - } - - pvPositions[iIndex] = pcMesh->mVertices[pcFace->mIndices[q]]; - - if (pcMesh->HasNormals()) - { - pvNormals[iIndex] = pcMesh->mNormals[pcFace->mIndices[q]]; - } - if (pcMesh->HasTangentsAndBitangents()) - { - pvTangents[iIndex] = pcMesh->mTangents[pcFace->mIndices[q]]; - pvBitangents[iIndex] = pcMesh->mBitangents[pcFace->mIndices[q]]; - } - - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - { - apvTextureCoords[p][iIndex] = pcMesh->mTextureCoords[p][pcFace->mIndices[q]]; - ++p; - } - p = 0; - while (pcMesh->HasVertexColors(p)) - { - apvColorSets[p][iIndex] = pcMesh->mColors[p][pcFace->mIndices[q]]; - ++p; - } - pcFace->mIndices[q] = iIndex; - } - } - - - - // build output vertex weights - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) - { - delete [] pcMesh->mBones[i]->mWeights; - if (!newWeights[i].empty()) { - pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()]; - aiVertexWeight *weightToCopy = &( newWeights[i][0] ); - memcpy(pcMesh->mBones[i]->mWeights, weightToCopy, - sizeof(aiVertexWeight) * newWeights[i].size()); - } else { - pcMesh->mBones[i]->mWeights = NULL; - } - } - delete[] newWeights; - - // delete the old members - delete[] pcMesh->mVertices; - pcMesh->mVertices = pvPositions; - - p = 0; - while (pcMesh->HasTextureCoords(p)) - { - delete[] pcMesh->mTextureCoords[p]; - pcMesh->mTextureCoords[p] = apvTextureCoords[p]; - ++p; - } - p = 0; - while (pcMesh->HasVertexColors(p)) - { - delete[] pcMesh->mColors[p]; - pcMesh->mColors[p] = apvColorSets[p]; - ++p; - } - pcMesh->mNumVertices = iNumVerts; - - if (pcMesh->HasNormals()) - { - delete[] pcMesh->mNormals; - pcMesh->mNormals = pvNormals; - } - if (pcMesh->HasTangentsAndBitangents()) - { - delete[] pcMesh->mTangents; - pcMesh->mTangents = pvTangents; - delete[] pcMesh->mBitangents; - pcMesh->mBitangents = pvBitangents; - } - return (pcMesh->mNumVertices != iOldNumVertices); -} - - -// ------------------------------------------------------------------------------------------------ -bool IsMeshInVerboseFormat(const aiMesh* mesh) { - // avoid slow vector specialization - std::vector seen(mesh->mNumVertices,0); - for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { - const aiFace& f = mesh->mFaces[i]; - for(unsigned int j = 0; j < f.mNumIndices; ++j) { - if(++seen[f.mIndices[j]] == 2) { - // found a duplicate index - return false; - } - } - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) { - for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) { - return false; - } - } - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h b/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h deleted file mode 100644 index 8565d5933a1e..000000000000 --- a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -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 Defines a post processing step to bring a given scene - into the verbose format that is expected by most postprocess steps. - This is the inverse of the "JoinIdenticalVertices" step. */ -#ifndef AI_MAKEVERBOSEFORMAT_H_INC -#define AI_MAKEVERBOSEFORMAT_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** MakeVerboseFormatProcess: Class to convert an asset to the verbose - * format which is expected by most postprocess steps. - * - * This is the inverse of what the "JoinIdenticalVertices" step is doing. - * This step has no official flag (since it wouldn't make sense to run it - * during import). It is intended for applications intending to modify the - * returned aiScene. After this step has been executed, they can execute - * other postprocess steps on the data. The code might also be useful to - * quickly adapt code that doesn't result in a verbose representation of - * the scene data. - * The step has been added because it was required by the viewer, however - * it has been moved to the main library since others might find it - * useful, too. */ -class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess -{ -public: - - - MakeVerboseFormatProcess(); - ~MakeVerboseFormatProcess(); - -public: - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not */ - bool IsActive( unsigned int /*pFlags*/ ) const - { - // NOTE: There is no direct flag that corresponds to - // this postprocess step. - return false; - } - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); - -public: - - // ------------------------------------------------------------------- - /** Checks whether the scene is already in verbose format. - * @param pScene The data to check. - * @return true if the scene is already in verbose format. */ - static bool IsVerboseFormat(const aiScene* pScene); - -private: - - //! Apply the postprocess step to a given submesh - bool MakeVerboseFormat (aiMesh* pcMesh); -}; - -} // end of namespace Assimp - -#endif // !!AI_KILLNORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp b/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp deleted file mode 100644 index 5db51f58b6ba..000000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 OptimizeGraph.cpp - * @brief Implementation of the aiProcess_OptimizGraph step - */ - - -#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS - -#include "OptimizeGraph.h" -#include "ProcessHelper.h" -#include -#include -#include - -using namespace Assimp; - -#define AI_RESERVED_NODE_NAME "$Reserved_And_Evil" - -/* AI_OG_USE_HASHING enables the use of hashing to speed-up std::set lookups. - * The unhashed variant should be faster, except for *very* large data sets - */ -#ifdef AI_OG_USE_HASHING - // Use our standard hashing function to compute the hash -# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length) -#else - // Otherwise hope that std::string will utilize a static buffer - // for shorter node names. This would avoid endless heap copying. -# define AI_OG_GETKEY(str) std::string(str.data) -#endif - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -OptimizeGraphProcess::OptimizeGraphProcess() -: mScene() -, nodes_in() -, nodes_out() -, count_merged() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeGraphProcess::~OptimizeGraphProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const { - return (0 != (pFlags & aiProcess_OptimizeGraph)); -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the post-processing step -void OptimizeGraphProcess::SetupProperties(const Importer* pImp) { - // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST - std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,""); - AddLockedNodeList(tmp); -} - -// ------------------------------------------------------------------------------------------------ -// Collect new children -void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list& nodes) { - nodes_in += nd->mNumChildren; - - // Process children - std::list child_nodes; - for (unsigned int i = 0; i < nd->mNumChildren; ++i) { - CollectNewChildren(nd->mChildren[i],child_nodes); - nd->mChildren[i] = nullptr; - } - - // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest). - if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) { - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { - - if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) { - (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation; - nodes.push_back(*it); - - it = child_nodes.erase(it); - continue; - } - ++it; - } - - if (nd->mNumMeshes || !child_nodes.empty()) { - nodes.push_back(nd); - } else { - delete nd; /* bye, node */ - return; - } - } else { - - // Retain our current position in the hierarchy - nodes.push_back(nd); - - // Now check for possible optimizations in our list of child nodes. join as many as possible - aiNode* join_master = NULL; - aiMatrix4x4 inv; - - const LockedSetType::const_iterator end = locked.end(); - - std::list join; - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { - aiNode* child = *it; - if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) { - - // There may be no instanced meshes - unsigned int n = 0; - for (; n < child->mNumMeshes;++n) { - if (meshes[child->mMeshes[n]] > 1) { - break; - } - } - if (n == child->mNumMeshes) { - if (!join_master) { - join_master = child; - inv = join_master->mTransformation; - inv.Inverse(); - } else { - child->mTransformation = inv * child->mTransformation ; - - join.push_back(child); - it = child_nodes.erase(it); - continue; - } - } - } - ++it; - } - if (join_master && !join.empty()) { - join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++); - - unsigned int out_meshes = 0; - for (std::list::iterator it = join.begin(); it != join.end(); ++it) { - out_meshes += (*it)->mNumMeshes; - } - - // copy all mesh references in one array - if (out_meshes) { - unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes; - for (unsigned int n = 0; n < join_master->mNumMeshes;++n) { - *tmp++ = join_master->mMeshes[n]; - } - - for (std::list::iterator it = join.begin(); it != join.end(); ++it) { - for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) { - - *tmp = (*it)->mMeshes[n]; - aiMesh* mesh = mScene->mMeshes[*tmp++]; - - // manually move the mesh into the right coordinate system - const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose(); - for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { - - mesh->mVertices[a] *= (*it)->mTransformation; - - if (mesh->HasNormals()) - mesh->mNormals[a] *= IT; - - if (mesh->HasTangentsAndBitangents()) { - mesh->mTangents[a] *= IT; - mesh->mBitangents[a] *= IT; - } - } - } - delete *it; // bye, node - } - delete[] join_master->mMeshes; - join_master->mMeshes = meshes; - join_master->mNumMeshes += out_meshes; - } - } - } - // reassign children if something changed - if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) { - - delete[] nd->mChildren; - - if (!child_nodes.empty()) { - nd->mChildren = new aiNode*[child_nodes.size()]; - } - else nd->mChildren = nullptr; - } - - nd->mNumChildren = static_cast(child_nodes.size()); - - if (nd->mChildren) { - aiNode** tmp = nd->mChildren; - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) { - aiNode* node = *tmp++ = *it; - node->mParent = nd; - } - } - - nodes_out += static_cast(child_nodes.size()); -} - -// ------------------------------------------------------------------------------------------------ -// Execute the post-processing step on the given scene -void OptimizeGraphProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin"); - nodes_in = nodes_out = count_merged = 0; - mScene = pScene; - - meshes.resize(pScene->mNumMeshes,0); - FindInstancedMeshes(pScene->mRootNode); - - // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it - locked.clear(); - for (std::list::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) { -#ifdef AI_OG_USE_HASHING - locked.insert(SuperFastHash((*it).c_str())); -#else - locked.insert(*it); -#endif - } - - for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { - for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) { - aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a]; - locked.insert(AI_OG_GETKEY(anim->mNodeName)); - } - } - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) { - - aiBone* bone = pScene->mMeshes[i]->mBones[a]; - locked.insert(AI_OG_GETKEY(bone->mName)); - - // HACK: Meshes referencing bones may not be transformed; we need to look them. - // The easiest way to do this is to increase their reference counters ... - meshes[i] += 2; - } - } - - for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { - aiCamera* cam = pScene->mCameras[i]; - locked.insert(AI_OG_GETKEY(cam->mName)); - } - - for (unsigned int i = 0; i < pScene->mNumLights; ++i) { - aiLight* lgh = pScene->mLights[i]; - locked.insert(AI_OG_GETKEY(lgh->mName)); - } - - // Insert a dummy master node and make it read-only - aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME); - locked.insert(AI_OG_GETKEY(dummy_root->mName)); - - const aiString prev = pScene->mRootNode->mName; - pScene->mRootNode->mParent = dummy_root; - - dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1]; - dummy_root->mChildren[0] = pScene->mRootNode; - - // Do our recursive processing of scenegraph nodes. For each node collect - // a fully new list of children and allow their children to place themselves - // on the same hierarchy layer as their parents. - std::list nodes; - CollectNewChildren (dummy_root,nodes); - - ai_assert(nodes.size() == 1); - - if (dummy_root->mNumChildren == 0) { - pScene->mRootNode = NULL; - throw DeadlyImportError("After optimizing the scene graph, no data remains"); - } - - if (dummy_root->mNumChildren > 1) { - pScene->mRootNode = dummy_root; - - // Keep the dummy node but assign the name of the old root node to it - pScene->mRootNode->mName = prev; - } - else { - - // Remove the dummy root node again. - pScene->mRootNode = dummy_root->mChildren[0]; - - dummy_root->mChildren[0] = NULL; - delete dummy_root; - } - - pScene->mRootNode->mParent = NULL; - if (!DefaultLogger::isNullLogger()) { - if ( nodes_in != nodes_out) { - ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out); - } else { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished"); - } - } - meshes.clear(); - locked.clear(); -} - -// ------------------------------------------------------------------------------------------------ -// Build a LUT of all instanced meshes -void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode) -{ - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - ++meshes[pNode->mMeshes[i]]; - } - - for (unsigned int i = 0; i < pNode->mNumChildren; ++i) - FindInstancedMeshes(pNode->mChildren[i]); -} - -#endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h b/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h deleted file mode 100644 index 82cc5db3fe45..000000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -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 OptimizeGraph.h - * @brief Declares a post processing step to optimize the scenegraph - */ -#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC -#define AI_OPTIMIZEGRAPHPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include "PostProcessing/ProcessHelper.h" - -#include - -#include - -// Forward declarations -struct aiMesh; - -class OptimizeGraphProcessTest; - -namespace Assimp { - -// ----------------------------------------------------------------------------- -/** @brief Postprocessing step to optimize the scenegraph - * - * The implementation tries to merge nodes, even if they use different - * transformations. Animations are preserved. - * - * @see aiProcess_OptimizeGraph for a detailed description of the - * algorithm being applied. - */ -class OptimizeGraphProcess : public BaseProcess { -public: - OptimizeGraphProcess(); - ~OptimizeGraphProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Add a list of node names to be locked and not modified. - * @param in List of nodes. See #AI_CONFIG_PP_OG_EXCLUDE_LIST for - * format explanations. - */ - inline void AddLockedNodeList(std::string& in) { - ConvertListToStrings (in,locked_nodes); - } - - // ------------------------------------------------------------------- - /** @brief Add another node to be locked and not modified. - * @param name Name to be locked - */ - inline void AddLockedNode(std::string& name) { - locked_nodes.push_back(name); - } - - // ------------------------------------------------------------------- - /** @brief Remove a node from the list of locked nodes. - * @param name Name to be unlocked - */ - inline void RemoveLockedNode(std::string& name) { - locked_nodes.remove(name); - } - -protected: - void CollectNewChildren(aiNode* nd, std::list& nodes); - void FindInstancedMeshes (aiNode* pNode); - -private: -#ifdef AI_OG_USE_HASHING - typedef std::set LockedSetType; -#else - typedef std::set LockedSetType; -#endif - - //! Scene we're working with - aiScene* mScene; - - //! List of locked names. Stored is the hash of the name - LockedSetType locked; - - //! List of nodes to be locked in addition to those with animations, lights or cameras assigned. - std::list locked_nodes; - - //! Node counters for logging purposes - unsigned int nodes_in,nodes_out, count_merged; - - //! Reference counters for meshes - std::vector meshes; -}; - -} // end of namespace Assimp - -#endif // AI_OPTIMIZEGRAPHPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp b/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp deleted file mode 100644 index 3f6765f6caf1..000000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 OptimizeMeshes.cpp - * @brief Implementation of the aiProcess_OptimizeMeshes step - */ - - -#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS - - -#include "OptimizeMeshes.h" -#include "ProcessHelper.h" -#include -#include - -using namespace Assimp; - -static const unsigned int NotSet = 0xffffffff; -static const unsigned int DeadBeef = 0xdeadbeef; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -OptimizeMeshesProcess::OptimizeMeshesProcess() - : mScene() - , pts(false) - , max_verts( NotSet ) - , max_faces( NotSet ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeMeshesProcess::~OptimizeMeshesProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const -{ - // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes - // steps are active. Thus we need to query their flags here and store the - // information, although we're breaking const-correctness. - // That's a serious design flaw, consider redesign. - if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) { - pts = (0 != (pFlags & aiProcess_SortByPType)); - max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts; - return true; - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the post-processing step -void OptimizeMeshesProcess::SetupProperties(const Importer* pImp) -{ - if( max_verts == DeadBeef /* magic hack */ ) { - max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); - max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); - } -} - -// ------------------------------------------------------------------------------------------------ -// Execute step -void OptimizeMeshesProcess::Execute( aiScene* pScene) -{ - const unsigned int num_old = pScene->mNumMeshes; - if (num_old <= 1) { - ASSIMP_LOG_DEBUG("Skipping OptimizeMeshesProcess"); - return; - } - - ASSIMP_LOG_DEBUG("OptimizeMeshesProcess begin"); - mScene = pScene; - - // need to clear persistent members from previous runs - merge_list.resize( 0 ); - output.resize( 0 ); - - // ensure we have the right sizes - merge_list.reserve(pScene->mNumMeshes); - output.reserve(pScene->mNumMeshes); - - // Prepare lookup tables - meshes.resize(pScene->mNumMeshes); - FindInstancedMeshes(pScene->mRootNode); - if( max_verts == DeadBeef ) /* undo the magic hack */ - max_verts = NotSet; - - // ... instanced meshes are immediately processed and added to the output list - for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) { - meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]); - - if (meshes[i].instance_cnt > 1 && meshes[i].output_id == NotSet ) { - meshes[i].output_id = n++; - output.push_back(mScene->mMeshes[i]); - } - } - - // and process all nodes in the scenegraph recursively - ProcessNode(pScene->mRootNode); - if (!output.size()) { - throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong"); - } - - meshes.resize( 0 ); - ai_assert(output.size() <= num_old); - - mScene->mNumMeshes = static_cast(output.size()); - std::copy(output.begin(),output.end(),mScene->mMeshes); - - if (output.size() != num_old) { - ASSIMP_LOG_DEBUG_F("OptimizeMeshesProcess finished. Input meshes: ", num_old, ", Output meshes: ", pScene->mNumMeshes); - } else { - ASSIMP_LOG_DEBUG( "OptimizeMeshesProcess finished" ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Process meshes for a single node -void OptimizeMeshesProcess::ProcessNode( aiNode* pNode) -{ - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - unsigned int& im = pNode->mMeshes[i]; - - if (meshes[im].instance_cnt > 1) { - im = meshes[im].output_id; - } - else { - merge_list.resize( 0 ); - unsigned int verts = 0, faces = 0; - - // Find meshes to merge with us - for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) { - unsigned int am = pNode->mMeshes[a]; - if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) { - - merge_list.push_back(mScene->mMeshes[am]); - verts += mScene->mMeshes[am]->mNumVertices; - faces += mScene->mMeshes[am]->mNumFaces; - - pNode->mMeshes[a] = pNode->mMeshes[pNode->mNumMeshes - 1]; - --pNode->mNumMeshes; - --a; - } - } - - // and merge all meshes which we found, replace the old ones - if (!merge_list.empty()) { - merge_list.push_back(mScene->mMeshes[im]); - - aiMesh* out; - SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end()); - output.push_back(out); - } else { - output.push_back(mScene->mMeshes[im]); - } - im = static_cast(output.size()-1); - } - } - - - for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) { - ProcessNode( pNode->mChildren[ i ] ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Check whether two meshes can be joined -bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces ) -{ - if (meshes[a].vertex_format != meshes[b].vertex_format) - return false; - - aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b]; - - if ((NotSet != max_verts && verts+mb->mNumVertices > max_verts) || - (NotSet != max_faces && faces+mb->mNumFaces > max_faces)) { - return false; - } - - // Never merge unskinned meshes with skinned meshes - if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones()) - return false; - - // Never merge meshes with different kinds of primitives if SortByPType did already - // do its work. We would destroy everything again ... - if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes) - return false; - - // If both meshes are skinned, check whether we have many bones defined in both meshes. - // If yes, we can join them. - if (ma->HasBones()) { - // TODO - return false; - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Build a LUT of all instanced meshes -void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode) -{ - for( unsigned int i = 0; i < pNode->mNumMeshes; ++i ) { - ++meshes[ pNode->mMeshes[ i ] ].instance_cnt; - } - - for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) { - FindInstancedMeshes( pNode->mChildren[ i ] ); - } -} - -// ------------------------------------------------------------------------------------------------ - -#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h b/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h deleted file mode 100644 index dec4ab52ded6..000000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -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 OptimizeMeshes.h - * @brief Declares a post processing step to join meshes, if possible - */ -#ifndef AI_OPTIMIZEMESHESPROCESS_H_INC -#define AI_OPTIMIZEMESHESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include - -#include - -struct aiMesh; -struct aiNode; -class OptimizeMeshesProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @brief Postprocessing step to optimize mesh usage - * - * The implementation looks for meshes that could be joined and joins them. - * Usually this will reduce the number of drawcalls. - * - * @note Instanced meshes are currently not processed. - */ -class OptimizeMeshesProcess : public BaseProcess { -public: - /// @brief The class constructor. - OptimizeMeshesProcess(); - - /// @brief The class destructor. - ~OptimizeMeshesProcess(); - - /** @brief Internal utility to store additional mesh info - */ - struct MeshInfo { - MeshInfo() AI_NO_EXCEPT - : instance_cnt(0) - , vertex_format(0) - , output_id(0xffffffff) { - // empty - } - - //! Number of times this mesh is referenced - unsigned int instance_cnt; - - //! Vertex format id - unsigned int vertex_format; - - //! Output ID - unsigned int output_id; - }; - -public: - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - - // ------------------------------------------------------------------- - /** @brief Specify whether you want meshes with different - * primitive types to be merged as well. - * - * IsActive() sets this property automatically to true if the - * aiProcess_SortByPType flag is found. - */ - void EnablePrimitiveTypeSorting(bool enable) { - pts = enable; - } - - // Getter - bool IsPrimitiveTypeSortingEnabled () const { - return pts; - } - - - // ------------------------------------------------------------------- - /** @brief Specify a maximum size of a single output mesh. - * - * If a single input mesh already exceeds this limit, it won't - * be split. - * @param verts Maximum number of vertices per mesh - * @param faces Maximum number of faces per mesh - */ - void SetPreferredMeshSizeLimit (unsigned int verts, unsigned int faces) - { - max_verts = verts; - max_faces = faces; - } - - -protected: - - // ------------------------------------------------------------------- - /** @brief Do the actual optimization on all meshes of this node - * @param pNode Node we're working with - */ - void ProcessNode( aiNode* pNode); - - // ------------------------------------------------------------------- - /** @brief Returns true if b can be joined with a - * - * @param verts Number of output verts up to now - * @param faces Number of output faces up to now - */ - bool CanJoin ( unsigned int a, unsigned int b, - unsigned int verts, unsigned int faces ); - - // ------------------------------------------------------------------- - /** @brief Find instanced meshes, for the moment we're excluding - * them from all optimizations - */ - void FindInstancedMeshes (aiNode* pNode); - -private: - - //! Scene we're working with - aiScene* mScene; - - //! Per mesh info - std::vector meshes; - - //! Output meshes - std::vector output; - - //! @see EnablePrimitiveTypeSorting - mutable bool pts; - - //! @see SetPreferredMeshSizeLimit - mutable unsigned int max_verts,max_faces; - - //! Temporary storage - std::vector merge_list; -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp b/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp deleted file mode 100644 index 52001a057844..000000000000 --- a/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp +++ /dev/null @@ -1,728 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 PretransformVertices.cpp - * @brief Implementation of the "PretransformVertices" post processing step -*/ - - -#include "PretransformVertices.h" -#include "ProcessHelper.h" -#include -#include - -using namespace Assimp; - -// some array offsets -#define AI_PTVS_VERTEX 0x0 -#define AI_PTVS_FACE 0x1 - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -PretransformVertices::PretransformVertices() -: configKeepHierarchy (false) -, configNormalize(false) -, configTransform(false) -, configTransformation() -, mConfigPointCloud( false ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -PretransformVertices::~PretransformVertices() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool PretransformVertices::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_PreTransformVertices) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void PretransformVertices::SetupProperties(const Importer* pImp) -{ - // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, - // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION - configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0)); - configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0)); - configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0)); - - configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); - - mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); -} - -// ------------------------------------------------------------------------------------------------ -// Count the number of nodes -unsigned int PretransformVertices::CountNodes( aiNode* pcNode ) -{ - unsigned int iRet = 1; - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - iRet += CountNodes(pcNode->mChildren[i]); - } - return iRet; -} - -// ------------------------------------------------------------------------------------------------ -// Get a bitwise combination identifying the vertex format of a mesh -unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh ) -{ - // the vertex format is stored in aiMesh::mBones for later retrieval. - // there isn't a good reason to compute it a few hundred times - // from scratch. The pointer is unused as animations are lost - // during PretransformVertices. - if (pcMesh->mBones) - return (unsigned int)(uint64_t)pcMesh->mBones; - - - const unsigned int iRet = GetMeshVFormatUnique(pcMesh); - - // store the value for later use - pcMesh->mBones = (aiBone**)(uint64_t)iRet; - return iRet; -} - -// ------------------------------------------------------------------------------------------------ -// Count the number of vertices in the whole scene and a given -// material index -void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices) -{ - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - *piVertices += pcMesh->mNumVertices; - *piFaces += pcMesh->mNumFaces; - } - } - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat, - iVFormat,piFaces,piVertices); - } -} - -// ------------------------------------------------------------------------------------------------ -// Collect vertex/face data -void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, aiMesh* pcMeshOut, - unsigned int aiCurrent[2], unsigned int* num_refs) -{ - // No need to multiply if there's no transformation - const bool identity = pcNode->mTransformation.IsIdentity(); - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - // Decrement mesh reference counter - unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; - ai_assert(0 != num_ref); - --num_ref; - // Save the name of the last mesh - if (num_ref==0) - { - pcMeshOut->mName = pcMesh->mName; - } - - if (identity) { - // copy positions without modifying them - ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mVertices, - pcMesh->mNumVertices * sizeof(aiVector3D)); - - if (iVFormat & 0x2) { - // copy normals without modifying them - ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mNormals, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - if (iVFormat & 0x4) - { - // copy tangents without modifying them - ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - // copy bitangents without modifying them - ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mBitangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - } - else - { - // copy positions, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n]; - } - aiMatrix4x4 mWorldIT = pcNode->mTransformation; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (iVFormat & 0x2) - { - // copy normals, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = - (m * pcMesh->mNormals[n]).Normalize(); - } - } - if (iVFormat & 0x4) - { - // copy tangents and bitangents, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize(); - pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize(); - } - } - } - unsigned int p = 0; - while (iVFormat & (0x100 << p)) - { - // copy texture coordinates - memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTextureCoords[p], - pcMesh->mNumVertices * sizeof(aiVector3D)); - ++p; - } - p = 0; - while (iVFormat & (0x1000000 << p)) - { - // copy vertex colors - memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mColors[p], - pcMesh->mNumVertices * sizeof(aiColor4D)); - ++p; - } - // now we need to copy all faces. since we will delete the source mesh afterwards, - // we don't need to reallocate the array of indices except if this mesh is - // referenced multiple times. - for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck) - { - aiFace& f_src = pcMesh->mFaces[planck]; - aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck]; - - const unsigned int num_idx = f_src.mNumIndices; - - f_dst.mNumIndices = num_idx; - - unsigned int* pi; - if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */ - pi = f_dst.mIndices = f_src.mIndices; - - // offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; - } - } - else { - pi = f_dst.mIndices = new unsigned int[num_idx]; - - // copy and offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX]; - } - } - - // Update the mPrimitiveTypes member of the mesh - switch (pcMesh->mFaces[planck].mNumIndices) - { - case 0x1: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 0x2: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 0x3: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; - } - aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices; - aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; - } - } - - // append all children of us - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - CollectData(pcScene,pcNode->mChildren[i],iMat, - iVFormat,pcMeshOut,aiCurrent,num_refs); - } -} - -// ------------------------------------------------------------------------------------------------ -// Get a list of all vertex formats that occur for a given material index -// The output list contains duplicate elements -void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list& aiOut) -{ - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ i ]; - if (iMat == pcMesh->mMaterialIndex) { - aiOut.push_back(GetMeshVFormat(pcMesh)); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Compute the absolute transformation matrices of each node -void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode ) -{ - if (pcNode->mParent) { - pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation; - } - - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - ComputeAbsoluteTransform(pcNode->mChildren[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the node transformation to a mesh -void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat) -{ - // Check whether we need to transform the coordinates at all - if (!mat.IsIdentity()) { - - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - aiMatrix4x4 mWorldIT = mat; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Simple routine to build meshes in worldspace, no further optimization -void PretransformVertices::BuildWCSMeshes(std::vector& out, aiMesh** in, - unsigned int numIn, aiNode* node) -{ - // NOTE: - // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy - // aiMesh::mBones store reference to abs. transform we multiplied with - - // process meshes - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - aiMesh* mesh = in[node->mMeshes[i]]; - - // check whether we can operate on this mesh - if (!mesh->mBones || *reinterpret_cast(mesh->mBones) == node->mTransformation) { - // yes, we can. - mesh->mBones = reinterpret_cast (&node->mTransformation); - mesh->mNumBones = UINT_MAX; - } - else { - - // try to find us in the list of newly created meshes - for (unsigned int n = 0; n < out.size(); ++n) { - aiMesh* ctz = out[n]; - if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { - - // ok, use this one. Update node mesh index - node->mMeshes[i] = numIn + n; - } - } - if (node->mMeshes[i] < numIn) { - // Worst case. Need to operate on a full copy of the mesh - ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); - aiMesh* ntz; - - const unsigned int tmp = mesh->mNumBones; // - mesh->mNumBones = 0; - SceneCombiner::Copy(&ntz,mesh); - mesh->mNumBones = tmp; - - ntz->mNumBones = node->mMeshes[i]; - ntz->mBones = reinterpret_cast (&node->mTransformation); - - out.push_back(ntz); - - node->mMeshes[i] = static_cast(numIn + out.size() - 1); - } - } - } - - // call children - for (unsigned int i = 0; i < node->mNumChildren;++i) - BuildWCSMeshes(out,in,numIn,node->mChildren[i]); -} - -// ------------------------------------------------------------------------------------------------ -// Reset transformation matrices to identity -void PretransformVertices::MakeIdentityTransform(aiNode* nd) -{ - nd->mTransformation = aiMatrix4x4(); - - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - MakeIdentityTransform(nd->mChildren[i]); -} - -// ------------------------------------------------------------------------------------------------ -// Build reference counters for all meshes -void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs) -{ - for (unsigned int i = 0; i< nd->mNumMeshes;++i) - refs[nd->mMeshes[i]]++; - - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - BuildMeshRefCountArray(nd->mChildren[i],refs); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void PretransformVertices::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin"); - - // Return immediately if we have no meshes - if (!pScene->mNumMeshes) - return; - - const unsigned int iOldMeshes = pScene->mNumMeshes; - const unsigned int iOldAnimationChannels = pScene->mNumAnimations; - const unsigned int iOldNodes = CountNodes(pScene->mRootNode); - - if(configTransform) { - pScene->mRootNode->mTransformation = configTransformation; - } - - // first compute absolute transformation matrices for all nodes - ComputeAbsoluteTransform(pScene->mRootNode); - - // Delete aiMesh::mBones for all meshes. The bones are - // removed during this step and we need the pointer as - // temporary storage - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - aiMesh* mesh = pScene->mMeshes[i]; - - for (unsigned int a = 0; a < mesh->mNumBones;++a) - delete mesh->mBones[a]; - - delete[] mesh->mBones; - mesh->mBones = NULL; - } - - // now build a list of output meshes - std::vector apcOutMeshes; - - // Keep scene hierarchy? It's an easy job in this case ... - // we go on and transform all meshes, if one is referenced by nodes - // with different absolute transformations a depth copy of the mesh - // is required. - if( configKeepHierarchy ) { - - // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones - BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode); - - // ... if new meshes have been generated, append them to the end of the scene - if (apcOutMeshes.size() > 0) { - aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()]; - - memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes); - memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size()); - - pScene->mNumMeshes += static_cast(apcOutMeshes.size()); - delete[] pScene->mMeshes; pScene->mMeshes = npp; - } - - // now iterate through all meshes and transform them to worldspace - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - ApplyTransform(pScene->mMeshes[i],*reinterpret_cast( pScene->mMeshes[i]->mBones )); - - // prevent improper destruction - pScene->mMeshes[i]->mBones = NULL; - pScene->mMeshes[i]->mNumBones = 0; - } - } else { - apcOutMeshes.reserve(pScene->mNumMaterials<<1u); - std::list aiVFormats; - - std::vector s(pScene->mNumMeshes,0); - BuildMeshRefCountArray(pScene->mRootNode,&s[0]); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - // get the list of all vertex formats for this material - aiVFormats.clear(); - GetVFormatList(pScene,i,aiVFormats); - aiVFormats.sort(); - aiVFormats.unique(); - for (std::list::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) { - unsigned int iVertices = 0; - unsigned int iFaces = 0; - CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices); - if (0 != iFaces && 0 != iVertices) - { - apcOutMeshes.push_back(new aiMesh()); - aiMesh* pcMesh = apcOutMeshes.back(); - pcMesh->mNumFaces = iFaces; - pcMesh->mNumVertices = iVertices; - pcMesh->mFaces = new aiFace[iFaces]; - pcMesh->mVertices = new aiVector3D[iVertices]; - pcMesh->mMaterialIndex = i; - if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices]; - if ((*j) & 0x4) - { - pcMesh->mTangents = new aiVector3D[iVertices]; - pcMesh->mBitangents = new aiVector3D[iVertices]; - } - iFaces = 0; - while ((*j) & (0x100 << iFaces)) - { - pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; - if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; - else pcMesh->mNumUVComponents[iFaces] = 2; - iFaces++; - } - iFaces = 0; - while ((*j) & (0x1000000 << iFaces)) - pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; - - // fill the mesh ... - unsigned int aiTemp[2] = {0,0}; - CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]); - } - } - } - - // If no meshes are referenced in the node graph it is possible that we get no output meshes. - if (apcOutMeshes.empty()) { - - throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); - } - else - { - // now delete all meshes in the scene and build a new mesh list - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - aiMesh* mesh = pScene->mMeshes[i]; - mesh->mNumBones = 0; - mesh->mBones = NULL; - - // we're reusing the face index arrays. avoid destruction - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { - mesh->mFaces[a].mNumIndices = 0; - mesh->mFaces[a].mIndices = NULL; - } - - delete mesh; - - // Invalidate the contents of the old mesh array. We will most - // likely have less output meshes now, so the last entries of - // the mesh array are not overridden. We set them to NULL to - // make sure the developer gets notified when his application - // attempts to access these fields ... - mesh = NULL; - } - - // It is impossible that we have more output meshes than - // input meshes, so we can easily reuse the old mesh array - pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - pScene->mMeshes[i] = apcOutMeshes[i]; - } - } - } - - // remove all animations from the scene - for (unsigned int i = 0; i < pScene->mNumAnimations;++i) - delete pScene->mAnimations[i]; - delete[] pScene->mAnimations; - - pScene->mAnimations = NULL; - pScene->mNumAnimations = 0; - - // --- we need to keep all cameras and lights - for (unsigned int i = 0; i < pScene->mNumCameras;++i) - { - aiCamera* cam = pScene->mCameras[i]; - const aiNode* nd = pScene->mRootNode->FindNode(cam->mName); - ai_assert(NULL != nd); - - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - cam->mPosition = nd->mTransformation * cam->mPosition; - cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt; - cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp; - } - - for (unsigned int i = 0; i < pScene->mNumLights;++i) - { - aiLight* l = pScene->mLights[i]; - const aiNode* nd = pScene->mRootNode->FindNode(l->mName); - ai_assert(NULL != nd); - - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - l->mPosition = nd->mTransformation * l->mPosition; - l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection; - l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp; - } - - if( !configKeepHierarchy ) { - - // now delete all nodes in the scene and build a new - // flat node graph with a root node and some level 1 children - aiNode* newRoot = new aiNode(); - newRoot->mName = pScene->mRootNode->mName; - delete pScene->mRootNode; - pScene->mRootNode = newRoot; - - if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) - { - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; - } - else - { - pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras; - aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; - - // generate mesh nodes - for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName = pScene->mMeshes[i]->mName; - - // setup mesh indices - pcNode->mNumMeshes = 1; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - } - // generate light nodes - for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i); - pScene->mLights[i]->mName = pcNode->mName; - } - // generate camera nodes - for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i); - pScene->mCameras[i]->mName = pcNode->mName; - } - } - } - else { - // ... and finally set the transformation matrix of all nodes to identity - MakeIdentityTransform(pScene->mRootNode); - } - - if (configNormalize) { - // compute the boundary of all meshes - aiVector3D min,max; - MinMaxChooser ()(min,max); - - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - min = std::min(m->mVertices[i],min); - max = std::max(m->mVertices[i],max); - } - } - - // find the dominant axis - aiVector3D d = max-min; - const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5); - - d = min + d * (ai_real)0.5; - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - m->mVertices[i] = (m->mVertices[i]-d)/div; - } - } - } - - // print statistics - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); - - ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", - CountNodes(pScene->mRootNode) ," output nodes)" ); - ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras." ); - ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); - } -} diff --git a/thirdparty/assimp/code/PostProcessing/PretransformVertices.h b/thirdparty/assimp/code/PostProcessing/PretransformVertices.h deleted file mode 100644 index b2982951e0dd..000000000000 --- a/thirdparty/assimp/code/PostProcessing/PretransformVertices.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -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 PretransformVertices.h - * @brief Defines a post processing step to pretransform all - * vertices in the scenegraph - */ -#ifndef AI_PRETRANSFORMVERTICES_H_INC -#define AI_PRETRANSFORMVERTICES_H_INC - -#include "Common/BaseProcess.h" - -#include - -#include -#include - -// Forward declarations -struct aiNode; - -class PretransformVerticesTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The PretransformVertices pre-transforms all vertices in the node tree - * and removes the whole graph. The output is a list of meshes, one for - * each material. -*/ -class ASSIMP_API PretransformVertices : public BaseProcess { -public: - PretransformVertices (); - ~PretransformVertices (); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Toggle the 'keep hierarchy' option - * @param keep true for keep configuration. - */ - void KeepHierarchy(bool keep) { - configKeepHierarchy = keep; - } - - // ------------------------------------------------------------------- - /** @brief Check whether 'keep hierarchy' is currently enabled. - * @return ... - */ - bool IsHierarchyKept() const { - return configKeepHierarchy; - } - -private: - // ------------------------------------------------------------------- - // Count the number of nodes - unsigned int CountNodes( aiNode* pcNode ); - - // ------------------------------------------------------------------- - // Get a bitwise combination identifying the vertex format of a mesh - unsigned int GetMeshVFormat(aiMesh* pcMesh); - - // ------------------------------------------------------------------- - // Count the number of vertices in the whole scene and a given - // material index - void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - unsigned int* piFaces, - unsigned int* piVertices); - - // ------------------------------------------------------------------- - // Collect vertex/face data - void CollectData( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - aiMesh* pcMeshOut, - unsigned int aiCurrent[2], - unsigned int* num_refs); - - // ------------------------------------------------------------------- - // Get a list of all vertex formats that occur for a given material - // The output list contains duplicate elements - void GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list& aiOut); - - // ------------------------------------------------------------------- - // Compute the absolute transformation matrices of each node - void ComputeAbsoluteTransform( aiNode* pcNode ); - - // ------------------------------------------------------------------- - // Simple routine to build meshes in worldspace, no further optimization - void BuildWCSMeshes(std::vector& out, aiMesh** in, - unsigned int numIn, aiNode* node); - - // ------------------------------------------------------------------- - // Apply the node transformation to a mesh - void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat); - - // ------------------------------------------------------------------- - // Reset transformation matrices to identity - void MakeIdentityTransform(aiNode* nd); - - // ------------------------------------------------------------------- - // Build reference counters for all meshes - void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); - - //! Configuration option: keep scene hierarchy as long as possible - bool configKeepHierarchy; - bool configNormalize; - bool configTransform; - aiMatrix4x4 configTransformation; - bool mConfigPointCloud; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp b/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp deleted file mode 100644 index 59869fdff781..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* -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 ProcessHelper.cpp -/** Implement shared utility functions for postprocessing steps */ - - -#include "ProcessHelper.h" - - -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------- -void ConvertListToStrings(const std::string& in, std::list& out) -{ - const char* s = in.c_str(); - while (*s) { - SkipSpacesAndLineEnd(&s); - if (*s == '\'') { - const char* base = ++s; - while (*s != '\'') { - ++s; - if (*s == '\0') { - ASSIMP_LOG_ERROR("ConvertListToString: String list is ill-formatted"); - return; - } - } - out.push_back(std::string(base,(size_t)(s-base))); - ++s; - } - else { - out.push_back(GetNextToken(s)); - } - } -} - -// ------------------------------------------------------------------------------- -void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, - const aiMatrix4x4& m) -{ - min = aiVector3D ( ai_real( 10e10 ), ai_real( 10e10 ), ai_real( 10e10 ) ); - max = aiVector3D ( ai_real( -10e10 ), ai_real( -10e10 ), ai_real( -10e10 ) ); - for (unsigned int i = 0;i < mesh->mNumVertices;++i) - { - const aiVector3D v = m * mesh->mVertices[i]; - min = std::min(v,min); - max = std::max(v,max); - } -} - -// ------------------------------------------------------------------------------- -void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max) -{ - ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max); - out = min + (max-min)*(ai_real)0.5; -} - -// ------------------------------------------------------------------------------- -void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) { - if ( NULL == scene ) { - return; - } - - if ( 0 == scene->mNumMeshes ) { - return; - } - FindMeshCenter(scene->mMeshes[0], out, min, max); - for (unsigned int i = 1; i < scene->mNumMeshes; ++i) { - aiVector3D tout, tmin, tmax; - FindMeshCenter(scene->mMeshes[i], tout, tmin, tmax); - if (min[0] > tmin[0]) min[0] = tmin[0]; - if (min[1] > tmin[1]) min[1] = tmin[1]; - if (min[2] > tmin[2]) min[2] = tmin[2]; - if (max[0] < tmax[0]) max[0] = tmax[0]; - if (max[1] < tmax[1]) max[1] = tmax[1]; - if (max[2] < tmax[2]) max[2] = tmax[2]; - } - out = min + (max-min)*(ai_real)0.5; -} - - -// ------------------------------------------------------------------------------- -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min, - aiVector3D& max, const aiMatrix4x4& m) -{ - FindAABBTransformed(mesh,min,max,m); - out = min + (max-min)*(ai_real)0.5; -} - -// ------------------------------------------------------------------------------- -void FindMeshCenter (aiMesh* mesh, aiVector3D& out) -{ - aiVector3D min,max; - FindMeshCenter(mesh,out,min,max); -} - -// ------------------------------------------------------------------------------- -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, - const aiMatrix4x4& m) -{ - aiVector3D min,max; - FindMeshCenterTransformed(mesh,out,min,max,m); -} - -// ------------------------------------------------------------------------------- -ai_real ComputePositionEpsilon(const aiMesh* pMesh) -{ - const ai_real epsilon = ai_real( 1e-4 ); - - // calculate the position bounds so we have a reliable epsilon to check position differences against - aiVector3D minVec, maxVec; - ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec); - return (maxVec - minVec).Length() * epsilon; -} - -// ------------------------------------------------------------------------------- -ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num) -{ - ai_assert( NULL != pMeshes ); - - const ai_real epsilon = ai_real( 1e-4 ); - - // calculate the position bounds so we have a reliable epsilon to check position differences against - aiVector3D minVec, maxVec, mi, ma; - MinMaxChooser()(minVec,maxVec); - - for (size_t a = 0; a < num; ++a) { - const aiMesh* pMesh = pMeshes[a]; - ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma); - - minVec = std::min(minVec,mi); - maxVec = std::max(maxVec,ma); - } - return (maxVec - minVec).Length() * epsilon; -} - - -// ------------------------------------------------------------------------------- -unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh) -{ - ai_assert(NULL != pcMesh); - - // FIX: the hash may never be 0. Otherwise a comparison against - // nullptr could be successful - unsigned int iRet = 1; - - // normals - if (pcMesh->HasNormals())iRet |= 0x2; - // tangents and bitangents - if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4; - -#ifdef BOOST_STATIC_ASSERT - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); -#endif - - // texture coordinates - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - { - iRet |= (0x100 << p); - if (3 == pcMesh->mNumUVComponents[p]) - iRet |= (0x10000 << p); - - ++p; - } - // vertex colors - p = 0; - while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++); - return iRet; -} - -// ------------------------------------------------------------------------------- -VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) -{ - if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) { - return NULL; - } - - VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; - for (unsigned int i = 0; i < pMesh->mNumBones;++i) { - - aiBone* bone = pMesh->mBones[i]; - for (unsigned int a = 0; a < bone->mNumWeights;++a) { - const aiVertexWeight& weight = bone->mWeights[a]; - avPerVertexWeights[weight.mVertexId].push_back( std::pair(i,weight.mWeight) ); - } - } - return avPerVertexWeights; -} - - -// ------------------------------------------------------------------------------- -const char* TextureTypeToString(aiTextureType in) -{ - switch (in) - { - case aiTextureType_NONE: - return "n/a"; - case aiTextureType_DIFFUSE: - return "Diffuse"; - case aiTextureType_SPECULAR: - return "Specular"; - case aiTextureType_AMBIENT: - return "Ambient"; - case aiTextureType_EMISSIVE: - return "Emissive"; - case aiTextureType_OPACITY: - return "Opacity"; - case aiTextureType_NORMALS: - return "Normals"; - case aiTextureType_HEIGHT: - return "Height"; - case aiTextureType_SHININESS: - return "Shininess"; - case aiTextureType_DISPLACEMENT: - return "Displacement"; - case aiTextureType_LIGHTMAP: - return "Lightmap"; - case aiTextureType_REFLECTION: - return "Reflection"; - case aiTextureType_UNKNOWN: - return "Unknown"; - default: - break; - } - - ai_assert(false); - return "BUG"; -} - -// ------------------------------------------------------------------------------- -const char* MappingTypeToString(aiTextureMapping in) -{ - switch (in) - { - case aiTextureMapping_UV: - return "UV"; - case aiTextureMapping_BOX: - return "Box"; - case aiTextureMapping_SPHERE: - return "Sphere"; - case aiTextureMapping_CYLINDER: - return "Cylinder"; - case aiTextureMapping_PLANE: - return "Plane"; - case aiTextureMapping_OTHER: - return "Other"; - default: - break; - } - - ai_assert(false); - return "BUG"; -} - - -// ------------------------------------------------------------------------------- -aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector &subMeshFaces, unsigned int subFlags) -{ - aiMesh *oMesh = new aiMesh(); - std::vector vMap(pMesh->mNumVertices,UINT_MAX); - - size_t numSubVerts = 0; - size_t numSubFaces = subMeshFaces.size(); - - for(unsigned int i=0;imFaces[subMeshFaces[i]]; - - for(unsigned int j=0;j(numSubVerts++); - } - } - } - - oMesh->mName = pMesh->mName; - - oMesh->mMaterialIndex = pMesh->mMaterialIndex; - oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; - - // create all the arrays for this mesh if the old mesh contained them - - oMesh->mNumFaces = static_cast(subMeshFaces.size()); - oMesh->mNumVertices = static_cast(numSubVerts); - oMesh->mVertices = new aiVector3D[numSubVerts]; - if( pMesh->HasNormals() ) { - oMesh->mNormals = new aiVector3D[numSubVerts]; - } - - if( pMesh->HasTangentsAndBitangents() ) { - oMesh->mTangents = new aiVector3D[numSubVerts]; - oMesh->mBitangents = new aiVector3D[numSubVerts]; - } - - for( size_t a = 0; pMesh->HasTextureCoords(static_cast(a)) ; ++a ) { - oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts]; - oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; - } - - for( size_t a = 0; pMesh->HasVertexColors( static_cast(a)); ++a ) { - oMesh->mColors[a] = new aiColor4D[numSubVerts]; - } - - // and copy over the data, generating faces with linear indices along the way - oMesh->mFaces = new aiFace[numSubFaces]; - - for(unsigned int a = 0; a < numSubFaces; ++a ) { - - const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; - aiFace& dstFace = oMesh->mFaces[a]; - dstFace.mNumIndices = srcFace.mNumIndices; - dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; - - // accumulate linearly all the vertices of the source face - for( size_t b = 0; b < dstFace.mNumIndices; ++b ) { - dstFace.mIndices[b] = vMap[srcFace.mIndices[b]]; - } - } - - for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) { - unsigned int nvi = vMap[srcIndex]; - if(nvi==UINT_MAX) { - continue; - } - - oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; - if( pMesh->HasNormals() ) { - oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; - } - - if( pMesh->HasTangentsAndBitangents() ) { - oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; - oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; - } - for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) { - oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; - } - for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) { - oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; - } - } - - if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) { - std::vector subBones(pMesh->mNumBones,0); - - for(unsigned int a=0;amNumBones;++a) { - const aiBone* bone = pMesh->mBones[a]; - - for(unsigned int b=0;bmNumWeights;b++) { - unsigned int v = vMap[bone->mWeights[b].mVertexId]; - - if(v!=UINT_MAX) { - subBones[a]++; - } - } - } - - for(unsigned int a=0;amNumBones;++a) { - if(subBones[a]>0) { - oMesh->mNumBones++; - } - } - - if(oMesh->mNumBones) { - oMesh->mBones = new aiBone*[oMesh->mNumBones](); - unsigned int nbParanoia = oMesh->mNumBones; - - oMesh->mNumBones = 0; //rewind - - for(unsigned int a=0;amNumBones;++a) { - if(subBones[a]==0) { - continue; - } - aiBone *newBone = new aiBone; - oMesh->mBones[oMesh->mNumBones++] = newBone; - - const aiBone* bone = pMesh->mBones[a]; - - newBone->mName = bone->mName; - newBone->mOffsetMatrix = bone->mOffsetMatrix; - newBone->mWeights = new aiVertexWeight[subBones[a]]; - - for(unsigned int b=0;bmNumWeights;b++) { - const unsigned int v = vMap[bone->mWeights[b].mVertexId]; - - if(v!=UINT_MAX) { - aiVertexWeight w(v,bone->mWeights[b].mWeight); - newBone->mWeights[newBone->mNumWeights++] = w; - } - } - } - - ai_assert(nbParanoia==oMesh->mNumBones); - (void)nbParanoia; // remove compiler warning on release build - } - } - - return oMesh; -} - -} // namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ProcessHelper.h b/thirdparty/assimp/code/PostProcessing/ProcessHelper.h deleted file mode 100644 index 0afcc4142066..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ProcessHelper.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -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 AI_PROCESS_HELPER_H_INCLUDED -#define AI_PROCESS_HELPER_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -#include -#include "Common/BaseProcess.h" -#include - -#include - -// ------------------------------------------------------------------------------- -// Some extensions to std namespace. Mainly std::min and std::max for all -// flat data types in the aiScene. They're used to quickly determine the -// min/max bounds of data arrays. -#ifdef __cplusplus -namespace std { - - // std::min for aiVector3D - template - inline ::aiVector3t min (const ::aiVector3t& a, const ::aiVector3t& b) { - return ::aiVector3t (min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); - } - - // std::max for aiVector3t - template - inline ::aiVector3t max (const ::aiVector3t& a, const ::aiVector3t& b) { - return ::aiVector3t (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); - } - - // std::min for aiVector2t - template - inline ::aiVector2t min (const ::aiVector2t& a, const ::aiVector2t& b) { - return ::aiVector2t (min(a.x,b.x),min(a.y,b.y)); - } - - // std::max for aiVector2t - template - inline ::aiVector2t max (const ::aiVector2t& a, const ::aiVector2t& b) { - return ::aiVector2t (max(a.x,b.x),max(a.y,b.y)); - } - - // std::min for aiColor4D - template - inline ::aiColor4t min (const ::aiColor4t& a, const ::aiColor4t& b) { - return ::aiColor4t (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a)); - } - - // std::max for aiColor4D - template - inline ::aiColor4t max (const ::aiColor4t& a, const ::aiColor4t& b) { - return ::aiColor4t (max(a.r,b.r),max(a.g,b.g),max(a.b,b.b),max(a.a,b.a)); - } - - - // std::min for aiQuaterniont - template - inline ::aiQuaterniont min (const ::aiQuaterniont& a, const ::aiQuaterniont& b) { - return ::aiQuaterniont (min(a.w,b.w),min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); - } - - // std::max for aiQuaterniont - template - inline ::aiQuaterniont max (const ::aiQuaterniont& a, const ::aiQuaterniont& b) { - return ::aiQuaterniont (max(a.w,b.w),max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); - } - - - - // std::min for aiVectorKey - inline ::aiVectorKey min (const ::aiVectorKey& a, const ::aiVectorKey& b) { - return ::aiVectorKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); - } - - // std::max for aiVectorKey - inline ::aiVectorKey max (const ::aiVectorKey& a, const ::aiVectorKey& b) { - return ::aiVectorKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); - } - - // std::min for aiQuatKey - inline ::aiQuatKey min (const ::aiQuatKey& a, const ::aiQuatKey& b) { - return ::aiQuatKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); - } - - // std::max for aiQuatKey - inline ::aiQuatKey max (const ::aiQuatKey& a, const ::aiQuatKey& b) { - return ::aiQuatKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); - } - - // std::min for aiVertexWeight - inline ::aiVertexWeight min (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { - return ::aiVertexWeight (min(a.mVertexId,b.mVertexId),min(a.mWeight,b.mWeight)); - } - - // std::max for aiVertexWeight - inline ::aiVertexWeight max (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { - return ::aiVertexWeight (max(a.mVertexId,b.mVertexId),max(a.mWeight,b.mWeight)); - } - -} // end namespace std -#endif // !! C++ - -namespace Assimp { - -// ------------------------------------------------------------------------------- -// Start points for ArrayBounds for all supported Ts -template -struct MinMaxChooser; - -template <> struct MinMaxChooser { - void operator ()(float& min,float& max) { - max = -1e10f; - min = 1e10f; -}}; -template <> struct MinMaxChooser { - void operator ()(double& min,double& max) { - max = -1e10; - min = 1e10; -}}; -template <> struct MinMaxChooser { - void operator ()(unsigned int& min,unsigned int& max) { - max = 0; - min = (1u<<(sizeof(unsigned int)*8-1)); -}}; - -template struct MinMaxChooser< aiVector3t > { - void operator ()(aiVector3t& min,aiVector3t& max) { - max = aiVector3t(-1e10f,-1e10f,-1e10f); - min = aiVector3t( 1e10f, 1e10f, 1e10f); -}}; -template struct MinMaxChooser< aiVector2t > { - void operator ()(aiVector2t& min,aiVector2t& max) { - max = aiVector2t(-1e10f,-1e10f); - min = aiVector2t( 1e10f, 1e10f); - }}; -template struct MinMaxChooser< aiColor4t > { - void operator ()(aiColor4t& min,aiColor4t& max) { - max = aiColor4t(-1e10f,-1e10f,-1e10f,-1e10f); - min = aiColor4t( 1e10f, 1e10f, 1e10f, 1e10f); -}}; - -template struct MinMaxChooser< aiQuaterniont > { - void operator ()(aiQuaterniont& min,aiQuaterniont& max) { - max = aiQuaterniont(-1e10f,-1e10f,-1e10f,-1e10f); - min = aiQuaterniont( 1e10f, 1e10f, 1e10f, 1e10f); -}}; - -template <> struct MinMaxChooser { - void operator ()(aiVectorKey& min,aiVectorKey& max) { - MinMaxChooser()(min.mTime,max.mTime); - MinMaxChooser()(min.mValue,max.mValue); -}}; -template <> struct MinMaxChooser { - void operator ()(aiQuatKey& min,aiQuatKey& max) { - MinMaxChooser()(min.mTime,max.mTime); - MinMaxChooser()(min.mValue,max.mValue); -}}; - -template <> struct MinMaxChooser { - void operator ()(aiVertexWeight& min,aiVertexWeight& max) { - MinMaxChooser()(min.mVertexId,max.mVertexId); - MinMaxChooser()(min.mWeight,max.mWeight); -}}; - -// ------------------------------------------------------------------------------- -/** @brief Find the min/max values of an array of Ts - * @param in Input array - * @param size Number of elements to process - * @param[out] min minimum value - * @param[out] max maximum value - */ -template -inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max) -{ - MinMaxChooser ()(min,max); - for (unsigned int i = 0; i < size;++i) { - min = std::min(in[i],min); - max = std::max(in[i],max); - } -} - - -// ------------------------------------------------------------------------------- -/** Little helper function to calculate the quadratic difference - * of two colours. - * @param pColor1 First color - * @param pColor2 second color - * @return Quadratic color difference */ -inline ai_real GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2) -{ - const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a); - return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a; -} - - -// ------------------------------------------------------------------------------- -/** @brief Extract single strings from a list of identifiers - * @param in Input string list. - * @param out Receives a list of clean output strings - * @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST */ -void ConvertListToStrings(const std::string& in, std::list& out); - - -// ------------------------------------------------------------------------------- -/** @brief Compute the AABB of a mesh after applying a given transform - * @param mesh Input mesh - * @param[out] min Receives minimum transformed vertex - * @param[out] max Receives maximum transformed vertex - * @param m Transformation matrix to be applied */ -void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -/** @brief Helper function to determine the 'real' center of a mesh - * - * That is the center of its axis-aligned bounding box. - * @param mesh Input mesh - * @param[out] min Minimum vertex of the mesh - * @param[out] max maximum vertex of the mesh - * @param[out] out Center point */ -void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max); - -// ------------------------------------------------------------------------------- -/** @brief Helper function to determine the 'real' center of a scene - * - * That is the center of its axis-aligned bounding box. - * @param scene Input scene - * @param[out] min Minimum vertex of the scene - * @param[out] max maximum vertex of the scene - * @param[out] out Center point */ -void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh after applying a given transform -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,aiVector3D& max, const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh -void FindMeshCenter (aiMesh* mesh, aiVector3D& out); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh after applying a given transform -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -// Compute a good epsilon value for position comparisons on a mesh -ai_real ComputePositionEpsilon(const aiMesh* pMesh); - - -// ------------------------------------------------------------------------------- -// Compute a good epsilon value for position comparisons on a array of meshes -ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num); - - -// ------------------------------------------------------------------------------- -// Compute an unique value for the vertex format of a mesh -unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh); - - -// defs for ComputeVertexBoneWeightTable() -typedef std::pair PerVertexWeight; -typedef std::vector VertexWeightTable; - -// ------------------------------------------------------------------------------- -// Compute a per-vertex bone weight table -VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh); - - -// ------------------------------------------------------------------------------- -// Get a string for a given aiTextureType -const char* TextureTypeToString(aiTextureType in); - - -// ------------------------------------------------------------------------------- -// Get a string for a given aiTextureMapping -const char* MappingTypeToString(aiTextureMapping in); - - -// flags for MakeSubmesh() -#define AI_SUBMESH_FLAGS_SANS_BONES 0x1 - -// ------------------------------------------------------------------------------- -// Split a mesh given a list of faces to be contained in the sub mesh -aiMesh* MakeSubmesh(const aiMesh *superMesh, const std::vector &subMeshFaces, unsigned int subFlags); - -// ------------------------------------------------------------------------------- -// Utility postprocess step to share the spatial sort tree between -// all steps which use it to speedup its computations. -class ComputeSpatialSortProcess : public BaseProcess -{ - bool IsActive( unsigned int pFlags) const - { - return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace | - aiProcess_GenNormals | aiProcess_JoinIdenticalVertices)); - } - - void Execute( aiScene* pScene) - { - typedef std::pair _Type; - ASSIMP_LOG_DEBUG("Generate spatially-sorted vertex cache"); - - std::vector<_Type>* p = new std::vector<_Type>(pScene->mNumMeshes); - std::vector<_Type>::iterator it = p->begin(); - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) { - aiMesh* mesh = pScene->mMeshes[i]; - _Type& blubb = *it; - blubb.first.Fill(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D)); - blubb.second = ComputePositionEpsilon(mesh); - } - - shared->AddProperty(AI_SPP_SPATIAL_SORT,p); - } -}; - -// ------------------------------------------------------------------------------- -// ... and the same again to cleanup the whole stuff -class DestroySpatialSortProcess : public BaseProcess -{ - bool IsActive( unsigned int pFlags) const - { - return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace | - aiProcess_GenNormals | aiProcess_JoinIdenticalVertices)); - } - - void Execute( aiScene* /*pScene*/) - { - shared->RemoveProperty(AI_SPP_SPATIAL_SORT); - } -}; - - - -} // ! namespace Assimp -#endif // !! AI_PROCESS_HELPER_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp b/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp deleted file mode 100644 index 49ec8f5c47c1..000000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 RemoveRedundantMaterials.cpp - * @brief Implementation of the "RemoveRedundantMaterials" post processing step -*/ - -// internal headers - -#include "RemoveRedundantMaterials.h" -#include -#include "ProcessHelper.h" -#include "Material/MaterialSystem.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() -: mConfigFixedMaterials() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup import properties -void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) -{ - // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST - mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void RemoveRedundantMatsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); - - unsigned int redundantRemoved = 0, unreferencedRemoved = 0; - if (pScene->mNumMaterials) - { - // Find out which materials are referenced by meshes - std::vector abReferenced(pScene->mNumMaterials,false); - for (unsigned int i = 0;i < pScene->mNumMeshes;++i) - abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; - - // If a list of materials to be excluded was given, match the list with - // our imported materials and 'salt' all positive matches to ensure that - // we get unique hashes later. - if (mConfigFixedMaterials.length()) { - - std::list strings; - ConvertListToStrings(mConfigFixedMaterials,strings); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - aiMaterial* mat = pScene->mMaterials[i]; - - aiString name; - mat->Get(AI_MATKEY_NAME,name); - - if (name.length) { - std::list::const_iterator it = std::find(strings.begin(), strings.end(), name.data); - if (it != strings.end()) { - - // Our brilliant 'salt': A single material property with ~ as first - // character to mark it as internal and temporary. - const int dummy = 1; - ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); - - // Keep this material even if no mesh references it - abReferenced[i] = true; - ASSIMP_LOG_DEBUG_F( "Found positive match in exclusion list: \'", name.data, "\'"); - } - } - } - } - - // TODO: re-implement this algorithm to work in-place - unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; - for ( unsigned int i=0; imNumMaterials; i++ ) { - aiMappingTable[ i ] = 0; - } - unsigned int iNewNum = 0; - - // Iterate through all materials and calculate a hash for them - // store all hashes in a list and so a quick search whether - // we do already have a specific hash. This allows us to - // determine which materials are identical. - uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { - // No mesh is referencing this material, remove it. - if (!abReferenced[i]) { - ++unreferencedRemoved; - delete pScene->mMaterials[i]; - pScene->mMaterials[i] = nullptr; - continue; - } - - // Check all previously mapped materials for a matching hash. - // On a match we can delete this material and just make it ref to the same index. - uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); - for (unsigned int a = 0; a < i;++a) - { - if (abReferenced[a] && me == aiHashes[a]) { - ++redundantRemoved; - me = 0; - aiMappingTable[i] = aiMappingTable[a]; - delete pScene->mMaterials[i]; - pScene->mMaterials[i] = nullptr; - break; - } - } - // This is a new material that is referenced, add to the map. - if (me) { - aiMappingTable[i] = iNewNum++; - } - } - // If the new material count differs from the original, - // we need to rebuild the material list and remap mesh material indexes. - if (iNewNum != pScene->mNumMaterials) { - ai_assert(iNewNum > 0); - aiMaterial** ppcMaterials = new aiMaterial*[iNewNum]; - ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); - for (unsigned int p = 0; p < pScene->mNumMaterials;++p) - { - // if the material is not referenced ... remove it - if (!abReferenced[p]) { - continue; - } - - // generate new names for modified materials that had no names - const unsigned int idx = aiMappingTable[p]; - if (ppcMaterials[idx]) { - aiString sz; - if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) { - sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p); - ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME); - } - } else { - ppcMaterials[idx] = pScene->mMaterials[p]; - } - } - // update all material indices - for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { - aiMesh* mesh = pScene->mMeshes[p]; - ai_assert( NULL!=mesh ); - mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; - } - // delete the old material list - delete[] pScene->mMaterials; - pScene->mMaterials = ppcMaterials; - pScene->mNumMaterials = iNewNum; - } - // delete temporary storage - delete[] aiHashes; - delete[] aiMappingTable; - } - if (redundantRemoved == 0 && unreferencedRemoved == 0) - { - ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); - } - else - { - ASSIMP_LOG_INFO_F("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ", - unreferencedRemoved, " unused materials."); - } -} diff --git a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h b/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h deleted file mode 100644 index 1f32a0abfb4e..000000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -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 RemoveRedundantMaterials.h - * @brief Defines a post processing step to remove redundant materials - */ -#ifndef AI_REMOVEREDUNDANTMATERIALS_H_INC -#define AI_REMOVEREDUNDANTMATERIALS_H_INC - -#include "Common/BaseProcess.h" -#include - -class RemoveRedundantMatsTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** RemoveRedundantMatsProcess: Post-processing step to remove redundant - * materials from the imported scene. - */ -class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { -public: - /// The default class constructor. - RemoveRedundantMatsProcess(); - - /// The class destructor. - ~RemoveRedundantMatsProcess(); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Set list of fixed (inmutable) materials - * @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST - */ - void SetFixedMaterialsString(const std::string& fixed = "") { - mConfigFixedMaterials = fixed; - } - - // ------------------------------------------------------------------- - /** @brief Get list of fixed (inmutable) materials - * @return See #AI_CONFIG_PP_RRM_EXCLUDE_LIST - */ - const std::string& GetFixedMaterialsString() const { - return mConfigFixedMaterials; - } - -private: - //! Configuration option: list of all fixed materials - std::string mConfigFixedMaterials; -}; - -} // end of namespace Assimp - -#endif // !!AI_REMOVEREDUNDANTMATERIALS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp b/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp deleted file mode 100644 index 99fd47a3aa1c..000000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the post processing step to remove - * any parts of the mesh structure from the imported data. -*/ - - -#include "RemoveVCProcess.h" -#include -#include -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -RemoveVCProcess::RemoveVCProcess() : - configDeleteFlags() - , mScene() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveVCProcess::~RemoveVCProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool RemoveVCProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_RemoveComponent) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Small helper function to delete all elements in a T** aray using delete -template -inline void ArrayDelete(T**& in, unsigned int& num) -{ - for (unsigned int i = 0; i < num; ++i) - delete in[i]; - - delete[] in; - in = NULL; - num = 0; -} - -#if 0 -// ------------------------------------------------------------------------------------------------ -// Updates the node graph - removes all nodes which have the "remove" flag set and the -// "don't remove" flag not set. Nodes with meshes are never deleted. -bool UpdateNodeGraph(aiNode* node,std::list& childsOfParent,bool root) -{ - bool b = false; - - std::list mine; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - if(UpdateNodeGraph(node->mChildren[i],mine,false)) - b = true; - } - - // somewhat tricky ... mNumMeshes must be originally 0 and MSB2 may not be set, - // so we can do a simple comparison against MSB here - if (!root && AI_RC_UINT_MSB == node->mNumMeshes ) - { - // this node needs to be removed - if(node->mNumChildren) - { - childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end()); - - // set all children to NULL to make sure they are not deleted when we delete ourself - for (unsigned int i = 0; i < node->mNumChildren;++i) - node->mChildren[i] = NULL; - } - b = true; - delete node; - } - else - { - AI_RC_UNMASK(node->mNumMeshes); - childsOfParent.push_back(node); - - if (b) - { - // reallocate the array of our children here - node->mNumChildren = (unsigned int)mine.size(); - aiNode** const children = new aiNode*[mine.size()]; - aiNode** ptr = children; - - for (std::list::iterator it = mine.begin(), end = mine.end(); - it != end; ++it) - { - *ptr++ = *it; - } - delete[] node->mChildren; - node->mChildren = children; - return false; - } - } - return b; -} -#endif - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void RemoveVCProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("RemoveVCProcess begin"); - bool bHas = false; //,bMasked = false; - - mScene = pScene; - - // handle animations - if ( configDeleteFlags & aiComponent_ANIMATIONS) - { - - bHas = true; - ArrayDelete(pScene->mAnimations,pScene->mNumAnimations); - } - - // handle textures - if ( configDeleteFlags & aiComponent_TEXTURES) - { - bHas = true; - ArrayDelete(pScene->mTextures,pScene->mNumTextures); - } - - // handle materials - if ( configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials) - { - bHas = true; - for (unsigned int i = 1;i < pScene->mNumMaterials;++i) - delete pScene->mMaterials[i]; - - pScene->mNumMaterials = 1; - aiMaterial* helper = (aiMaterial*) pScene->mMaterials[0]; - ai_assert(NULL != helper); - helper->Clear(); - - // gray - aiColor3D clr(0.6f,0.6f,0.6f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); - - // add a small ambient color value - clr = aiColor3D(0.05f,0.05f,0.05f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); - - aiString s; - s.Set("Dummy_MaterialsRemoved"); - helper->AddProperty(&s,AI_MATKEY_NAME); - } - - // handle light sources - if ( configDeleteFlags & aiComponent_LIGHTS) - { - bHas = true; - ArrayDelete(pScene->mLights,pScene->mNumLights); - } - - // handle camneras - if ( configDeleteFlags & aiComponent_CAMERAS) - { - bHas = true; - ArrayDelete(pScene->mCameras,pScene->mNumCameras); - } - - // handle meshes - if (configDeleteFlags & aiComponent_MESHES) - { - bHas = true; - ArrayDelete(pScene->mMeshes,pScene->mNumMeshes); - } - else - { - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if( ProcessMesh( pScene->mMeshes[a])) - bHas = true; - } - } - - - // now check whether the result is still a full scene - if (!pScene->mNumMeshes || !pScene->mNumMaterials) - { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - ASSIMP_LOG_DEBUG("Setting AI_SCENE_FLAGS_INCOMPLETE flag"); - - // If we have no meshes anymore we should also clear another flag ... - if (!pScene->mNumMeshes) - pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - } - - if (bHas) { - ASSIMP_LOG_INFO("RemoveVCProcess finished. Data structure cleanup has been done."); - } else { - ASSIMP_LOG_DEBUG("RemoveVCProcess finished. Nothing to be done ..."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties for the step -void RemoveVCProcess::SetupProperties(const Importer* pImp) -{ - configDeleteFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,0x0); - if (!configDeleteFlags) - { - ASSIMP_LOG_WARN("RemoveVCProcess: AI_CONFIG_PP_RVC_FLAGS is zero."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh) -{ - bool ret = false; - - // if all materials have been deleted let the material - // index of the mesh point to the created default material - if ( configDeleteFlags & aiComponent_MATERIALS) - pMesh->mMaterialIndex = 0; - - // handle normals - if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals) - { - delete[] pMesh->mNormals; - pMesh->mNormals = NULL; - ret = true; - } - - // handle tangents and bitangents - if (configDeleteFlags & aiComponent_TANGENTS_AND_BITANGENTS && pMesh->mTangents) - { - delete[] pMesh->mTangents; - pMesh->mTangents = NULL; - - delete[] pMesh->mBitangents; - pMesh->mBitangents = NULL; - ret = true; - } - - // handle texture coordinates - bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS)); - for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real) - { - if (!pMesh->mTextureCoords[i])break; - if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b) - { - delete [] pMesh->mTextureCoords[i]; - pMesh->mTextureCoords[i] = NULL; - ret = true; - - if (!b) - { - // collapse the rest of the array - for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) - pMesh->mTextureCoords[a-1] = pMesh->mTextureCoords[a]; - - pMesh->mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS-1] = NULL; - continue; - } - } - ++i; - } - - // handle vertex colors - b = (0 != (configDeleteFlags & aiComponent_COLORS)); - for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_COLOR_SETS; ++real) - { - if (!pMesh->mColors[i])break; - if (configDeleteFlags & aiComponent_COLORSn(i) || b) - { - delete [] pMesh->mColors[i]; - pMesh->mColors[i] = NULL; - ret = true; - - if (!b) - { - // collapse the rest of the array - for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) - pMesh->mColors[a-1] = pMesh->mColors[a]; - - pMesh->mColors[AI_MAX_NUMBER_OF_COLOR_SETS-1] = NULL; - continue; - } - } - ++i; - } - - // handle bones - if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones) - { - ArrayDelete(pMesh->mBones,pMesh->mNumBones); - ret = true; - } - return ret; -} diff --git a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h b/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h deleted file mode 100644 index 7bb21a83307e..000000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -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 Defines a post processing step to remove specific parts of the scene */ -#ifndef AI_REMOVEVCPROCESS_H_INCLUDED -#define AI_REMOVEVCPROCESS_H_INCLUDED - -#include "Common/BaseProcess.h" - -#include - -class RemoveVCProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** RemoveVCProcess: Class to exclude specific parts of the data structure - * from further processing by removing them, -*/ -class ASSIMP_API RemoveVCProcess : public BaseProcess { -public: - /// The default class constructor. - RemoveVCProcess(); - - /// The class destructor. - ~RemoveVCProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Manually setup the configuration flags for the step - * - * @param Bitwise combination of the #aiComponent enumerated values. - */ - void SetDeleteFlags(unsigned int f) - { - configDeleteFlags = f; - } - - // ------------------------------------------------------------------- - /** Query the current configuration. - */ - unsigned int GetDeleteFlags() const - { - return configDeleteFlags; - } - -private: - - bool ProcessMesh (aiMesh* pcMesh); - - /** Configuration flag - */ - unsigned int configDeleteFlags; - - /** The scene we're working with - */ - aiScene* mScene; -}; - -// --------------------------------------------------------------------------- - -} // end of namespace Assimp - -#endif // !!AI_REMOVEVCPROCESS_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp b/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp deleted file mode 100644 index ac770c41f2b9..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ -#include "ScaleProcess.h" - -#include -#include -#include - -namespace Assimp { - -ScaleProcess::ScaleProcess() -: BaseProcess() -, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { -} - -ScaleProcess::~ScaleProcess() { - // empty -} - -void ScaleProcess::setScale( ai_real scale ) { - mScale = scale; -} - -ai_real ScaleProcess::getScale() const { - return mScale; -} - -bool ScaleProcess::IsActive( unsigned int pFlags ) const { - return ( pFlags & aiProcess_GlobalScale ) != 0; -} - -void ScaleProcess::SetupProperties( const Importer* pImp ) { - // User scaling - mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); - - // File scaling * Application Scaling - float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f ); - - // apply scale to the scale - // helps prevent bugs with backward compatibility for anyone using normal scaling. - mScale *= importerScale; -} - -void ScaleProcess::Execute( aiScene* pScene ) { - if(mScale == 1.0f) { - return; // nothing to scale - } - - ai_assert( mScale != 0 ); - ai_assert( nullptr != pScene ); - ai_assert( nullptr != pScene->mRootNode ); - - if ( nullptr == pScene ) { - return; - } - - if ( nullptr == pScene->mRootNode ) { - return; - } - - // Process animations and update position transform to new unit system - for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) - { - aiAnimation* animation = pScene->mAnimations[animationID]; - - for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) - { - aiNodeAnim* anim = animation->mChannels[animationChannel]; - - for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) - { - aiVectorKey& vectorKey = anim->mPositionKeys[posKey]; - vectorKey.mValue *= mScale; - } - } - } - - for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) - { - aiMesh *mesh = pScene->mMeshes[meshID]; - - // Reconstruct mesh vertexes to the new unit system - for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) - { - aiVector3D& vertex = mesh->mVertices[vertexID]; - vertex *= mScale; - } - - - // bone placement / scaling - for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) - { - // Reconstruct matrix by transform rather than by scale - // This prevent scale values being changed which can - // be meaningful in some cases - // like when you want the modeller to see 1:1 compatibility. - aiBone* bone = mesh->mBones[boneID]; - - aiVector3D pos, scale; - aiQuaternion rotation; - - bone->mOffsetMatrix.Decompose( scale, rotation, pos); - - aiMatrix4x4 translation; - aiMatrix4x4::Translation( pos * mScale, translation ); - - aiMatrix4x4 scaling; - aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); - - aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); - - bone->mOffsetMatrix = translation * RotMatrix * scaling; - } - - - // animation mesh processing - // convert by position rather than scale. - for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) - { - aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID]; - - for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) - { - aiVector3D& vertex = animMesh->mVertices[vertexID]; - vertex *= mScale; - } - } - } - - traverseNodes( pScene->mRootNode ); -} - -void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { - applyScaling( node ); - - for( size_t i = 0; i < node->mNumChildren; i++) - { - // recurse into the tree until we are done! - traverseNodes( node->mChildren[i], nested_node_id+1 ); - } -} - -void ScaleProcess::applyScaling( aiNode *currentNode ) { - if ( nullptr != currentNode ) { - // Reconstruct matrix by transform rather than by scale - // This prevent scale values being changed which can - // be meaningful in some cases - // like when you want the modeller to - // see 1:1 compatibility. - - aiVector3D pos, scale; - aiQuaternion rotation; - currentNode->mTransformation.Decompose( scale, rotation, pos); - - aiMatrix4x4 translation; - aiMatrix4x4::Translation( pos * mScale, translation ); - - aiMatrix4x4 scaling; - - // note: we do not use mScale here, this is on purpose. - aiMatrix4x4::Scaling( scale, scaling ); - - aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); - - currentNode->mTransformation = translation * RotMatrix * scaling; - } -} - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ScaleProcess.h b/thirdparty/assimp/code/PostProcessing/ScaleProcess.h deleted file mode 100644 index 468a216736b4..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ScaleProcess.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -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 SCALE_PROCESS_H_ -#define SCALE_PROCESS_H_ - -#include "Common/BaseProcess.h" - -struct aiNode; - -#if (!defined AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT) -# define AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT 1.0f -#endif // !! AI_DEBONE_THRESHOLD - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** ScaleProcess: Class to rescale the whole model. - * Now rescales animations, bones, and blend shapes properly. - * Please note this will not write to 'scale' transform it will rewrite mesh - * and matrixes so that your scale values - * from your model package are preserved, so this is completely intentional - * bugs should be reported as soon as they are found. -*/ -class ASSIMP_API ScaleProcess : public BaseProcess { -public: - /// The default class constructor. - ScaleProcess(); - - /// The class destructor. - virtual ~ScaleProcess(); - - /// Will set the scale manually. - void setScale( ai_real scale ); - - /// Returns the current scaling value. - ai_real getScale() const; - - /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); - - /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); - -private: - void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); - void applyScaling( aiNode *currentNode ); - -private: - ai_real mScale; -}; - -} // Namespace Assimp - - -#endif // SCALE_PROCESS_H_ \ No newline at end of file diff --git a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp b/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp deleted file mode 100644 index be8405a17b49..000000000000 --- a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Implementation of the DeterminePTypeHelperProcess and - * SortByPTypeProcess post-process steps. -*/ - - - -// internal headers -#include "ProcessHelper.h" -#include "SortByPTypeProcess.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -SortByPTypeProcess::SortByPTypeProcess() -: mConfigRemoveMeshes( 0 ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -SortByPTypeProcess::~SortByPTypeProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SortByPTypeProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_SortByPType) != 0; -} - -// ------------------------------------------------------------------------------------------------ -void SortByPTypeProcess::SetupProperties(const Importer* pImp) -{ - mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,0); -} - -// ------------------------------------------------------------------------------------------------ -// Update changed meshes in all nodes -void UpdateNodes(const std::vector& replaceMeshIndex, aiNode* node) -{ - if (node->mNumMeshes) - { - unsigned int newSize = 0; - for (unsigned int m = 0; m< node->mNumMeshes; ++m) - { - unsigned int add = node->mMeshes[m]<<2; - for (unsigned int i = 0; i < 4;++i) - { - if (UINT_MAX != replaceMeshIndex[add+i])++newSize; - } - } - if (!newSize) - { - delete[] node->mMeshes; - node->mNumMeshes = 0; - node->mMeshes = NULL; - } - else - { - // Try to reuse the old array if possible - unsigned int* newMeshes = (newSize > node->mNumMeshes - ? new unsigned int[newSize] : node->mMeshes); - - for (unsigned int m = 0; m< node->mNumMeshes; ++m) - { - unsigned int add = node->mMeshes[m]<<2; - for (unsigned int i = 0; i < 4;++i) - { - if (UINT_MAX != replaceMeshIndex[add+i]) - *newMeshes++ = replaceMeshIndex[add+i]; - } - } - if (newSize > node->mNumMeshes) - delete[] node->mMeshes; - - node->mMeshes = newMeshes-(node->mNumMeshes = newSize); - } - } - - // call all subnodes recursively - for (unsigned int m = 0; m < node->mNumChildren; ++m) - UpdateNodes(replaceMeshIndex,node->mChildren[m]); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SortByPTypeProcess::Execute( aiScene* pScene) { - if ( 0 == pScene->mNumMeshes) { - ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes"); - return; - } - - ASSIMP_LOG_DEBUG("SortByPTypeProcess begin"); - - unsigned int aiNumMeshesPerPType[4] = {0,0,0,0}; - - std::vector outMeshes; - outMeshes.reserve(pScene->mNumMeshes<<1u); - - bool bAnyChanges = false; - - std::vector replaceMeshIndex(pScene->mNumMeshes*4,UINT_MAX); - std::vector::iterator meshIdx = replaceMeshIndex.begin(); - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - aiMesh* const mesh = pScene->mMeshes[i]; - ai_assert(0 != mesh->mPrimitiveTypes); - - // if there's just one primitive type in the mesh there's nothing to do for us - unsigned int num = 0; - if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) { - ++aiNumMeshesPerPType[0]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) { - ++aiNumMeshesPerPType[1]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) { - ++aiNumMeshesPerPType[2]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) { - ++aiNumMeshesPerPType[3]; - ++num; - } - - if (1 == num) { - if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { - *meshIdx = static_cast( outMeshes.size() ); - outMeshes.push_back(mesh); - } else { - delete mesh; - pScene->mMeshes[ i ] = nullptr; - bAnyChanges = true; - } - - meshIdx += 4; - continue; - } - bAnyChanges = true; - - // reuse our current mesh arrays for the submesh - // with the largest number of primitives - unsigned int aiNumPerPType[4] = {0,0,0,0}; - aiFace* pFirstFace = mesh->mFaces; - aiFace* const pLastFace = pFirstFace + mesh->mNumFaces; - - unsigned int numPolyVerts = 0; - for (;pFirstFace != pLastFace; ++pFirstFace) { - if (pFirstFace->mNumIndices <= 3) - ++aiNumPerPType[pFirstFace->mNumIndices-1]; - else - { - ++aiNumPerPType[3]; - numPolyVerts += pFirstFace-> mNumIndices; - } - } - - VertexWeightTable* avw = ComputeVertexBoneWeightTable(mesh); - for (unsigned int real = 0; real < 4; ++real,++meshIdx) - { - if ( !aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) - { - continue; - } - - *meshIdx = (unsigned int) outMeshes.size(); - outMeshes.push_back(new aiMesh()); - aiMesh* out = outMeshes.back(); - - // the name carries the adjacency information between the meshes - out->mName = mesh->mName; - - // copy data members - out->mPrimitiveTypes = 1u << real; - out->mMaterialIndex = mesh->mMaterialIndex; - - // allocate output storage - out->mNumFaces = aiNumPerPType[real]; - aiFace* outFaces = out->mFaces = new aiFace[out->mNumFaces]; - - out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real+1)); - - aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr); - aiVector3D *uv [AI_MAX_NUMBER_OF_TEXTURECOORDS]; - aiColor4D *cols [AI_MAX_NUMBER_OF_COLOR_SETS]; - - if (mesh->mVertices) { - vert = out->mVertices = new aiVector3D[out->mNumVertices]; - } - - if (mesh->mNormals) { - nor = out->mNormals = new aiVector3D[out->mNumVertices]; - } - - if (mesh->mTangents) { - tan = out->mTangents = new aiVector3D[out->mNumVertices]; - bit = out->mBitangents = new aiVector3D[out->mNumVertices]; - } - - for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS;++j) { - uv[j] = nullptr; - if (mesh->mTextureCoords[j]) { - uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices]; - } - - out->mNumUVComponents[j] = mesh->mNumUVComponents[j]; - } - - for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS;++j) { - cols[j] = nullptr; - if (mesh->mColors[j]) { - cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices]; - } - } - - typedef std::vector< aiVertexWeight > TempBoneInfo; - std::vector< TempBoneInfo > tempBones(mesh->mNumBones); - - // try to guess how much storage we'll need - for (unsigned int q = 0; q < mesh->mNumBones;++q) - { - tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num-1)); - } - - unsigned int outIdx = 0; - for (unsigned int m = 0; m < mesh->mNumFaces; ++m) - { - aiFace& in = mesh->mFaces[m]; - if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real+1)) - { - continue; - } - - outFaces->mNumIndices = in.mNumIndices; - outFaces->mIndices = in.mIndices; - - for (unsigned int q = 0; q < in.mNumIndices; ++q) - { - unsigned int idx = in.mIndices[q]; - - // process all bones of this index - if (avw) - { - VertexWeightTable& tbl = avw[idx]; - for (VertexWeightTable::const_iterator it = tbl.begin(), end = tbl.end(); - it != end; ++it) - { - tempBones[ (*it).first ].push_back( aiVertexWeight(outIdx, (*it).second) ); - } - } - - if (vert) - { - *vert++ = mesh->mVertices[idx]; - //mesh->mVertices[idx].x = get_qnan(); - } - if (nor )*nor++ = mesh->mNormals[idx]; - if (tan ) - { - *tan++ = mesh->mTangents[idx]; - *bit++ = mesh->mBitangents[idx]; - } - - for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) - { - if (!uv[pp])break; - *uv[pp]++ = mesh->mTextureCoords[pp][idx]; - } - - for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) - { - if (!cols[pp])break; - *cols[pp]++ = mesh->mColors[pp][idx]; - } - - in.mIndices[q] = outIdx++; - } - - in.mIndices = nullptr; - ++outFaces; - } - ai_assert(outFaces == out->mFaces + out->mNumFaces); - - // now generate output bones - for (unsigned int q = 0; q < mesh->mNumBones;++q) - if (!tempBones[q].empty())++out->mNumBones; - - if (out->mNumBones) - { - out->mBones = new aiBone*[out->mNumBones]; - for (unsigned int q = 0, real = 0; q < mesh->mNumBones;++q) - { - TempBoneInfo& in = tempBones[q]; - if (in.empty())continue; - - aiBone* srcBone = mesh->mBones[q]; - aiBone* bone = out->mBones[real] = new aiBone(); - - bone->mName = srcBone->mName; - bone->mOffsetMatrix = srcBone->mOffsetMatrix; - - bone->mNumWeights = (unsigned int)in.size(); - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - - ::memcpy(bone->mWeights,&in[0],bone->mNumWeights*sizeof(aiVertexWeight)); - - ++real; - } - } - } - - // delete the per-vertex bone weights table - delete[] avw; - - // delete the input mesh - delete mesh; - - // avoid invalid pointer - pScene->mMeshes[i] = NULL; - } - - if (outMeshes.empty()) - { - // This should not occur - throw DeadlyImportError("No meshes remaining"); - } - - // If we added at least one mesh process all nodes in the node - // graph and update their respective mesh indices. - if (bAnyChanges) - { - UpdateNodes(replaceMeshIndex,pScene->mRootNode); - } - - if (outMeshes.size() != pScene->mNumMeshes) - { - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)outMeshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - } - ::memcpy(pScene->mMeshes,&outMeshes[0],pScene->mNumMeshes*sizeof(void*)); - - if (!DefaultLogger::isNullLogger()) - { - char buffer[1024]; - ::ai_snprintf(buffer,1024,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)", - aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""), - aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""), - aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""), - aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : "")); - ASSIMP_LOG_INFO(buffer); - ASSIMP_LOG_DEBUG("SortByPTypeProcess finished"); - } -} - diff --git a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h b/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h deleted file mode 100644 index 1d7ccfc15240..000000000000 --- a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -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 Defines a post processing step to sort meshes by the types - of primitives they contain */ -#ifndef AI_SORTBYPTYPEPROCESS_H_INC -#define AI_SORTBYPTYPEPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include - -class SortByPTypeProcessTest; - -namespace Assimp { - - -// --------------------------------------------------------------------------- -/** SortByPTypeProcess: Sorts meshes by the types of primitives they contain. - * A mesh with 5 lines, 3 points and 145 triangles would be split in 3 - * submeshes. -*/ -class ASSIMP_API SortByPTypeProcess : public BaseProcess { -public: - SortByPTypeProcess(); - ~SortByPTypeProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - -private: - int mConfigRemoveMeshes; -}; - - -} // end of namespace Assimp - -#endif // !!AI_SORTBYPTYPEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp b/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp deleted file mode 100644 index 1797b28d5ac4..000000000000 --- a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* -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 Implementation of the SplitLargeMeshes postprocessing step - */ - -// internal headers of the post-processing framework -#include "SplitLargeMeshes.h" -#include "ProcessHelper.h" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() { - LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_SplitLargeMeshes) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) { - if (0xffffffff == this->LIMIT || nullptr == pScene ) { - return; - } - - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin"); - std::vector > avList; - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - this->SplitMesh(a, pScene->mMeshes[a],avList); - } - - if (avList.size() != pScene->mNumMeshes) { - // it seems something has been split. rebuild the mesh list - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)avList.size(); - pScene->mMeshes = new aiMesh*[avList.size()]; - - for (unsigned int i = 0; i < avList.size();++i) { - pScene->mMeshes[i] = avList[i].first; - } - - // now we need to update all nodes - this->UpdateNode(pScene->mRootNode,avList); - ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); - } else { - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) { - // get the current value of the split property - this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); -} - -// ------------------------------------------------------------------------------------------------ -// Update a node after some meshes have been split -void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, - const std::vector >& avList) { - // for every index in out list build a new entry - std::vector aiEntries; - aiEntries.reserve(pcNode->mNumMeshes + 1); - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) { - for (unsigned int a = 0; a < avList.size();++a) { - if (avList[a].second == pcNode->mMeshes[i]) { - aiEntries.push_back(a); - } - } - } - - // now build the new list - delete[] pcNode->mMeshes; - pcNode->mNumMeshes = (unsigned int)aiEntries.size(); - pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; - - for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) { - pcNode->mMeshes[b] = aiEntries[b]; - } - - // recusively update all other nodes - for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { - UpdateNode ( pcNode->mChildren[i], avList ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Triangle::SplitMesh( - unsigned int a, - aiMesh* pMesh, - std::vector >& avList) { - if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) { - ASSIMP_LOG_INFO("Mesh exceeds the triangle limit. It will be split ..."); - - // we need to split this mesh into sub meshes - // determine the size of a submesh - const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1; - - const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes; - const unsigned int iOutVertexNum = iOutFaceNum * 3; - - // now generate all submeshes - for (unsigned int i = 0; i < iSubMeshes;++i) { - aiMesh* pcMesh = new aiMesh; - pcMesh->mNumFaces = iOutFaceNum; - pcMesh->mMaterialIndex = pMesh->mMaterialIndex; - - // the name carries the adjacency information between the meshes - pcMesh->mName = pMesh->mName; - - if (i == iSubMeshes-1) { - pcMesh->mNumFaces = iOutFaceNum + ( - pMesh->mNumFaces - iOutFaceNum * iSubMeshes); - } - // copy the list of faces - pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; - - const unsigned int iBase = iOutFaceNum * i; - - // get the total number of indices - unsigned int iCnt = 0; - for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p) { - iCnt += pMesh->mFaces[p].mNumIndices; - } - pcMesh->mNumVertices = iCnt; - - // allocate storage - if (pMesh->mVertices != nullptr) { - pcMesh->mVertices = new aiVector3D[iCnt]; - } - - if (pMesh->HasNormals()) { - pcMesh->mNormals = new aiVector3D[iCnt]; - } - - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents = new aiVector3D[iCnt]; - pcMesh->mBitangents = new aiVector3D[iCnt]; - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; - if (pMesh->HasTextureCoords( c)) { - pcMesh->mTextureCoords[c] = new aiVector3D[iCnt]; - } - } - - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c] = new aiColor4D[iCnt]; - } - } - - if (pMesh->HasBones()) { - // assume the number of bones won't change in most cases - pcMesh->mBones = new aiBone*[pMesh->mNumBones]; - - // iterate through all bones of the mesh and find those which - // need to be copied to the split mesh - std::vector avTempWeights; - for (unsigned int p = 0; p < pcMesh->mNumBones;++p) { - aiBone* const bone = pcMesh->mBones[p]; - avTempWeights.clear(); - avTempWeights.reserve(bone->mNumWeights / iSubMeshes); - - for (unsigned int q = 0; q < bone->mNumWeights;++q) { - aiVertexWeight& weight = bone->mWeights[q]; - if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum) { - avTempWeights.push_back(weight); - weight = avTempWeights.back(); - weight.mVertexId -= iBase; - } - } - - if (!avTempWeights.empty()) { - // we'll need this bone. Copy it ... - aiBone* pc = new aiBone(); - pcMesh->mBones[pcMesh->mNumBones++] = pc; - pc->mName = aiString(bone->mName); - pc->mNumWeights = (unsigned int)avTempWeights.size(); - pc->mOffsetMatrix = bone->mOffsetMatrix; - - // no need to reallocate the array for the last submesh. - // Here we can reuse the (large) source array, although - // we'll waste some memory - if (iSubMeshes-1 == i) { - pc->mWeights = bone->mWeights; - bone->mWeights = nullptr; - } else { - pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - } - - // copy the weights - ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights); - } - } - } - - // (we will also need to copy the array of indices) - unsigned int iCurrent = 0; - for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) { - pcMesh->mFaces[p].mNumIndices = 3; - // allocate a new array - const unsigned int iTemp = p + iBase; - const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices; - - // setup face type and number of indices - pcMesh->mFaces[p].mNumIndices = iNumIndices; - unsigned int* pi = pMesh->mFaces[iTemp].mIndices; - unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices]; - - // need to update the output primitive types - switch (iNumIndices) { - case 1: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - } - - // and copy the contents of the old array, offset by current base - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pi[v]; - unsigned int iIndexOut = iCurrent++; - piOut[v] = iIndexOut; - - // copy positions - if (pMesh->mVertices != nullptr) { - pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex]; - } - - // copy normals - if (pMesh->HasNormals()) { - pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex]; - } - - // copy tangents/bitangents - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex]; - pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex]; - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (pMesh->HasTextureCoords( c ) ) { - pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex]; - } - } - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex]; - } - } - } - } - - // add the newly created mesh to the list - avList.push_back(std::pair(pcMesh,a)); - } - - // now delete the old mesh data - delete pMesh; - } else { - avList.push_back(std::pair(pMesh,a)); - } -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() { - LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_SplitLargeMeshes) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) { - if (0xffffffff == this->LIMIT || nullptr == pScene ) { - return; - } - - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin"); - - std::vector > avList; - - //Check for point cloud first, - //Do not process point cloud, splitMesh works only with faces data - for (unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) { - return; - } - } - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - this->SplitMesh(a, pScene->mMeshes[a], avList); - } - - if (avList.size() != pScene->mNumMeshes) { - // it seems something has been split. rebuild the mesh list - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)avList.size(); - pScene->mMeshes = new aiMesh*[avList.size()]; - - for (unsigned int i = 0; i < avList.size();++i) { - pScene->mMeshes[i] = avList[i].first; - } - - // now we need to update all nodes - SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList); - ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Vertex finished. Meshes have been split"); - } else { - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) { - this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Vertex::SplitMesh( - unsigned int a, - aiMesh* pMesh, - std::vector >& avList) { - if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) { - typedef std::vector< std::pair > VertexWeightTable; - - // build a per-vertex weight list if necessary - VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh); - - // we need to split this mesh into sub meshes - // determine the estimated size of a submesh - // (this could be too large. Max waste is a single digit percentage) - const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1; - - // create a std::vector to indicate which vertices - // have already been copied - std::vector avWasCopied; - avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF); - - // try to find a good estimate for the number of output faces - // per mesh. Add 12.5% as buffer - unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes; - iEstimatedSize += iEstimatedSize >> 3; - - // now generate all submeshes - unsigned int iBase( 0 ); - while (true) { - const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT; - aiMesh* pcMesh = new aiMesh; - pcMesh->mNumVertices = 0; - pcMesh->mMaterialIndex = pMesh->mMaterialIndex; - - // the name carries the adjacency information between the meshes - pcMesh->mName = pMesh->mName; - - typedef std::vector BoneWeightList; - if (pMesh->HasBones()) { - pcMesh->mBones = new aiBone*[pMesh->mNumBones]; - ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones); - } - - // clear the temporary helper array - if (iBase) { - // we can't use memset here we unsigned int needn' be 32 bits - for (auto &elem : avWasCopied) { - elem = 0xffffffff; - } - } - - // output vectors - std::vector vFaces; - - // reserve enough storage for most cases - if (pMesh->HasPositions()) { - pcMesh->mVertices = new aiVector3D[iOutVertexNum]; - } - if (pMesh->HasNormals()) { - pcMesh->mNormals = new aiVector3D[iOutVertexNum]; - } - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents = new aiVector3D[iOutVertexNum]; - pcMesh->mBitangents = new aiVector3D[iOutVertexNum]; - } - for (unsigned int c = 0; pMesh->HasVertexColors(c);++c) { - pcMesh->mColors[c] = new aiColor4D[iOutVertexNum]; - } - for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c) { - pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; - pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum]; - } - vFaces.reserve(iEstimatedSize); - - // (we will also need to copy the array of indices) - while (iBase < pMesh->mNumFaces) { - // allocate a new array - const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices; - - // doesn't catch degenerates but is quite fast - unsigned int iNeed = 0; - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; - - // check whether we do already have this vertex - if (0xFFFFFFFF == avWasCopied[iIndex]) { - iNeed++; - } - } - if (pcMesh->mNumVertices + iNeed > iOutVertexNum) { - // don't use this face - break; - } - - vFaces.push_back(aiFace()); - aiFace& rFace = vFaces.back(); - - // setup face type and number of indices - rFace.mNumIndices = iNumIndices; - rFace.mIndices = new unsigned int[iNumIndices]; - - // need to update the output primitive types - switch (rFace.mNumIndices) { - case 1: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - } - - // and copy the contents of the old array, offset by current base - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; - - // check whether we do already have this vertex - if (0xFFFFFFFF != avWasCopied[iIndex]) { - rFace.mIndices[v] = avWasCopied[iIndex]; - continue; - } - - // copy positions - pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]); - - // copy normals - if (pMesh->HasNormals()) { - pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]); - } - - // copy tangents/bitangents - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]); - pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]); - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (pMesh->HasTextureCoords( c)) { - pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex]; - } - } - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex]; - } - } - // check whether we have bone weights assigned to this vertex - rFace.mIndices[v] = pcMesh->mNumVertices; - if (avPerVertexWeights) { - VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ]; - if( !table.empty() ) { - for (VertexWeightTable::const_iterator iter = table.begin(); - iter != table.end();++iter) { - // allocate the bone weight array if necessary - BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first]; - if (nullptr == pcWeightList) { - pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList()); - } - pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second)); - } - } - } - - avWasCopied[iIndex] = pcMesh->mNumVertices; - pcMesh->mNumVertices++; - } - ++iBase; - if(pcMesh->mNumVertices == iOutVertexNum) { - // break here. The face is only added if it was complete - break; - } - } - - // check which bones we'll need to create for this submesh - if (pMesh->HasBones()) { - aiBone** ppCurrent = pcMesh->mBones; - for (unsigned int k = 0; k < pMesh->mNumBones;++k) { - // check whether the bone is existing - BoneWeightList* pcWeightList; - if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k])) { - aiBone* pcOldBone = pMesh->mBones[k]; - aiBone* pcOut( nullptr ); - *ppCurrent++ = pcOut = new aiBone(); - pcOut->mName = aiString(pcOldBone->mName); - pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix; - pcOut->mNumWeights = (unsigned int)pcWeightList->size(); - pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights]; - - // copy the vertex weights - ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0), - pcOut->mNumWeights * sizeof(aiVertexWeight)); - - // delete the temporary bone weight list - delete pcWeightList; - pcMesh->mNumBones++; - } - } - } - - // copy the face list to the mesh - pcMesh->mFaces = new aiFace[vFaces.size()]; - pcMesh->mNumFaces = (unsigned int)vFaces.size(); - - for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) { - pcMesh->mFaces[p] = vFaces[p]; - } - - // add the newly created mesh to the list - avList.push_back(std::pair(pcMesh,a)); - - if (iBase == pMesh->mNumFaces) { - // have all faces ... finish the outer loop, too - break; - } - } - - // delete the per-vertex weight list again - delete[] avPerVertexWeights; - - // now delete the old mesh data - delete pMesh; - return; - } - avList.push_back(std::pair(pMesh,a)); -} diff --git a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h b/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h deleted file mode 100644 index 3f90576ea9bf..000000000000 --- a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -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 Defines a post processing step to split large meshes into sub-meshes - */ -#ifndef AI_SPLITLARGEMESHES_H_INC -#define AI_SPLITLARGEMESHES_H_INC - -#include -#include "Common/BaseProcess.h" - -#include -#include - -// Forward declarations -class SplitLargeMeshesTest; - -namespace Assimp { - -class SplitLargeMeshesProcess_Triangle; -class SplitLargeMeshesProcess_Vertex; - -// NOTE: If you change these limits, don't forget to change the -// corresponding values in all Assimp ports - -// ********************************************************** -// Java: ConfigProperty.java, -// ConfigProperty.DEFAULT_VERTEX_SPLIT_LIMIT -// ConfigProperty.DEFAULT_TRIANGLE_SPLIT_LIMIT -// ********************************************************** - -// default limit for vertices -#if (!defined AI_SLM_DEFAULT_MAX_VERTICES) -# define AI_SLM_DEFAULT_MAX_VERTICES 1000000 -#endif - -// default limit for triangles -#if (!defined AI_SLM_DEFAULT_MAX_TRIANGLES) -# define AI_SLM_DEFAULT_MAX_TRIANGLES 1000000 -#endif - -// --------------------------------------------------------------------------- -/** Post-processing filter to split large meshes into sub-meshes - * - * Applied BEFORE the JoinVertices-Step occurs. - * Returns NON-UNIQUE vertices, splits by triangle number. -*/ -class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess -{ - friend class SplitLargeMeshesProcess_Vertex; - -public: - - SplitLargeMeshesProcess_Triangle(); - ~SplitLargeMeshesProcess_Triangle(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - - //! Set the split limit - needed for unit testing - inline void SetLimit(unsigned int l) - {LIMIT = l;} - - //! Get the split limit - inline unsigned int GetLimit() const - {return LIMIT;} - -public: - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - //! Apply the algorithm to a given mesh - void SplitMesh (unsigned int a, aiMesh* pcMesh, - std::vector >& avList); - - // ------------------------------------------------------------------- - //! Update a node in the asset after a few of its meshes - //! have been split - static void UpdateNode(aiNode* pcNode, - const std::vector >& avList); - -public: - //! Triangle limit - unsigned int LIMIT; -}; - - -// --------------------------------------------------------------------------- -/** Post-processing filter to split large meshes into sub-meshes - * - * Applied AFTER the JoinVertices-Step occurs. - * Returns UNIQUE vertices, splits by vertex number. -*/ -class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess -{ -public: - - SplitLargeMeshesProcess_Vertex(); - ~SplitLargeMeshesProcess_Vertex(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - - //! Set the split limit - needed for unit testing - inline void SetLimit(unsigned int l) - {LIMIT = l;} - - //! Get the split limit - inline unsigned int GetLimit() const - {return LIMIT;} - -public: - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - //! Apply the algorithm to a given mesh - void SplitMesh (unsigned int a, aiMesh* pcMesh, - std::vector >& avList); - - // NOTE: Reuse SplitLargeMeshesProcess_Triangle::UpdateNode() - -public: - //! Triangle limit - unsigned int LIMIT; -}; - -} // end of namespace Assimp - -#endif // !!AI_SPLITLARGEMESHES_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp b/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp deleted file mode 100644 index 8ae2ba721854..000000000000 --- a/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* -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 A helper class that processes texture transformations */ - - - -#include -#include -#include -#include - -#include "TextureTransform.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TextureTransformStep::TextureTransformStep() : - configFlags() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TextureTransformStep::~TextureTransformStep() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool TextureTransformStep::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_TransformUVCoords) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void TextureTransformStep::SetupProperties(const Importer* pImp) -{ - configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL); -} - -// ------------------------------------------------------------------------------------------------ -void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) -{ - /* This function tries to simplify the input UV transformation. - * That's very important as it allows us to reduce the number - * of output UV channels. The order in which the transformations - * are applied is - as always - scaling, rotation, translation. - */ - - char szTemp[512]; - int rounded = 0; - - - /* Optimize the rotation angle. That's slightly difficult as - * we have an inprecise floating-point number (when comparing - * UV transformations we'll take that into account by using - * an epsilon of 5 degrees). If there is a rotation value, we can't - * perform any further optimizations. - */ - if (info.mRotation) - { - float out = info.mRotation; - if ((rounded = static_cast((info.mRotation / static_cast(AI_MATH_TWO_PI))))) - { - out -= rounded * static_cast(AI_MATH_PI); - ASSIMP_LOG_INFO_F("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out); - } - - // Next step - convert negative rotation angles to positives - if (out < 0.f) - out = (float)AI_MATH_TWO_PI * 2 + out; - - info.mRotation = out; - return; - } - - - /* Optimize UV translation in the U direction. To determine whether - * or not we can optimize we need to look at the requested mapping - * type (e.g. if mirroring is active there IS a difference between - * offset 2 and 3) - */ - if ((rounded = (int)info.mTranslation.x)) { - float out = 0.0f; - szTemp[0] = 0; - if (aiTextureMapMode_Wrap == info.mapU) { - // Wrap - simple take the fraction of the field - out = info.mTranslation.x-(float)rounded; - ai_snprintf(szTemp, 512, "[w] UV U offset %f can be simplified to %f", info.mTranslation.x, out); - } - else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) { - // Mirror - if (rounded % 2) - rounded--; - out = info.mTranslation.x-(float)rounded; - - ai_snprintf(szTemp,512,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out); - } - else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) { - // Clamp - translations beyond 1,1 are senseless - ai_snprintf(szTemp,512,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x); - - out = 1.f; - } - if (szTemp[0]) { - ASSIMP_LOG_INFO(szTemp); - info.mTranslation.x = out; - } - } - - /* Optimize UV translation in the V direction. To determine whether - * or not we can optimize we need to look at the requested mapping - * type (e.g. if mirroring is active there IS a difference between - * offset 2 and 3) - */ - if ((rounded = (int)info.mTranslation.y)) { - float out = 0.0f; - szTemp[0] = 0; - if (aiTextureMapMode_Wrap == info.mapV) { - // Wrap - simple take the fraction of the field - out = info.mTranslation.y-(float)rounded; - ::ai_snprintf(szTemp,512,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out); - } - else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) { - // Mirror - if (rounded % 2) - rounded--; - out = info.mTranslation.x-(float)rounded; - - ::ai_snprintf(szTemp,512,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out); - } - else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) { - // Clamp - translations beyond 1,1 are senseless - ::ai_snprintf(szTemp,512,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y); - - out = 1.f; - } - if (szTemp[0]) { - ASSIMP_LOG_INFO(szTemp); - info.mTranslation.y = out; - } - } - return; -} - -// ------------------------------------------------------------------------------------------------ -void UpdateUVIndex(const std::list& l, unsigned int n) -{ - // Don't set if == 0 && wasn't set before - for (std::list::const_iterator it = l.begin();it != l.end(); ++it) { - const TTUpdateInfo& info = *it; - - if (info.directShortcut) - *info.directShortcut = n; - else if (!n) - { - info.mat->AddProperty((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index)); - } - } -} - -// ------------------------------------------------------------------------------------------------ -inline const char* MappingModeToChar(aiTextureMapMode map) -{ - if (aiTextureMapMode_Wrap == map) - return "-w"; - - if (aiTextureMapMode_Mirror == map) - return "-m"; - - return "-c"; -} - -// ------------------------------------------------------------------------------------------------ -void TextureTransformStep::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin"); - - - /* We build a per-mesh list of texture transformations we'll need - * to apply. To achieve this, we iterate through all materials, - * find all textures and get their transformations and UV indices. - * Then we search for all meshes using this material. - */ - typedef std::list MeshTrafoList; - std::vector meshLists(pScene->mNumMeshes); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - - aiMaterial* mat = pScene->mMaterials[i]; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - - aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.file")) { - STransformVecInfo info; - - // Setup a shortcut structure to allow for a fast updating - // of the UV index later - TTUpdateInfo update; - update.mat = (aiMaterial*) mat; - update.semantic = prop->mSemantic; - update.index = prop->mIndex; - - // Get textured properties and transform - for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) { - aiMaterialProperty* prop2 = mat->mProperties[a2]; - if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) { - continue; - } - - if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) { - info.uvIndex = *((int*)prop2->mData); - - // Store a direct pointer for later use - update.directShortcut = (unsigned int*) prop2->mData; - } - - else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) { - info.mapU = *((aiTextureMapMode*)prop2->mData); - } - else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) { - info.mapV = *((aiTextureMapMode*)prop2->mData); - } - else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) { - // ValidateDS should check this - ai_assert(prop2->mDataLength >= 20); - ::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5); - - // Directly remove this property from the list - mat->mNumProperties--; - for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) { - mat->mProperties[a3] = mat->mProperties[a3+1]; - } - - delete prop2; - - // Warn: could be an underflow, but this does not invoke undefined behaviour - --a2; - } - } - - // Find out which transformations are to be evaluated - if (!(configFlags & AI_UVTRAFO_ROTATION)) { - info.mRotation = 0.f; - } - if (!(configFlags & AI_UVTRAFO_SCALING)) { - info.mScaling = aiVector2D(1.f,1.f); - } - if (!(configFlags & AI_UVTRAFO_TRANSLATION)) { - info.mTranslation = aiVector2D(0.f,0.f); - } - - // Do some preprocessing - PreProcessUVTransform(info); - info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u); - - // Find out whether this material is used by more than - // one mesh. This will make our task much, much more difficult! - unsigned int cnt = 0; - for (unsigned int n = 0; n < pScene->mNumMeshes;++n) { - if (pScene->mMeshes[n]->mMaterialIndex == i) - ++cnt; - } - - if (!cnt) - continue; - else if (1 != cnt) { - // This material is referenced by more than one mesh! - // So we need to make sure the UV index for the texture - // is identical for each of it ... - info.lockedPos = AI_TT_UV_IDX_LOCK_TBD; - } - - // Get all corresponding meshes - for (unsigned int n = 0; n < pScene->mNumMeshes;++n) { - aiMesh* mesh = pScene->mMeshes[n]; - if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0]) - continue; - - unsigned int uv = info.uvIndex; - if (!mesh->mTextureCoords[uv]) { - // If the requested UV index is not available, take the first one instead. - uv = 0; - } - - if (mesh->mNumUVComponents[info.uvIndex] >= 3){ - ASSIMP_LOG_WARN("UV transformations on 3D mapping channels are not supported"); - continue; - } - - MeshTrafoList::iterator it; - - // Check whether we have this transform setup already - for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) { - - if ((*it) == info && (*it).uvIndex == uv) { - (*it).updateList.push_back(update); - break; - } - } - - if (it == meshLists[n].end()) { - meshLists[n].push_back(info); - meshLists[n].back().uvIndex = uv; - meshLists[n].back().updateList.push_back(update); - } - } - } - } - } - - char buffer[1024]; // should be sufficiently large - unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0; - - // Now process all meshes. Important: we don't remove unreferenced UV channels. - // This is a job for the RemoveUnreferencedData-Step. - for (unsigned int q = 0; q < pScene->mNumMeshes;++q) { - - aiMesh* mesh = pScene->mMeshes[q]; - MeshTrafoList& trafo = meshLists[q]; - - inChannels += mesh->GetNumUVChannels(); - - if (!mesh->mTextureCoords[0] || trafo.empty() || (trafo.size() == 1 && trafo.begin()->IsUntransformed())) { - outChannels += mesh->GetNumUVChannels(); - continue; - } - - // Move untransformed UV channels to the first position in the list .... - // except if we need a new locked index which should be as small as possible - bool veto = false, need = false; - unsigned int cnt = 0; - unsigned int untransformed = 0; - - MeshTrafoList::iterator it,it2; - for (it = trafo.begin();it != trafo.end(); ++it,++cnt) { - - if (!(*it).IsUntransformed()) { - need = true; - } - - if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) { - // Lock this index and make sure it won't be changed - (*it).lockedPos = cnt; - veto = true; - continue; - } - - if (!veto && it != trafo.begin() && (*it).IsUntransformed()) { - for (it2 = trafo.begin();it2 != it; ++it2) { - if (!(*it2).IsUntransformed()) - break; - } - trafo.insert(it2,*it); - trafo.erase(it); - break; - } - } - if (!need) - continue; - - // Find all that are not at their 'locked' position and move them to it. - // Conflicts are possible but quite unlikely. - cnt = 0; - for (it = trafo.begin();it != trafo.end(); ++it,++cnt) { - if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) { - it2 = trafo.begin();unsigned int t = 0; - while (t != (*it).lockedPos) - ++it2; - - if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) { - ASSIMP_LOG_ERROR("Channel mismatch, can't compute all transformations properly [design bug]"); - continue; - } - - std::swap(*it2,*it); - if ((*it).lockedPos == untransformed) - untransformed = cnt; - } - } - - // ... and add dummies for all unreferenced channels - // at the end of the list - bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) - ref[n] = (!mesh->mTextureCoords[n] ? true : false); - - for (it = trafo.begin();it != trafo.end(); ++it) - ref[(*it).uvIndex] = true; - - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (ref[n]) - continue; - trafo.push_back(STransformVecInfo()); - trafo.back().uvIndex = n; - } - - // Then check whether this list breaks the channel limit. - // The unimportant ones are at the end of the list, so - // it shouldn't be too worse if we remove them. - unsigned int size = (unsigned int)trafo.size(); - if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) { - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_ERROR_F(static_cast(trafo.size()), " UV channels required but just ", - AI_MAX_NUMBER_OF_TEXTURECOORDS, " available"); - } - size = AI_MAX_NUMBER_OF_TEXTURECOORDS; - } - - - aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) - old[n] = mesh->mTextureCoords[n]; - - // Now continue and generate the output channels. Channels - // that we're not going to need later can be overridden. - it = trafo.begin(); - for (unsigned int n = 0; n < trafo.size();++n,++it) { - - if (n >= size) { - // Try to use an untransformed channel for all channels we threw over board - UpdateUVIndex((*it).updateList,untransformed); - continue; - } - - outChannels++; - - // Write to the log - if (!DefaultLogger::isNullLogger()) { - ::ai_snprintf(buffer,1024,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s", - q,n, - (*it).mTranslation.x, - (*it).mTranslation.y, - (*it).mScaling.x, - (*it).mScaling.y, - AI_RAD_TO_DEG( (*it).mRotation), - MappingModeToChar ((*it).mapU), - MappingModeToChar ((*it).mapV)); - - ASSIMP_LOG_INFO(buffer); - } - - // Check whether we need a new buffer here - if (mesh->mTextureCoords[n]) { - - it2 = it;++it2; - for (unsigned int m = n+1; m < size;++m, ++it2) { - - if ((*it2).uvIndex == n){ - it2 = trafo.begin(); - break; - } - } - if (it2 == trafo.begin()){ - mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - } - } - else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - - aiVector3D* src = old[(*it).uvIndex]; - aiVector3D* dest, *end; - dest = mesh->mTextureCoords[n]; - - ai_assert(NULL != src); - - // Copy the data to the destination array - if (dest != src) - ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); - - end = dest + mesh->mNumVertices; - - // Build a transformation matrix and transform all UV coords with it - if (!(*it).IsUntransformed()) { - const aiVector2D& trl = (*it).mTranslation; - const aiVector2D& scl = (*it).mScaling; - - // fixme: simplify .. - ++transformedChannels; - aiMatrix3x3 matrix; - - aiMatrix3x3 m2,m3,m4,m5; - - m4.a1 = scl.x; - m4.b2 = scl.y; - - m2.a3 = m2.b3 = 0.5f; - m3.a3 = m3.b3 = -0.5f; - - if ((*it).mRotation > AI_TT_ROTATION_EPSILON ) - aiMatrix3x3::RotationZ((*it).mRotation,matrix); - - m5.a3 += trl.x; m5.b3 += trl.y; - matrix = m2 * m4 * matrix * m3 * m5; - - for (src = dest; src != end; ++src) { /* manual homogenious divide */ - src->z = 1.f; - *src = matrix * *src; - src->x /= src->z; - src->y /= src->z; - src->z = 0.f; - } - } - - // Update all UV indices - UpdateUVIndex((*it).updateList,n); - } - } - - // Print some detailed statistics into the log - if (!DefaultLogger::isNullLogger()) { - - if (transformedChannels) { - ASSIMP_LOG_INFO_F("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")"); - } else { - ASSIMP_LOG_DEBUG("TransformUVCoordsProcess finished"); - } - } -} - - diff --git a/thirdparty/assimp/code/PostProcessing/TextureTransform.h b/thirdparty/assimp/code/PostProcessing/TextureTransform.h deleted file mode 100644 index 2a5d623d7fef..000000000000 --- a/thirdparty/assimp/code/PostProcessing/TextureTransform.h +++ /dev/null @@ -1,232 +0,0 @@ -/* -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 Definition of a helper step that processes texture transformations */ -#ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED -#define AI_TEXTURE_TRANSFORM_H_INCLUDED - -#include -#include "Common/BaseProcess.h" - -#include -#include - -struct aiNode; -struct aiMaterial; - -namespace Assimp { - -#define AI_TT_UV_IDX_LOCK_TBD 0xffffffff -#define AI_TT_UV_IDX_LOCK_NONE 0xeeeeeeee - - -#define AI_TT_ROTATION_EPSILON ((float)AI_DEG_TO_RAD(0.5)) - -// --------------------------------------------------------------------------- -/** Small helper structure representing a shortcut into the material list - * to be able to update some values quickly. -*/ -struct TTUpdateInfo { - TTUpdateInfo() AI_NO_EXCEPT - : directShortcut(nullptr) - , mat(nullptr) - , semantic(0) - , index(0) { - // empty - } - - //! Direct shortcut, if available - unsigned int* directShortcut; - - //! Material - aiMaterial *mat; - - //! Texture type and index - unsigned int semantic, index; -}; - - -// --------------------------------------------------------------------------- -/** Helper class representing texture coordinate transformations -*/ -struct STransformVecInfo : public aiUVTransform { - STransformVecInfo() AI_NO_EXCEPT - : uvIndex(0) - , mapU(aiTextureMapMode_Wrap) - , mapV(aiTextureMapMode_Wrap) - , lockedPos(AI_TT_UV_IDX_LOCK_NONE) { - // empty - } - - //! Source texture coordinate index - unsigned int uvIndex; - - //! Texture mapping mode in the u, v direction - aiTextureMapMode mapU,mapV; - - //! Locked destination UV index - //! AI_TT_UV_IDX_LOCK_TBD - to be determined - //! AI_TT_UV_IDX_LOCK_NONE - none (default) - unsigned int lockedPos; - - //! Update info - shortcuts into all materials - //! that are referencing this transform setup - std::list updateList; - - - // ------------------------------------------------------------------- - /** Compare two transform setups - */ - inline bool operator== (const STransformVecInfo& other) const - { - // We use a small epsilon here - const static float epsilon = 0.05f; - - if (std::fabs( mTranslation.x - other.mTranslation.x ) > epsilon || - std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon) - { - return false; - } - - if (std::fabs( mScaling.x - other.mScaling.x ) > epsilon || - std::fabs( mScaling.y - other.mScaling.y ) > epsilon) - { - return false; - } - - if (std::fabs( mRotation - other.mRotation) > epsilon) - { - return false; - } - return true; - } - - inline bool operator!= (const STransformVecInfo& other) const - { - return !(*this == other); - } - - - // ------------------------------------------------------------------- - /** Returns whether this is an untransformed texture coordinate set - */ - inline bool IsUntransformed() const - { - return (1.0f == mScaling.x && 1.f == mScaling.y && - !mTranslation.x && !mTranslation.y && - mRotation < AI_TT_ROTATION_EPSILON); - } - - // ------------------------------------------------------------------- - /** Build a 3x3 matrix from the transformations - */ - inline void GetMatrix(aiMatrix3x3& mOut) - { - mOut = aiMatrix3x3(); - - if (1.0f != mScaling.x || 1.0f != mScaling.y) - { - aiMatrix3x3 mScale; - mScale.a1 = mScaling.x; - mScale.b2 = mScaling.y; - mOut = mScale; - } - if (mRotation) - { - aiMatrix3x3 mRot; - mRot.a1 = mRot.b2 = std::cos(mRotation); - mRot.a2 = mRot.b1 = std::sin(mRotation); - mRot.a2 = -mRot.a2; - mOut *= mRot; - } - if (mTranslation.x || mTranslation.y) - { - aiMatrix3x3 mTrans; - mTrans.a3 = mTranslation.x; - mTrans.b3 = mTranslation.y; - mOut *= mTrans; - } - } -}; - - -// --------------------------------------------------------------------------- -/** Helper step to compute final UV coordinate sets if there are scalings - * or rotations in the original data read from the file. -*/ -class TextureTransformStep : public BaseProcess -{ -public: - - TextureTransformStep(); - ~TextureTransformStep(); - -public: - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - -protected: - - - // ------------------------------------------------------------------- - /** Preprocess a specific UV transformation setup - * - * @param info Transformation setup to be preprocessed. - */ - void PreProcessUVTransform(STransformVecInfo& info); - -private: - - unsigned int configFlags; -}; - -} - -#endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp b/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp deleted file mode 100644 index 1040836bbe1a..000000000000 --- a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 TriangulateProcess.cpp - * @brief Implementation of the post processing step to split up - * all faces with more than three indices into triangles. - * - * - * The triangulation algorithm will handle concave or convex polygons. - * Self-intersecting or non-planar polygons are not rejected, but - * they're probably not triangulated correctly. - * - * DEBUG SWITCHES - do not enable any of them in release builds: - * - * AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - * - generates vertex colors to represent the face winding order. - * the first vertex of a polygon becomes red, the last blue. - * AI_BUILD_TRIANGULATE_DEBUG_POLYS - * - dump all polygons and their triangulation sequences to - * a file - */ -#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS - -#include "PostProcessing/TriangulateProcess.h" -#include "PostProcessing/ProcessHelper.h" -#include "Common/PolyTools.h" - -#include - -//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING -//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS - -#define POLY_GRID_Y 40 -#define POLY_GRID_X 70 -#define POLY_GRID_XPAD 20 -#define POLY_OUTPUT_FILE "assimp_polygons_debug.txt" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TriangulateProcess::TriangulateProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TriangulateProcess::~TriangulateProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool TriangulateProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_Triangulate) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void TriangulateProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("TriangulateProcess begin"); - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if (pScene->mMeshes[ a ]) { - if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) { - bHas = true; - } - } - } - if ( bHas ) { - ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." ); - } else { - ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Triangulates the given mesh. -bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) -{ - // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases - if (!pMesh->mPrimitiveTypes) { - bool bNeed = false; - - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - const aiFace& face = pMesh->mFaces[a]; - - if( face.mNumIndices != 3) { - bNeed = true; - } - } - if (!bNeed) - return false; - } - else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) { - return false; - } - - // Find out how many output faces we'll get - unsigned int numOut = 0, max_out = 0; - bool get_normals = true; - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices <= 4) { - get_normals = false; - } - if( face.mNumIndices <= 3) { - numOut++; - - } - else { - numOut += face.mNumIndices-2; - max_out = std::max(max_out,face.mNumIndices); - } - } - - // Just another check whether aiMesh::mPrimitiveTypes is correct - ai_assert(numOut != pMesh->mNumFaces); - - aiVector3D* nor_out = NULL; - - // if we don't have normals yet, but expect them to be a cheap side - // product of triangulation anyway, allocate storage for them. - if (!pMesh->mNormals && get_normals) { - // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals - // nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - } - - // the output mesh will contain triangles, but no polys anymore - pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON; - - aiFace* out = new aiFace[numOut](), *curOut = out; - std::vector temp_verts3d(max_out+2); /* temporary storage for vertices */ - std::vector temp_verts(max_out+2); - - // Apply vertex colors to represent the face winding? -#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - if (!pMesh->mColors[0]) - pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; - else - new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices]; - - aiColor4D* clr = pMesh->mColors[0]; -#endif - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - FILE* fout = fopen(POLY_OUTPUT_FILE,"a"); -#endif - - const aiVector3D* verts = pMesh->mVertices; - - // use std::unique_ptr to avoid slow std::vector specialiations - std::unique_ptr done(new bool[max_out]); - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - aiFace& face = pMesh->mFaces[a]; - - unsigned int* idx = face.mIndices; - int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num; - - // Apply vertex colors to represent the face winding? -#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - for (unsigned int i = 0; i < face.mNumIndices; ++i) { - aiColor4D& c = clr[idx[i]]; - c.r = (i+1) / (float)max; - c.b = 1.f - c.r; - } -#endif - - aiFace* const last_face = curOut; - - // if it's a simple point,line or triangle: just copy it - if( face.mNumIndices <= 3) - { - aiFace& nface = *curOut++; - nface.mNumIndices = face.mNumIndices; - nface.mIndices = face.mIndices; - - face.mIndices = NULL; - continue; - } - // optimized code for quadrilaterals - else if ( face.mNumIndices == 4) { - - // quads can have at maximum one concave vertex. Determine - // this vertex (if it exists) and start tri-fanning from - // it. - unsigned int start_vertex = 0; - for (unsigned int i = 0; i < 4; ++i) { - const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]]; - const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]]; - const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]]; - - const aiVector3D& v = verts[face.mIndices[i]]; - - aiVector3D left = (v0-v); - aiVector3D diag = (v1-v); - aiVector3D right = (v2-v); - - left.Normalize(); - diag.Normalize(); - right.Normalize(); - - const float angle = std::acos(left*diag) + std::acos(right*diag); - if (angle > AI_MATH_PI_F) { - // this is the concave point - start_vertex = i; - break; - } - } - - const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]}; - - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - nface.mIndices = face.mIndices; - - nface.mIndices[0] = temp[start_vertex]; - nface.mIndices[1] = temp[(start_vertex + 1) % 4]; - nface.mIndices[2] = temp[(start_vertex + 2) % 4]; - - aiFace& sface = *curOut++; - sface.mNumIndices = 3; - sface.mIndices = new unsigned int[3]; - - sface.mIndices[0] = temp[start_vertex]; - sface.mIndices[1] = temp[(start_vertex + 2) % 4]; - sface.mIndices[2] = temp[(start_vertex + 3) % 4]; - - // prevent double deletion of the indices field - face.mIndices = NULL; - continue; - } - else - { - // A polygon with more than 3 vertices can be either concave or convex. - // Usually everything we're getting is convex and we could easily - // triangulate by tri-fanning. However, LightWave is probably the only - // modeling suite to make extensive use of highly concave, monster polygons ... - // so we need to apply the full 'ear cutting' algorithm to get it right. - - // RERQUIREMENT: polygon is expected to be simple and *nearly* planar. - // We project it onto a plane to get a 2d triangle. - - // Collect all vertices of of the polygon. - for (tmp = 0; tmp < max; ++tmp) { - temp_verts3d[tmp] = verts[idx[tmp]]; - } - - // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh - aiVector3D n; - NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z); - if (nor_out) { - for (tmp = 0; tmp < max; ++tmp) - nor_out[idx[tmp]] = n; - } - - // Select largest normal coordinate to ignore for projection - const float ax = (n.x>0 ? n.x : -n.x); - const float ay = (n.y>0 ? n.y : -n.y); - const float az = (n.z>0 ? n.z : -n.z); - - unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */ - float inv = n.z; - if (ax > ay) { - if (ax > az) { /* no x coord. projection to yz */ - ac = 1; bc = 2; - inv = n.x; - } - } - else if (ay > az) { /* no y coord. projection to zy */ - ac = 2; bc = 0; - inv = n.y; - } - - // Swap projection axes to take the negated projection vector into account - if (inv < 0.f) { - std::swap(ac,bc); - } - - for (tmp =0; tmp < max; ++tmp) { - temp_verts[tmp].x = verts[idx[tmp]][ac]; - temp_verts[tmp].y = verts[idx[tmp]][bc]; - done[tmp] = false; - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - // plot the plane onto which we mapped the polygon to a 2D ASCII pic - aiVector2D bmin,bmax; - ArrayBounds(&temp_verts[0],max,bmin,bmax); - - char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD]; - std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' '); - - for (int i =0; i < max; ++i) { - const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin); - const size_t x = static_cast(v.x*(POLY_GRID_X-1)), y = static_cast(v.y*(POLY_GRID_Y-1)); - char* loc = grid[y]+x; - if (grid[y][x] != ' ') { - for(;*loc != ' '; ++loc); - *loc++ = '_'; - } - *(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' '; - } - - - for(size_t y = 0; y < POLY_GRID_Y; ++y) { - grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0'; - fprintf(fout,"%s\n",grid[y]); - } - - fprintf(fout,"\ntriangulation sequence: "); -#endif - - // - // FIXME: currently this is the slow O(kn) variant with a worst case - // complexity of O(n^2) (I think). Can be done in O(n). - while (num > 3) { - - // Find the next ear of the polygon - int num_found = 0; - for (ear = next;;prev = ear,ear = next) { - - // break after we looped two times without a positive match - for (next=ear+1;done[(next>=max?next=0:next)];++next); - if (next < ear) { - if (++num_found == 2) { - break; - } - } - const aiVector2D* pnt1 = &temp_verts[ear], - *pnt0 = &temp_verts[prev], - *pnt2 = &temp_verts[next]; - - // Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1. - if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) { - continue; - } - - // and no other point may be contained in this triangle - for ( tmp = 0; tmp < max; ++tmp) { - - // We need to compare the actual values because it's possible that multiple indexes in - // the polygon are referring to the same position. concave_polygon.obj is a sample - // - // FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in - // PointInTriangle() I'm guessing that it's actually possible to construct - // input data that would cause us to end up with no ears. The problem is, - // which epsilon? If we chose a too large value, we'd get wrong results - const aiVector2D& vtmp = temp_verts[tmp]; - if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) { - break; - } - } - if (tmp != max) { - continue; - } - - // this vertex is an ear - break; - } - if (num_found == 2) { - - // Due to the 'two ear theorem', every simple polygon with more than three points must - // have 2 'ears'. Here's definitely something wrong ... but we don't give up yet. - // - - // Instead we're continuing with the standard tri-fanning algorithm which we'd - // use if we had only convex polygons. That's life. - ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?"); - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - fprintf(fout,"critical error here, no ear found! "); -#endif - num = 0; - break; - - curOut -= (max-num); /* undo all previous work */ - for (tmp = 0; tmp < max-2; ++tmp) { - aiFace& nface = *curOut++; - - nface.mNumIndices = 3; - if (!nface.mIndices) - nface.mIndices = new unsigned int[3]; - - nface.mIndices[0] = 0; - nface.mIndices[1] = tmp+1; - nface.mIndices[2] = tmp+2; - - } - num = 0; - break; - } - - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - // setup indices for the new triangle ... - nface.mIndices[0] = prev; - nface.mIndices[1] = ear; - nface.mIndices[2] = next; - - // exclude the ear from most further processing - done[ear] = true; - --num; - } - if (num > 0) { - // We have three indices forming the last 'ear' remaining. Collect them. - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - for (tmp = 0; done[tmp]; ++tmp); - nface.mIndices[0] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[1] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[2] = tmp; - - } - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - - for(aiFace* f = last_face; f != curOut; ++f) { - unsigned int* i = f->mIndices; - fprintf(fout," (%i %i %i)",i[0],i[1],i[2]); - } - - fprintf(fout,"\n*********************************************************************\n"); - fflush(fout); - -#endif - - for(aiFace* f = last_face; f != curOut; ) { - unsigned int* i = f->mIndices; - - // drop dumb 0-area triangles - deactivated for now: - //FindDegenerates post processing step can do the same thing - //if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) { - // ASSIMP_LOG_DEBUG("Dropping triangle with area 0"); - // --curOut; - - // delete[] f->mIndices; - // f->mIndices = nullptr; - - // for(aiFace* ff = f; ff != curOut; ++ff) { - // ff->mNumIndices = (ff+1)->mNumIndices; - // ff->mIndices = (ff+1)->mIndices; - // (ff+1)->mIndices = nullptr; - // } - // continue; - //} - - i[0] = idx[i[0]]; - i[1] = idx[i[1]]; - i[2] = idx[i[2]]; - ++f; - } - - delete[] face.mIndices; - face.mIndices = NULL; - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - fclose(fout); -#endif - - // kill the old faces - delete [] pMesh->mFaces; - - // ... and store the new ones - pMesh->mFaces = out; - pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */ - return true; -} - -#endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h b/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h deleted file mode 100644 index 916b5103ddbe..000000000000 --- a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -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 Defines a post processing step to triangulate all faces - with more than three vertices. - */ -#ifndef AI_TRIANGULATEPROCESS_H_INC -#define AI_TRIANGULATEPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -class TriangulateProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The TriangulateProcess splits up all faces with more than three indices - * into triangles. You usually want this to happen because the graphics cards - * need their data as triangles. - */ -class ASSIMP_API TriangulateProcess : public BaseProcess { -public: - TriangulateProcess(); - ~TriangulateProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Triangulates the given mesh. - * @param pMesh The mesh to triangulate. - */ - bool TriangulateMesh( aiMesh* pMesh); -}; - -} // end of namespace Assimp - -#endif // AI_TRIANGULATEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp b/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp deleted file mode 100644 index 75d1b6ef7844..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 ValidateDataStructure.cpp - * @brief Implementation of the post processing step to validate - * the data structure returned by Assimp. - */ - -// internal headers -#include "ValidateDataStructure.h" -#include -#include -#include "ProcessHelper.h" -#include - -// CRT headers -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ValidateDSProcess::ValidateDSProcess() : - mScene() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ValidateDSProcess::~ValidateDSProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ValidateDSProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_ValidateDataStructure) != 0; -} -// ------------------------------------------------------------------------------------------------ -AI_WONT_RETURN void ValidateDSProcess::ReportError(const char* msg,...) -{ - ai_assert(NULL != msg); - - va_list args; - va_start(args,msg); - - char szBuffer[3000]; - const int iLen = vsprintf(szBuffer,msg,args); - ai_assert(iLen > 0); - - va_end(args); - - throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen)); -} -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::ReportWarning(const char* msg,...) -{ - ai_assert(NULL != msg); - - va_list args; - va_start(args,msg); - - char szBuffer[3000]; - const int iLen = vsprintf(szBuffer,msg,args); - ai_assert(iLen > 0); - - va_end(args); - ASSIMP_LOG_WARN("Validation warning: " + std::string(szBuffer,iLen)); -} - -// ------------------------------------------------------------------------------------------------ -inline -int HasNameMatch(const aiString& in, aiNode* node) { - int result = (node->mName == in ? 1 : 0 ); - for (unsigned int i = 0; i < node->mNumChildren;++i) { - result += HasNameMatch(in,node->mChildren[i]); - } - return result; -} - -// ------------------------------------------------------------------------------------------------ -template -inline -void ValidateDSProcess::DoValidation(T** parray, unsigned int size, const char* firstName, const char* secondName) { - // validate all entries - if (size) - { - if (!parray) - { - ReportError("aiScene::%s is NULL (aiScene::%s is %i)", - firstName, secondName, size); - } - for (unsigned int i = 0; i < size;++i) - { - if (!parray[i]) - { - ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)", - firstName,i,secondName,size); - } - Validate(parray[i]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, - const char* firstName, const char* secondName) -{ - // validate all entries - if (size) - { - if (!parray) { - ReportError("aiScene::%s is NULL (aiScene::%s is %i)", - firstName, secondName, size); - } - for (unsigned int i = 0; i < size;++i) - { - if (!parray[i]) - { - ReportError("aiScene::%s[%u] is NULL (aiScene::%s is %u)", - firstName,i,secondName,size); - } - Validate(parray[i]); - - // check whether there are duplicate names - for (unsigned int a = i+1; a < size;++a) - { - if (parray[i]->mName == parray[a]->mName) - { - ReportError("aiScene::%s[%u] has the same name as " - "aiScene::%s[%u]",firstName, i,secondName, a); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline -void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, const char* firstName, - const char* secondName) { - // validate all entries - DoValidationEx(array,size,firstName,secondName); - - for (unsigned int i = 0; i < size;++i) { - int res = HasNameMatch(array[i]->mName,mScene->mRootNode); - if (0 == res) { - const std::string name = static_cast(array[i]->mName.data); - ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)", - firstName,i, name.c_str()); - } else if (1 != res) { - const std::string name = static_cast(array[i]->mName.data); - ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name", - firstName,i, name.c_str()); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void ValidateDSProcess::Execute( aiScene* pScene) { - mScene = pScene; - ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin"); - - // validate the node graph of the scene - Validate(pScene->mRootNode); - - // validate all meshes - if (pScene->mNumMeshes) { - DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes"); - } - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { - ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); - } - else if (pScene->mMeshes) { - ReportError("aiScene::mMeshes is non-null although there are no meshes"); - } - - // validate all animations - if (pScene->mNumAnimations) { - DoValidation(pScene->mAnimations,pScene->mNumAnimations, - "mAnimations","mNumAnimations"); - } - else if (pScene->mAnimations) { - ReportError("aiScene::mAnimations is non-null although there are no animations"); - } - - // validate all cameras - if (pScene->mNumCameras) { - DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras, - "mCameras","mNumCameras"); - } - else if (pScene->mCameras) { - ReportError("aiScene::mCameras is non-null although there are no cameras"); - } - - // validate all lights - if (pScene->mNumLights) { - DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights, - "mLights","mNumLights"); - } - else if (pScene->mLights) { - ReportError("aiScene::mLights is non-null although there are no lights"); - } - - // validate all textures - if (pScene->mNumTextures) { - DoValidation(pScene->mTextures,pScene->mNumTextures, - "mTextures","mNumTextures"); - } - else if (pScene->mTextures) { - ReportError("aiScene::mTextures is non-null although there are no textures"); - } - - // validate all materials - if (pScene->mNumMaterials) { - DoValidation(pScene->mMaterials,pScene->mNumMaterials,"mMaterials","mNumMaterials"); - } -#if 0 - // NOTE: ScenePreprocessor generates a default material if none is there - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { - ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); - } -#endif - else if (pScene->mMaterials) { - ReportError("aiScene::mMaterials is non-null although there are no materials"); - } - -// if (!has)ReportError("The aiScene data structure is empty"); - ASSIMP_LOG_DEBUG("ValidateDataStructureProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiLight* pLight) -{ - if (pLight->mType == aiLightSource_UNDEFINED) - ReportWarning("aiLight::mType is aiLightSource_UNDEFINED"); - - if (!pLight->mAttenuationConstant && - !pLight->mAttenuationLinear && - !pLight->mAttenuationQuadratic) { - ReportWarning("aiLight::mAttenuationXXX - all are zero"); - } - - if (pLight->mAngleInnerCone > pLight->mAngleOuterCone) - ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone"); - - if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() - && pLight->mColorSpecular.IsBlack()) - { - ReportWarning("aiLight::mColorXXX - all are black and won't have any influence"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiCamera* pCamera) -{ - if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear) - ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); - - // FIX: there are many 3ds files with invalid FOVs. No reason to - // reject them at all ... a warning is appropriate. - if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) - ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh) -{ - // validate the material index of the mesh - if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) - { - ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)", - pMesh->mMaterialIndex,mScene->mNumMaterials-1); - } - - Validate(&pMesh->mName); - - for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) - { - aiFace& face = pMesh->mFaces[i]; - - if (pMesh->mPrimitiveTypes) - { - switch (face.mNumIndices) - { - case 0: - ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); - break; - case 1: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) - { - ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes " - "does not report the POINT flag",i); - } - break; - case 2: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) - { - ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes " - "does not report the LINE flag",i); - } - break; - case 3: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) - { - ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes " - "does not report the TRIANGLE flag",i); - } - break; - default: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) - { - this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes " - "does not report the POLYGON flag",i); - } - break; - }; - } - - if (!face.mIndices) - ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); - } - - // positions must always be there ... - if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) { - ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str()); - } - - if (pMesh->mNumVertices > AI_MAX_VERTICES) { - ReportError("Mesh has too many vertices: %u, but the limit is %u",pMesh->mNumVertices,AI_MAX_VERTICES); - } - if (pMesh->mNumFaces > AI_MAX_FACES) { - ReportError("Mesh has too many faces: %u, but the limit is %u",pMesh->mNumFaces,AI_MAX_FACES); - } - - // if tangents are there there must also be bitangent vectors ... - if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL)) { - ReportError("If there are tangents, bitangent vectors must be present as well"); - } - - // faces, too - if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) { - ReportError("Mesh %s contains no faces", pMesh->mName.C_Str()); - } - - // now check whether the face indexing layout is correct: - // unique vertices, pseudo-indexed. - std::vector abRefList; - abRefList.resize(pMesh->mNumVertices,false); - for (unsigned int i = 0; i < pMesh->mNumFaces;++i) - { - aiFace& face = pMesh->mFaces[i]; - if (face.mNumIndices > AI_MAX_FACE_INDICES) { - ReportError("Face %u has too many faces: %u, but the limit is %u",i,face.mNumIndices,AI_MAX_FACE_INDICES); - } - - for (unsigned int a = 0; a < face.mNumIndices;++a) - { - if (face.mIndices[a] >= pMesh->mNumVertices) { - ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); - } - // the MSB flag is temporarily used by the extra verbose - // mode to tell us that the JoinVerticesProcess might have - // been executed already. - /*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) && - abRefList[face.mIndices[a]]) - { - ReportError("aiMesh::mVertices[%i] is referenced twice - second " - "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a); - }*/ - abRefList[face.mIndices[a]] = true; - } - } - - // check whether there are vertices that aren't referenced by a face - bool b = false; - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (!abRefList[i])b = true; - } - abRefList.clear(); - if (b) { - ReportWarning("There are unreferenced vertices"); - } - - // texture channel 2 may not be set if channel 1 is zero ... - { - unsigned int i = 0; - for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - if (!pMesh->HasTextureCoords(i))break; - } - for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - if (pMesh->HasTextureCoords(i)) - { - ReportError("Texture coordinate channel %i exists " - "although the previous channel was NULL.",i); - } - } - // the same for the vertex colors - { - unsigned int i = 0; - for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) - { - if (!pMesh->HasVertexColors(i))break; - } - for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) - if (pMesh->HasVertexColors(i)) - { - ReportError("Vertex color channel %i is exists " - "although the previous channel was NULL.",i); - } - } - - - // now validate all bones - if (pMesh->mNumBones) - { - if (!pMesh->mBones) - { - ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)", - pMesh->mNumBones); - } - std::unique_ptr afSum(nullptr); - if (pMesh->mNumVertices) - { - afSum.reset(new float[pMesh->mNumVertices]); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) - afSum[i] = 0.0f; - } - - // check whether there are duplicate bone names - for (unsigned int i = 0; i < pMesh->mNumBones;++i) - { - const aiBone* bone = pMesh->mBones[i]; - if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) { - ReportError("Bone %u has too many weights: %u, but the limit is %u",i,bone->mNumWeights,AI_MAX_BONE_WEIGHTS); - } - - if (!pMesh->mBones[i]) - { - ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", - i,pMesh->mNumBones); - } - Validate(pMesh,pMesh->mBones[i],afSum.get()); - - for (unsigned int a = i+1; a < pMesh->mNumBones;++a) - { - if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) - { - const char *name = "unknown"; - if (nullptr != pMesh->mBones[ i ]->mName.C_Str()) { - name = pMesh->mBones[ i ]->mName.C_Str(); - } - ReportError("aiMesh::mBones[%i], name = \"%s\" has the same name as " - "aiMesh::mBones[%i]", i, name, a ); - } - } - } - // check whether all bone weights for a vertex sum to 1.0 ... - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) - { - if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) { - ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); - } - } - } - else if (pMesh->mBones) - { - ReportError("aiMesh::mBones is non-null although there are no bones"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh, const aiBone* pBone,float* afSum) { - this->Validate(&pBone->mName); - - if (!pBone->mNumWeights) { - //ReportError("aiBone::mNumWeights is zero"); - } - - // check whether all vertices affected by this bone are valid - for (unsigned int i = 0; i < pBone->mNumWeights;++i) - { - if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) { - ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); - } - else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) { - ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i); - } - afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight; - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiAnimation* pAnimation) -{ - Validate(&pAnimation->mName); - - // validate all animations - if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) - { - if (!pAnimation->mChannels && pAnimation->mNumChannels) { - ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", - pAnimation->mNumChannels); - } - if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) { - ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)", - pAnimation->mNumMorphMeshChannels); - } - for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) - { - if (!pAnimation->mChannels[i]) - { - ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)", - i, pAnimation->mNumChannels); - } - Validate(pAnimation, pAnimation->mChannels[i]); - } - for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i) - { - if (!pAnimation->mMorphMeshChannels[i]) - { - ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)", - i, pAnimation->mNumMorphMeshChannels); - } - Validate(pAnimation, pAnimation->mMorphMeshChannels[i]); - } - } - else { - ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, - aiTextureType type) -{ - const char* szType = TextureTypeToString(type); - - // **************************************************************************** - // Search all keys of the material ... - // textures must be specified with ascending indices - // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...) - // **************************************************************************** - - int iNumIndices = 0; - int iIndex = -1; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { - aiMaterialProperty* prop = pMaterial->mProperties[ i ]; - ai_assert(nullptr != prop); - if ( !::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == static_cast(type)) { - iIndex = std::max(iIndex, (int) prop->mIndex); - ++iNumIndices; - - if (aiPTI_String != prop->mType) { - ReportError("Material property %s is expected to be a string", prop->mKey.data); - } - } - } - if (iIndex +1 != iNumIndices) { - ReportError("%s #%i is set, but there are only %i %s textures", - szType,iIndex,iNumIndices,szType); - } - if (!iNumIndices)return; - std::vector mappings(iNumIndices); - - // Now check whether all UV indices are valid ... - bool bNoSpecified = true; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { - aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (prop->mSemantic != type)continue; - - if ((int)prop->mIndex >= iNumIndices) - { - ReportError("Found texture property with index %i, although there " - "are only %i textures of type %s", - prop->mIndex, iNumIndices, szType); - } - - if (!::strcmp(prop->mKey.data,"$tex.mapping")) { - if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) - { - ReportError("Material property %s%i is expected to be an integer (size is %i)", - prop->mKey.data,prop->mIndex,prop->mDataLength); - } - mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); - } - else if (!::strcmp(prop->mKey.data,"$tex.uvtrafo")) { - if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) - { - ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", - prop->mKey.data,prop->mIndex, prop->mDataLength); - } - mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); - } - else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) { - if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) - { - ReportError("Material property %s%i is expected to be an integer (size is %i)", - prop->mKey.data,prop->mIndex,prop->mDataLength); - } - bNoSpecified = false; - - // Ignore UV indices for texture channels that are not there ... - - // Get the value - iIndex = *((unsigned int*)prop->mData); - - // Check whether there is a mesh using this material - // which has not enough UV channels ... - for (unsigned int a = 0; a < mScene->mNumMeshes;++a) - { - aiMesh* mesh = this->mScene->mMeshes[a]; - if(mesh->mMaterialIndex == (unsigned int)i) - { - int iChannels = 0; - while (mesh->HasTextureCoords(iChannels))++iChannels; - if (iIndex >= iChannels) - { - ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", - iIndex,prop->mKey.data,a,iChannels); - } - } - } - } - } - if (bNoSpecified) - { - // Assume that all textures are using the first UV channel - for (unsigned int a = 0; a < mScene->mNumMeshes;++a) - { - aiMesh* mesh = mScene->mMeshes[a]; - if(mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV) - { - if (!mesh->mTextureCoords[0]) - { - // This is a special case ... it could be that the - // original mesh format intended the use of a special - // mapping here. - ReportWarning("UV-mapped texture, but there are no UV coords"); - } - } - } - } -} -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMaterial* pMaterial) -{ - // check whether there are material keys that are obviously not legal - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { - const aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (!prop) { - ReportError("aiMaterial::mProperties[%i] is NULL (aiMaterial::mNumProperties is %i)", - i,pMaterial->mNumProperties); - } - if (!prop->mDataLength || !prop->mData) { - ReportError("aiMaterial::mProperties[%i].mDataLength or " - "aiMaterial::mProperties[%i].mData is 0",i,i); - } - // check all predefined types - if (aiPTI_String == prop->mType) { - // FIX: strings are now stored in a less expensive way, but we can't use the - // validation routine for 'normal' aiStrings - if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast(prop->mData)) + 1) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain a string (%i, needed: %i)", - i,prop->mDataLength,static_cast(sizeof(aiString))); - } - if(prop->mData[prop->mDataLength-1]) { - ReportError("Missing null-terminator in string material property"); - } - // Validate((const aiString*)prop->mData); - } - else if (aiPTI_Float == prop->mType) { - if (prop->mDataLength < sizeof(float)) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain a float (%i, needed: %i)", - i,prop->mDataLength, static_cast(sizeof(float))); - } - } - else if (aiPTI_Integer == prop->mType) { - if (prop->mDataLength < sizeof(int)) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain an integer (%i, needed: %i)", - i,prop->mDataLength, static_cast(sizeof(int))); - } - } - // TODO: check whether there is a key with an unknown name ... - } - - // make some more specific tests - ai_real fTemp; - int iShading; - if (AI_SUCCESS == aiGetMaterialInteger( pMaterial,AI_MATKEY_SHADING_MODEL,&iShading)) { - switch ((aiShadingMode)iShading) - { - case aiShadingMode_Blinn: - case aiShadingMode_CookTorrance: - case aiShadingMode_Phong: - - if (AI_SUCCESS != aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS,&fTemp)) { - ReportWarning("A specular shading model is specified but there is no " - "AI_MATKEY_SHININESS key"); - } - if (AI_SUCCESS == aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS_STRENGTH,&fTemp) && !fTemp) { - ReportWarning("A specular shading model is specified but the value of the " - "AI_MATKEY_SHININESS_STRENGTH key is 0.0"); - } - break; - default: - break; - } - } - - if (AI_SUCCESS == aiGetMaterialFloat( pMaterial,AI_MATKEY_OPACITY,&fTemp) && (!fTemp || fTemp > 1.01)) { - ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)"); - } - - // Check whether there are invalid texture keys - // TODO: that's a relict of the past, where texture type and index were baked - // into the material string ... we could do that in one single pass. - SearchForInvalidTextures(pMaterial,aiTextureType_DIFFUSE); - SearchForInvalidTextures(pMaterial,aiTextureType_SPECULAR); - SearchForInvalidTextures(pMaterial,aiTextureType_AMBIENT); - SearchForInvalidTextures(pMaterial,aiTextureType_EMISSIVE); - SearchForInvalidTextures(pMaterial,aiTextureType_OPACITY); - SearchForInvalidTextures(pMaterial,aiTextureType_SHININESS); - SearchForInvalidTextures(pMaterial,aiTextureType_HEIGHT); - SearchForInvalidTextures(pMaterial,aiTextureType_NORMALS); - SearchForInvalidTextures(pMaterial,aiTextureType_DISPLACEMENT); - SearchForInvalidTextures(pMaterial,aiTextureType_LIGHTMAP); - SearchForInvalidTextures(pMaterial,aiTextureType_REFLECTION); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiTexture* pTexture) -{ - // the data section may NEVER be NULL - if (!pTexture->pcData) { - ReportError("aiTexture::pcData is NULL"); - } - if (pTexture->mHeight) - { - if (!pTexture->mWidth){ - ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)", - pTexture->mHeight); - } - } - else - { - if (!pTexture->mWidth) { - ReportError("aiTexture::mWidth is zero (compressed texture)"); - } - if ('\0' != pTexture->achFormatHint[3]) { - ReportWarning("aiTexture::achFormatHint must be zero-terminated"); - } - else if ('.' == pTexture->achFormatHint[0]) { - ReportWarning("aiTexture::achFormatHint should contain a file extension " - "without a leading dot (format hint: %s).",pTexture->achFormatHint); - } - } - - const char* sz = pTexture->achFormatHint; - if ((sz[0] >= 'A' && sz[0] <= 'Z') || - (sz[1] >= 'A' && sz[1] <= 'Z') || - (sz[2] >= 'A' && sz[2] <= 'Z') || - (sz[3] >= 'A' && sz[3] <= 'Z')) { - ReportError("aiTexture::achFormatHint contains non-lowercase letters"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiAnimation* pAnimation, - const aiNodeAnim* pNodeAnim) -{ - Validate(&pNodeAnim->mNodeName); - - if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) { - ReportError("Empty node animation channel"); - } - // otherwise check whether one of the keys exceeds the total duration of the animation - if (pNodeAnim->mNumPositionKeys) - { - if (!pNodeAnim->mPositionKeys) - { - ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)", - pNodeAnim->mNumPositionKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys;++i) - { - // ScenePreprocessor will compute the duration if still the default value - // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, - // seems to be due the compilers register usage/width. - if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mPositionKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mPositionKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mPositionKeys[i].mTime; - } - } - // rotation keys - if (pNodeAnim->mNumRotationKeys) - { - if (!pNodeAnim->mRotationKeys) - { - ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)", - pNodeAnim->mNumRotationKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys;++i) - { - if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mRotationKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mRotationKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mRotationKeys[i].mTime; - } - } - // scaling keys - if (pNodeAnim->mNumScalingKeys) - { - if (!pNodeAnim->mScalingKeys) { - ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)", - pNodeAnim->mNumScalingKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys;++i) - { - if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mScalingKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mScalingKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mScalingKeys[i].mTime; - } - } - - if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys && - !pNodeAnim->mNumPositionKeys) - { - ReportError("A node animation channel must have at least one subtrack"); - } -} - -void ValidateDSProcess::Validate( const aiAnimation* pAnimation, - const aiMeshMorphAnim* pMeshMorphAnim) -{ - Validate(&pMeshMorphAnim->mName); - - if (!pMeshMorphAnim->mNumKeys) { - ReportError("Empty mesh morph animation channel"); - } - - // otherwise check whether one of the keys exceeds the total duration of the animation - if (pMeshMorphAnim->mNumKeys) - { - if (!pMeshMorphAnim->mKeys) - { - ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)", - pMeshMorphAnim->mNumKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i) - { - // ScenePreprocessor will compute the duration if still the default value - // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, - // seems to be due the compilers register usage/width. - if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pMeshMorphAnim->mKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast) - { - ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller " - "than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i, - (float)pMeshMorphAnim->mKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pMeshMorphAnim->mKeys[i].mTime; - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiNode* pNode) -{ - if (!pNode) { - ReportError("A node of the scenegraph is NULL"); - } - // Validate node name string first so that it's safe to use in below expressions - this->Validate(&pNode->mName); - const char* nodeName = (&pNode->mName)->C_Str(); - if (pNode != mScene->mRootNode && !pNode->mParent){ - ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is NULL) ", nodeName); - } - - // validate all meshes - if (pNode->mNumMeshes) - { - if (!pNode->mMeshes) - { - ReportError("aiNode::mMeshes is NULL for node %s (aiNode::mNumMeshes is %i)", - nodeName, pNode->mNumMeshes); - } - std::vector abHadMesh; - abHadMesh.resize(mScene->mNumMeshes,false); - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) - { - if (pNode->mMeshes[i] >= mScene->mNumMeshes) - { - ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)", - pNode->mMeshes[i], nodeName, mScene->mNumMeshes-1); - } - if (abHadMesh[pNode->mMeshes[i]]) - { - ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)", - i, nodeName, pNode->mMeshes[i]); - } - abHadMesh[pNode->mMeshes[i]] = true; - } - } - if (pNode->mNumChildren) - { - if (!pNode->mChildren) { - ReportError("aiNode::mChildren is NULL for node %s (aiNode::mNumChildren is %i)", - nodeName, pNode->mNumChildren); - } - for (unsigned int i = 0; i < pNode->mNumChildren;++i) { - Validate(pNode->mChildren[i]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiString* pString) -{ - if (pString->length > MAXLEN) - { - ReportError("aiString::length is too large (%u, maximum is %lu)", - pString->length,MAXLEN); - } - const char* sz = pString->data; - while (true) - { - if ('\0' == *sz) - { - if (pString->length != (unsigned int)(sz-pString->data)) { - ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); - } - break; - } - else if (sz >= &pString->data[MAXLEN]) { - ReportError("aiString::data is invalid. There is no terminal character"); - } - ++sz; - } -} diff --git a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h b/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h deleted file mode 100644 index 7b309c925151..000000000000 --- a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -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 Defines a (dummy) post processing step to validate the loader's - * output data structure (for debugging) - */ -#ifndef AI_VALIDATEPROCESS_H_INC -#define AI_VALIDATEPROCESS_H_INC - -#include -#include - -#include "Common/BaseProcess.h" - -struct aiBone; -struct aiMesh; -struct aiAnimation; -struct aiNodeAnim; -struct aiMeshMorphAnim; -struct aiTexture; -struct aiMaterial; -struct aiNode; -struct aiString; -struct aiCamera; -struct aiLight; - -namespace Assimp { - -// -------------------------------------------------------------------------------------- -/** Validates the whole ASSIMP scene data structure for correctness. - * ImportErrorException is thrown of the scene is corrupt.*/ -// -------------------------------------------------------------------------------------- -class ValidateDSProcess : public BaseProcess -{ -public: - - ValidateDSProcess(); - ~ValidateDSProcess(); - -public: - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Report a validation error. This will throw an exception, - * control won't return. - * @param msg Format string for sprintf().*/ - AI_WONT_RETURN void ReportError(const char* msg,...) AI_WONT_RETURN_SUFFIX; - - - // ------------------------------------------------------------------- - /** Report a validation warning. This won't throw an exception, - * control will return to the caller. - * @param msg Format string for sprintf().*/ - void ReportWarning(const char* msg,...); - - - // ------------------------------------------------------------------- - /** Validates a mesh - * @param pMesh Input mesh*/ - void Validate( const aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Validates a bone - * @param pMesh Input mesh - * @param pBone Input bone*/ - void Validate( const aiMesh* pMesh,const aiBone* pBone,float* afSum); - - // ------------------------------------------------------------------- - /** Validates an animation - * @param pAnimation Input animation*/ - void Validate( const aiAnimation* pAnimation); - - // ------------------------------------------------------------------- - /** Validates a material - * @param pMaterial Input material*/ - void Validate( const aiMaterial* pMaterial); - - // ------------------------------------------------------------------- - /** Search the material data structure for invalid or corrupt - * texture keys. - * @param pMaterial Input material - * @param type Type of the texture*/ - void SearchForInvalidTextures(const aiMaterial* pMaterial, - aiTextureType type); - - // ------------------------------------------------------------------- - /** Validates a texture - * @param pTexture Input texture*/ - void Validate( const aiTexture* pTexture); - - // ------------------------------------------------------------------- - /** Validates a light source - * @param pLight Input light - */ - void Validate( const aiLight* pLight); - - // ------------------------------------------------------------------- - /** Validates a camera - * @param pCamera Input camera*/ - void Validate( const aiCamera* pCamera); - - // ------------------------------------------------------------------- - /** Validates a bone animation channel - * @param pAnimation Animation channel. - * @param pBoneAnim Input bone animation */ - void Validate( const aiAnimation* pAnimation, - const aiNodeAnim* pBoneAnim); - - /** Validates a mesh morph animation channel. - * @param pAnimation Input animation. - * @param pMeshMorphAnim Mesh morph animation channel. - * */ - void Validate( const aiAnimation* pAnimation, - const aiMeshMorphAnim* pMeshMorphAnim); - - // ------------------------------------------------------------------- - /** Validates a node and all of its subnodes - * @param Node Input node*/ - void Validate( const aiNode* pNode); - - // ------------------------------------------------------------------- - /** Validates a string - * @param pString Input string*/ - void Validate( const aiString* pString); - -private: - - // template to validate one of the aiScene::mXXX arrays - template - inline void DoValidation(T** array, unsigned int size, - const char* firstName, const char* secondName); - - // extended version: checks whether T::mName occurs twice - template - inline void DoValidationEx(T** array, unsigned int size, - const char* firstName, const char* secondName); - - // extension to the first template which does also search - // the nodegraph for an item with the same name - template - inline void DoValidationWithNameCheck(T** array, unsigned int size, - const char* firstName, const char* secondName); - - aiScene* mScene; -}; - - - - -} // end of namespace Assimp - -#endif // AI_VALIDATEPROCESS_H_INC diff --git a/thirdparty/assimp/contrib/utf8cpp/source/utf8.h b/thirdparty/assimp/contrib/utf8cpp/source/utf8.h deleted file mode 100644 index 82b13f59f983..000000000000 --- a/thirdparty/assimp/contrib/utf8cpp/source/utf8.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "utf8/checked.h" -#include "utf8/unchecked.h" - -#endif // header guard diff --git a/thirdparty/assimp/contrib/utf8cpp/source/utf8/checked.h b/thirdparty/assimp/contrib/utf8cpp/source/utf8/checked.h deleted file mode 100644 index 133115513814..000000000000 --- a/thirdparty/assimp/contrib/utf8cpp/source/utf8/checked.h +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "core.h" -#include - -namespace utf8 -{ - // Base for the exceptions that may be thrown from the library - class exception : public ::std::exception { - }; - - // Exceptions that may be thrown from the library functions. - class invalid_code_point : public exception { - uint32_t cp; - public: - invalid_code_point(uint32_t cp) : cp(cp) {} - virtual const char* what() const throw() { return "Invalid code point"; } - uint32_t code_point() const {return cp;} - }; - - class invalid_utf8 : public exception { - uint8_t u8; - public: - invalid_utf8 (uint8_t u) : u8(u) {} - virtual const char* what() const throw() { return "Invalid UTF-8"; } - uint8_t utf8_octet() const {return u8;} - }; - - class invalid_utf16 : public exception { - uint16_t u16; - public: - invalid_utf16 (uint16_t u) : u16(u) {} - virtual const char* what() const throw() { return "Invalid UTF-16"; } - uint16_t utf16_word() const {return u16;} - }; - - class not_enough_room : public exception { - public: - virtual const char* what() const throw() { return "Not enough space"; } - }; - - /// The library API - functions intended to be called by the users - - template - octet_iterator append(uint32_t cp, octet_iterator result) - { - if (!utf8::internal::is_code_point_valid(cp)) - throw invalid_code_point(cp); - - if (cp < 0x80) // one octet - *(result++) = static_cast(cp); - else if (cp < 0x800) { // two octets - *(result++) = static_cast((cp >> 6) | 0xc0); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else if (cp < 0x10000) { // three octets - *(result++) = static_cast((cp >> 12) | 0xe0); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else { // four octets - *(result++) = static_cast((cp >> 18) | 0xf0); - *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - return result; - } - - template - output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) - { - while (start != end) { - octet_iterator sequence_start = start; - internal::utf_error err_code = utf8::internal::validate_next(start, end); - switch (err_code) { - case internal::UTF8_OK : - for (octet_iterator it = sequence_start; it != start; ++it) - *out++ = *it; - break; - case internal::NOT_ENOUGH_ROOM: - throw not_enough_room(); - case internal::INVALID_LEAD: - out = utf8::append (replacement, out); - ++start; - break; - case internal::INCOMPLETE_SEQUENCE: - case internal::OVERLONG_SEQUENCE: - case internal::INVALID_CODE_POINT: - out = utf8::append (replacement, out); - ++start; - // just one replacement mark for the sequence - while (start != end && utf8::internal::is_trail(*start)) - ++start; - break; - } - } - return out; - } - - template - inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) - { - static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); - return utf8::replace_invalid(start, end, out, replacement_marker); - } - - template - uint32_t next(octet_iterator& it, octet_iterator end) - { - uint32_t cp = 0; - internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); - switch (err_code) { - case internal::UTF8_OK : - break; - case internal::NOT_ENOUGH_ROOM : - throw not_enough_room(); - case internal::INVALID_LEAD : - case internal::INCOMPLETE_SEQUENCE : - case internal::OVERLONG_SEQUENCE : - throw invalid_utf8(*it); - case internal::INVALID_CODE_POINT : - throw invalid_code_point(cp); - } - return cp; - } - - template - uint32_t peek_next(octet_iterator it, octet_iterator end) - { - return utf8::next(it, end); - } - - template - uint32_t prior(octet_iterator& it, octet_iterator start) - { - // can't do much if it == start - if (it == start) - throw not_enough_room(); - - octet_iterator end = it; - // Go back until we hit either a lead octet or start - while (utf8::internal::is_trail(*(--it))) - if (it == start) - throw invalid_utf8(*it); // error - no lead byte in the sequence - return utf8::peek_next(it, end); - } - - /// Deprecated in versions that include "prior" - template - uint32_t previous(octet_iterator& it, octet_iterator pass_start) - { - octet_iterator end = it; - while (utf8::internal::is_trail(*(--it))) - if (it == pass_start) - throw invalid_utf8(*it); // error - no lead byte in the sequence - octet_iterator temp = it; - return utf8::next(temp, end); - } - - template - void advance (octet_iterator& it, distance_type n, octet_iterator end) - { - for (distance_type i = 0; i < n; ++i) - utf8::next(it, end); - } - - template - typename std::iterator_traits::difference_type - distance (octet_iterator first, octet_iterator last) - { - typename std::iterator_traits::difference_type dist; - for (dist = 0; first < last; ++dist) - utf8::next(first, last); - return dist; - } - - template - octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) - { - while (start != end) { - uint32_t cp = utf8::internal::mask16(*start++); - // Take care of surrogate pairs first - if (utf8::internal::is_lead_surrogate(cp)) { - if (start != end) { - uint32_t trail_surrogate = utf8::internal::mask16(*start++); - if (utf8::internal::is_trail_surrogate(trail_surrogate)) - cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; - else - throw invalid_utf16(static_cast(trail_surrogate)); - } - else - throw invalid_utf16(static_cast(cp)); - - } - // Lone trail surrogate - else if (utf8::internal::is_trail_surrogate(cp)) - throw invalid_utf16(static_cast(cp)); - - result = utf8::append(cp, result); - } - return result; - } - - template - u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) - { - while (start != end) { - uint32_t cp = utf8::next(start, end); - if (cp > 0xffff) { //make a surrogate pair - *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); - *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); - } - else - *result++ = static_cast(cp); - } - return result; - } - - template - octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) - { - while (start != end) - result = utf8::append(*(start++), result); - - return result; - } - - template - u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) - { - while (start != end) - (*result++) = utf8::next(start, end); - - return result; - } - - // The iterator class - template - class iterator : public std::iterator { - octet_iterator it; - octet_iterator range_start; - octet_iterator range_end; - public: - iterator () {} - explicit iterator (const octet_iterator& octet_it, - const octet_iterator& range_start, - const octet_iterator& range_end) : - it(octet_it), range_start(range_start), range_end(range_end) - { - if (it < range_start || it > range_end) - throw std::out_of_range("Invalid utf-8 iterator position"); - } - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return utf8::next(temp, range_end); - } - bool operator == (const iterator& rhs) const - { - if (range_start != rhs.range_start || range_end != rhs.range_end) - throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - utf8::next(it, range_end); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - utf8::next(it, range_end); - return temp; - } - iterator& operator -- () - { - utf8::prior(it, range_start); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - utf8::prior(it, range_start); - return temp; - } - }; // class iterator - -} // namespace utf8 - -#endif //header guard - - diff --git a/thirdparty/assimp/contrib/utf8cpp/source/utf8/core.h b/thirdparty/assimp/contrib/utf8cpp/source/utf8/core.h deleted file mode 100644 index 693d388c078d..000000000000 --- a/thirdparty/assimp/contrib/utf8cpp/source/utf8/core.h +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include - -namespace utf8 -{ - // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers - // You may need to change them to match your system. - // These typedefs have the same names as ones from cstdint, or boost/cstdint - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - -// Helper code - not intended to be directly called by the library users. May be changed at any time -namespace internal -{ - // Unicode constants - // Leading (high) surrogates: 0xd800 - 0xdbff - // Trailing (low) surrogates: 0xdc00 - 0xdfff - const uint16_t LEAD_SURROGATE_MIN = 0xd800u; - const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; - const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; - const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; - const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); - const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; - - // Maximum valid value for a Unicode code point - const uint32_t CODE_POINT_MAX = 0x0010ffffu; - - template - inline uint8_t mask8(octet_type oc) - { - return static_cast(0xff & oc); - } - template - inline uint16_t mask16(u16_type oc) - { - return static_cast(0xffff & oc); - } - template - inline bool is_trail(octet_type oc) - { - return ((utf8::internal::mask8(oc) >> 6) == 0x2); - } - - template - inline bool is_lead_surrogate(u16 cp) - { - return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); - } - - template - inline bool is_trail_surrogate(u16 cp) - { - return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); - } - - template - inline bool is_surrogate(u16 cp) - { - return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); - } - - template - inline bool is_code_point_valid(u32 cp) - { - return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); - } - - template - inline typename std::iterator_traits::difference_type - sequence_length(octet_iterator lead_it) - { - uint8_t lead = utf8::internal::mask8(*lead_it); - if (lead < 0x80) - return 1; - else if ((lead >> 5) == 0x6) - return 2; - else if ((lead >> 4) == 0xe) - return 3; - else if ((lead >> 3) == 0x1e) - return 4; - else - return 0; - } - - template - inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) - { - if (cp < 0x80) { - if (length != 1) - return true; - } - else if (cp < 0x800) { - if (length != 2) - return true; - } - else if (cp < 0x10000) { - if (length != 3) - return true; - } - - return false; - } - - enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; - - /// Helper for get_sequence_x - template - utf_error increase_safely(octet_iterator& it, octet_iterator end) - { - if (++it == end) - return NOT_ENOUGH_ROOM; - - if (!utf8::internal::is_trail(*it)) - return INCOMPLETE_SEQUENCE; - - return UTF8_OK; - } - - #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} - - /// get_sequence_x functions decode utf-8 sequences of the length x - template - utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - return UTF8_OK; - } - - template - utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); - - return UTF8_OK; - } - - template - utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (*it) & 0x3f; - - return UTF8_OK; - } - - template - utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - if (it == end) - return NOT_ENOUGH_ROOM; - - code_point = utf8::internal::mask8(*it); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; - - UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) - - code_point += (*it) & 0x3f; - - return UTF8_OK; - } - - #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR - - template - utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) - { - // Save the original value of it so we can go back in case of failure - // Of course, it does not make much sense with i.e. stream iterators - octet_iterator original_it = it; - - uint32_t cp = 0; - // Determine the sequence length based on the lead octet - typedef typename std::iterator_traits::difference_type octet_difference_type; - const octet_difference_type length = utf8::internal::sequence_length(it); - - // Get trail octets and calculate the code point - utf_error err = UTF8_OK; - switch (length) { - case 0: - return INVALID_LEAD; - case 1: - err = utf8::internal::get_sequence_1(it, end, cp); - break; - case 2: - err = utf8::internal::get_sequence_2(it, end, cp); - break; - case 3: - err = utf8::internal::get_sequence_3(it, end, cp); - break; - case 4: - err = utf8::internal::get_sequence_4(it, end, cp); - break; - } - - if (err == UTF8_OK) { - // Decoding succeeded. Now, security checks... - if (utf8::internal::is_code_point_valid(cp)) { - if (!utf8::internal::is_overlong_sequence(cp, length)){ - // Passed! Return here. - code_point = cp; - ++it; - return UTF8_OK; - } - else - err = OVERLONG_SEQUENCE; - } - else - err = INVALID_CODE_POINT; - } - - // Failure branch - restore the original value of the iterator - it = original_it; - return err; - } - - template - inline utf_error validate_next(octet_iterator& it, octet_iterator end) { - uint32_t ignored; - return utf8::internal::validate_next(it, end, ignored); - } - -} // namespace internal - - /// The library API - functions intended to be called by the users - - // Byte order mark - const uint8_t bom[] = {0xef, 0xbb, 0xbf}; - - template - octet_iterator find_invalid(octet_iterator start, octet_iterator end) - { - octet_iterator result = start; - while (result != end) { - utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); - if (err_code != internal::UTF8_OK) - return result; - } - return result; - } - - template - inline bool is_valid(octet_iterator start, octet_iterator end) - { - return (utf8::find_invalid(start, end) == end); - } - - template - inline bool starts_with_bom (octet_iterator it, octet_iterator end) - { - return ( - ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && - ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && - ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) - ); - } - - //Deprecated in release 2.3 - template - inline bool is_bom (octet_iterator it) - { - return ( - (utf8::internal::mask8(*it++)) == bom[0] && - (utf8::internal::mask8(*it++)) == bom[1] && - (utf8::internal::mask8(*it)) == bom[2] - ); - } -} // namespace utf8 - -#endif // header guard - - diff --git a/thirdparty/assimp/contrib/utf8cpp/source/utf8/unchecked.h b/thirdparty/assimp/contrib/utf8cpp/source/utf8/unchecked.h deleted file mode 100644 index cb2427166b19..000000000000 --- a/thirdparty/assimp/contrib/utf8cpp/source/utf8/unchecked.h +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2006 Nemanja Trifunovic - -/* -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 - -#include "core.h" - -namespace utf8 -{ - namespace unchecked - { - template - octet_iterator append(uint32_t cp, octet_iterator result) - { - if (cp < 0x80) // one octet - *(result++) = static_cast(cp); - else if (cp < 0x800) { // two octets - *(result++) = static_cast((cp >> 6) | 0xc0); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else if (cp < 0x10000) { // three octets - *(result++) = static_cast((cp >> 12) | 0xe0); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - else { // four octets - *(result++) = static_cast((cp >> 18) | 0xf0); - *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); - *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); - *(result++) = static_cast((cp & 0x3f) | 0x80); - } - return result; - } - - template - uint32_t next(octet_iterator& it) - { - uint32_t cp = utf8::internal::mask8(*it); - typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); - switch (length) { - case 1: - break; - case 2: - it++; - cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); - break; - case 3: - ++it; - cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); - ++it; - cp += (*it) & 0x3f; - break; - case 4: - ++it; - cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); - ++it; - cp += (utf8::internal::mask8(*it) << 6) & 0xfff; - ++it; - cp += (*it) & 0x3f; - break; - } - ++it; - return cp; - } - - template - uint32_t peek_next(octet_iterator it) - { - return utf8::unchecked::next(it); - } - - template - uint32_t prior(octet_iterator& it) - { - while (utf8::internal::is_trail(*(--it))) ; - octet_iterator temp = it; - return utf8::unchecked::next(temp); - } - - // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) - template - inline uint32_t previous(octet_iterator& it) - { - return utf8::unchecked::prior(it); - } - - template - void advance (octet_iterator& it, distance_type n) - { - for (distance_type i = 0; i < n; ++i) - utf8::unchecked::next(it); - } - - template - typename std::iterator_traits::difference_type - distance (octet_iterator first, octet_iterator last) - { - typename std::iterator_traits::difference_type dist; - for (dist = 0; first < last; ++dist) - utf8::unchecked::next(first); - return dist; - } - - template - octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) - { - while (start != end) { - uint32_t cp = utf8::internal::mask16(*start++); - // Take care of surrogate pairs first - if (utf8::internal::is_lead_surrogate(cp)) { - uint32_t trail_surrogate = utf8::internal::mask16(*start++); - cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; - } - result = utf8::unchecked::append(cp, result); - } - return result; - } - - template - u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) - { - while (start < end) { - uint32_t cp = utf8::unchecked::next(start); - if (cp > 0xffff) { //make a surrogate pair - *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); - *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); - } - else - *result++ = static_cast(cp); - } - return result; - } - - template - octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) - { - while (start != end) - result = utf8::unchecked::append(*(start++), result); - - return result; - } - - template - u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) - { - while (start < end) - (*result++) = utf8::unchecked::next(start); - - return result; - } - - // The iterator class - template - class iterator : public std::iterator { - octet_iterator it; - public: - iterator () {} - explicit iterator (const octet_iterator& octet_it): it(octet_it) {} - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return utf8::unchecked::next(temp); - } - bool operator == (const iterator& rhs) const - { - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - ::std::advance(it, utf8::internal::sequence_length(it)); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - ::std::advance(it, utf8::internal::sequence_length(it)); - return temp; - } - iterator& operator -- () - { - utf8::unchecked::prior(it); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - utf8::unchecked::prior(it); - return temp; - } - }; // class iterator - - } // namespace utf8::unchecked -} // namespace utf8 - - -#endif // header guard - diff --git a/thirdparty/assimp/include/assimp/.editorconfig b/thirdparty/assimp/include/assimp/.editorconfig deleted file mode 100644 index 9ea66423ad1a..000000000000 --- a/thirdparty/assimp/include/assimp/.editorconfig +++ /dev/null @@ -1,8 +0,0 @@ -# See for details - -[*.{h,hpp,inl}] -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_size = 4 -indent_style = space diff --git a/thirdparty/assimp/include/assimp/BaseImporter.h b/thirdparty/assimp/include/assimp/BaseImporter.h deleted file mode 100644 index ad8a3dafd86c..000000000000 --- a/thirdparty/assimp/include/assimp/BaseImporter.h +++ /dev/null @@ -1,420 +0,0 @@ -/* -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 Definition of the base class for all importer worker classes. */ -#pragma once -#ifndef INCLUDED_AI_BASEIMPORTER_H -#define INCLUDED_AI_BASEIMPORTER_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include "Exceptional.h" - -#include -#include -#include -#include -#include -#include - -struct aiScene; -struct aiImporterDesc; - -namespace Assimp { - -class Importer; -class IOSystem; -class BaseProcess; -class SharedPostProcessInfo; -class IOStream; - -// utility to do char4 to uint32 in a portable manner -#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ - (string[1] << 16) + (string[2] << 8) + string[3])) - - -// --------------------------------------------------------------------------- -/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface - * for all importer worker classes. - * - * The interface defines two functions: CanRead() is used to check if the - * importer can handle the format of the given file. If an implementation of - * this function returns true, the importer then calls ReadFile() which - * imports the given file. ReadFile is not overridable, it just calls - * InternReadFile() and catches any ImportErrorException that might occur. - */ -class ASSIMP_API BaseImporter { - friend class Importer; - -private: - /* Pushes state into importer for the importer scale */ - virtual void UpdateImporterScale( Importer* pImp ); - -public: - - /** Constructor to be privately used by #Importer */ - BaseImporter() AI_NO_EXCEPT; - - /** Destructor, private as well */ - virtual ~BaseImporter(); - - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * - * The implementation should be as quick as possible. A check for - * the file extension is enough. If no suitable loader is found with - * this strategy, CanRead() is called again, the 'checkSig' parameter - * set to true this time. Now the implementation is expected to - * perform a full check of the file structure, possibly searching the - * first bytes of the file for magic identifiers or keywords. - * - * @param pFile Path and file name of the file to be examined. - * @param pIOHandler The IO handler to use for accessing any file. - * @param checkSig Set to true if this method is called a second time. - * This time, the implementation may take more time to examine the - * contents of the file to be loaded for magic bytes, keywords, etc - * to be able to load files with unknown/not existent file extensions. - * @return true if the class can read this file, false if not. - */ - virtual bool CanRead( - const std::string& pFile, - IOSystem* pIOHandler, - bool checkSig - ) const = 0; - - // ------------------------------------------------------------------- - /** Imports the given file and returns the imported data. - * If the import succeeds, ownership of the data is transferred to - * the caller. If the import fails, NULL is returned. The function - * takes care that any partially constructed data is destroyed - * beforehand. - * - * @param pImp #Importer object hosting this loader. - * @param pFile Path of the file to be imported. - * @param pIOHandler IO-Handler used to open this and possible other files. - * @return The imported data or NULL if failed. If it failed a - * human-readable error description can be retrieved by calling - * GetErrorText() - * - * @note This function is not intended to be overridden. Implement - * InternReadFile() to do the import. If an exception is thrown somewhere - * in InternReadFile(), this function will catch it and transform it into - * a suitable response to the caller. - */ - aiScene* ReadFile( - Importer* pImp, - const std::string& pFile, - IOSystem* pIOHandler - ); - - // ------------------------------------------------------------------- - /** Returns the error description of the last error that occurred. - * @return A description of the last error that occurred. An empty - * string if there was no error. - */ - const std::string& GetErrorText() const { - return m_ErrorText; - } - - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - * @param pImp Importer instance - */ - virtual void SetupProperties( - const Importer* pImp - ); - - // ------------------------------------------------------------------- - /** Called by #Importer::GetImporterInfo to get a description of - * some loader features. Importers must provide this information. */ - virtual const aiImporterDesc* GetInfo() const = 0; - - /** - * Will be called only by scale process when scaling is requested. - */ - virtual void SetFileScale(double scale) - { - fileScale = scale; - } - - virtual double GetFileScale() const - { - return fileScale; - } - - enum ImporterUnits { - M, - MM, - CM, - INCHES, - FEET - }; - - /** - * Assimp Importer - * unit conversions available - * NOTE: Valid options are initialised in the - * constructor in the implementation file to - * work around a VS2013 compiler bug if support - * for that compiler is dropped in the future - * initialisation can be moved back here - * */ - std::map importerUnits; - - virtual void SetApplicationUnits( const ImporterUnits& unit ) - { - importerScale = importerUnits[unit]; - applicationUnits = unit; - } - - virtual const ImporterUnits& GetApplicationUnits() - { - return applicationUnits; - } - - // ------------------------------------------------------------------- - /** Called by #Importer::GetExtensionList for each loaded importer. - * Take the extension list contained in the structure returned by - * #GetInfo and insert all file extensions into the given set. - * @param extension set to collect file extensions in*/ - void GetExtensionList(std::set& extensions); - -protected: - ImporterUnits applicationUnits = ImporterUnits::M; - double importerScale = 1.0; - double fileScale = 1.0; - - - - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. The - * function is expected to throw an ImportErrorException if there is - * an error. If it terminates normally, the data in aiScene is - * expected to be correct. Override this function to implement the - * actual importing. - *
- * The output scene must meet the following requirements:
- *
    - *
  • At least a root node must be there, even if its only purpose - * is to reference one mesh.
  • - *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives - * in the mesh are determined automatically in this case.
  • - *
  • the vertex data is stored in a pseudo-indexed "verbose" format. - * In fact this means that every vertex that is referenced by - * a face is unique. Or the other way round: a vertex index may - * not occur twice in a single aiMesh.
  • - *
  • aiAnimation::mDuration may be -1. Assimp determines the length - * of the animation automatically in this case as the length of - * the longest animation channel.
  • - *
  • aiMesh::mBitangents may be NULL if tangents and normals are - * given. In this case bitangents are computed as the cross product - * between normal and tangent.
  • - *
  • There needn't be a material. If none is there a default material - * is generated. However, it is recommended practice for loaders - * to generate a default material for yourself that matches the - * default material setting for the file format better than Assimp's - * generic default material. Note that default materials *should* - * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded - * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) - * texture.
  • - *
- * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    - *
  • at least one mesh must be there
  • - *
  • there may be no meshes with 0 vertices or faces
  • - *
- * This won't be checked (except by the validation step): Assimp will - * crash if one of the conditions is not met! - * - * @param pFile Path of the file to be imported. - * @param pScene The scene object to hold the imported data. - * NULL is not a valid parameter. - * @param pIOHandler The IO handler to use for any file access. - * NULL is not a valid parameter. */ - virtual void InternReadFile( - const std::string& pFile, - aiScene* pScene, - IOSystem* pIOHandler - ) = 0; - -public: // static utilities - - // ------------------------------------------------------------------- - /** A utility for CanRead(). - * - * The function searches the header of a file for a specific token - * and returns true if this token is found. This works for text - * files only. There is a rudimentary handling of UNICODE files. - * The comparison is case independent. - * - * @param pIOSystem IO System to work with - * @param file File name of the file - * @param tokens List of tokens to search for - * @param numTokens Size of the token array - * @param searchBytes Number of bytes to be searched for the tokens. - */ - static bool SearchFileHeaderForToken( - IOSystem* pIOSystem, - const std::string& file, - const char** tokens, - unsigned int numTokens, - unsigned int searchBytes = 200, - bool tokensSol = false, - bool noAlphaBeforeTokens = false); - - // ------------------------------------------------------------------- - /** @brief Check whether a file has a specific file extension - * @param pFile Input file - * @param ext0 Extension to check for. Lowercase characters only, no dot! - * @param ext1 Optional second extension - * @param ext2 Optional third extension - * @note Case-insensitive - */ - static bool SimpleExtensionCheck ( - const std::string& pFile, - const char* ext0, - const char* ext1 = NULL, - const char* ext2 = NULL); - - // ------------------------------------------------------------------- - /** @brief Extract file extension from a string - * @param pFile Input file - * @return Extension without trailing dot, all lowercase - */ - static std::string GetExtension ( - const std::string& pFile); - - // ------------------------------------------------------------------- - /** @brief Check whether a file starts with one or more magic tokens - * @param pFile Input file - * @param pIOHandler IO system to be used - * @param magic n magic tokens - * @params num Size of magic - * @param offset Offset from file start where tokens are located - * @param Size of one token, in bytes. Maximally 16 bytes. - * @return true if one of the given tokens was found - * - * @note For convenience, the check is also performed for the - * byte-swapped variant of all tokens (big endian). Only for - * tokens of size 2,4. - */ - static bool CheckMagicToken( - IOSystem* pIOHandler, - const std::string& pFile, - const void* magic, - unsigned int num, - unsigned int offset = 0, - unsigned int size = 4); - - // ------------------------------------------------------------------- - /** An utility for all text file loaders. It converts a file to our - * UTF8 character set. Errors are reported, but ignored. - * - * @param data File buffer to be converted to UTF8 data. The buffer - * is resized as appropriate. */ - static void ConvertToUTF8( - std::vector& data); - - // ------------------------------------------------------------------- - /** An utility for all text file loaders. It converts a file from our - * UTF8 character set back to ISO-8859-1. Errors are reported, but ignored. - * - * @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer - * is resized as appropriate. */ - static void ConvertUTF8toISO8859_1( - std::string& data); - - // ------------------------------------------------------------------- - /// @brief Enum to define, if empty files are ok or not. - enum TextFileMode { - ALLOW_EMPTY, - FORBID_EMPTY - }; - - // ------------------------------------------------------------------- - /** Utility for text file loaders which copies the contents of the - * file into a memory buffer and converts it to our UTF8 - * representation. - * @param stream Stream to read from. - * @param data Output buffer to be resized and filled with the - * converted text file data. The buffer is terminated with - * a binary 0. - * @param mode Whether it is OK to load empty text files. */ - static void TextFileToBuffer( - IOStream* stream, - std::vector& data, - TextFileMode mode = FORBID_EMPTY); - - // ------------------------------------------------------------------- - /** Utility function to move a std::vector into a aiScene array - * @param vec The vector to be moved - * @param out The output pointer to the allocated array. - * @param numOut The output count of elements copied. */ - template - AI_FORCE_INLINE - static void CopyVector( - std::vector& vec, - T*& out, - unsigned int& outLength) - { - outLength = unsigned(vec.size()); - if (outLength) { - out = new T[outLength]; - std::swap_ranges(vec.begin(), vec.end(), out); - } - } - -protected: - /// Error description in case there was one. - std::string m_ErrorText; - /// Currently set progress handler. - ProgressHandler* m_progress; -}; - - - -} // end of namespace Assimp - -#endif // AI_BASEIMPORTER_H_INC diff --git a/thirdparty/assimp/include/assimp/Bitmap.h b/thirdparty/assimp/include/assimp/Bitmap.h deleted file mode 100644 index 4c3f5a437b45..000000000000 --- a/thirdparty/assimp/include/assimp/Bitmap.h +++ /dev/null @@ -1,129 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Bitmap.h - * @brief Defines bitmap format helper for textures - * - * Used for file formats which embed their textures into the model file. - */ -#pragma once -#ifndef AI_BITMAP_H_INC -#define AI_BITMAP_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include "defs.h" -#include -#include - -struct aiTexture; - -namespace Assimp { - -class IOStream; - -class ASSIMP_API Bitmap { -protected: - - struct Header { - uint16_t type; - uint32_t size; - uint16_t reserved1; - uint16_t reserved2; - uint32_t offset; - - // We define the struct size because sizeof(Header) might return a wrong result because of structure padding. - // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). - static const std::size_t header_size = - sizeof(uint16_t) + // type - sizeof(uint32_t) + // size - sizeof(uint16_t) + // reserved1 - sizeof(uint16_t) + // reserved2 - sizeof(uint32_t); // offset - }; - - struct DIB { - uint32_t size; - int32_t width; - int32_t height; - uint16_t planes; - uint16_t bits_per_pixel; - uint32_t compression; - uint32_t image_size; - int32_t x_resolution; - int32_t y_resolution; - uint32_t nb_colors; - uint32_t nb_important_colors; - - // We define the struct size because sizeof(DIB) might return a wrong result because of structure padding. - // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). - static const std::size_t dib_size = - sizeof(uint32_t) + // size - sizeof(int32_t) + // width - sizeof(int32_t) + // height - sizeof(uint16_t) + // planes - sizeof(uint16_t) + // bits_per_pixel - sizeof(uint32_t) + // compression - sizeof(uint32_t) + // image_size - sizeof(int32_t) + // x_resolution - sizeof(int32_t) + // y_resolution - sizeof(uint32_t) + // nb_colors - sizeof(uint32_t); // nb_important_colors - }; - - static const std::size_t mBytesPerPixel = 4; - -public: - static void Save(aiTexture* texture, IOStream* file); - -protected: - static void WriteHeader(Header& header, IOStream* file); - static void WriteDIB(DIB& dib, IOStream* file); - static void WriteData(aiTexture* texture, IOStream* file); -}; - -} - -#endif // AI_BITMAP_H_INC diff --git a/thirdparty/assimp/include/assimp/BlobIOSystem.h b/thirdparty/assimp/include/assimp/BlobIOSystem.h deleted file mode 100644 index d005e5c119dc..000000000000 --- a/thirdparty/assimp/include/assimp/BlobIOSystem.h +++ /dev/null @@ -1,338 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Provides cheat implementations for IOSystem and IOStream to - * redirect exporter output to a blob chain.*/ - -#ifndef AI_BLOBIOSYSTEM_H_INCLUDED -#define AI_BLOBIOSYSTEM_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -namespace Assimp { - class BlobIOSystem; - -// -------------------------------------------------------------------------------------------- -/** Redirect IOStream to a blob */ -// -------------------------------------------------------------------------------------------- -class BlobIOStream : public IOStream -{ -public: - - BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096) - : buffer() - , cur_size() - , file_size() - , cursor() - , initial(initial) - , file(file) - , creator(creator) - { - } - - - virtual ~BlobIOStream(); - -public: - - // ------------------------------------------------------------------- - aiExportDataBlob* GetBlob() - { - aiExportDataBlob* blob = new aiExportDataBlob(); - blob->size = file_size; - blob->data = buffer; - - buffer = NULL; - - return blob; - } - - -public: - - - // ------------------------------------------------------------------- - virtual size_t Read( void *, - size_t, - size_t ) - { - return 0; - } - - // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, - size_t pSize, - size_t pCount) - { - pSize *= pCount; - if (cursor + pSize > cur_size) { - Grow(cursor + pSize); - } - - memcpy(buffer+cursor, pvBuffer, pSize); - cursor += pSize; - - file_size = std::max(file_size,cursor); - return pCount; - } - - // ------------------------------------------------------------------- - virtual aiReturn Seek(size_t pOffset, - aiOrigin pOrigin) - { - switch(pOrigin) - { - case aiOrigin_CUR: - cursor += pOffset; - break; - - case aiOrigin_END: - cursor = file_size - pOffset; - break; - - case aiOrigin_SET: - cursor = pOffset; - break; - - default: - return AI_FAILURE; - } - - if (cursor > file_size) { - Grow(cursor); - } - - file_size = std::max(cursor,file_size); - return AI_SUCCESS; - } - - // ------------------------------------------------------------------- - virtual size_t Tell() const - { - return cursor; - } - - // ------------------------------------------------------------------- - virtual size_t FileSize() const - { - return file_size; - } - - // ------------------------------------------------------------------- - virtual void Flush() - { - // ignore - } - - - -private: - - // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - // 1.5 and phi are very heap-friendly growth factors (the first - // allows for frequent re-use of heap blocks, the second - // forms a fibonacci sequence with similar characteristics - - // since this heavily depends on the heap implementation - // and other factors as well, i'll just go with 1.5 since - // it is quicker to compute). - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); - - const uint8_t* const old = buffer; - buffer = new uint8_t[new_size]; - - if (old) { - memcpy(buffer,old,cur_size); - delete[] old; - } - - cur_size = new_size; - } - -private: - - uint8_t* buffer; - size_t cur_size,file_size, cursor, initial; - - const std::string file; - BlobIOSystem* const creator; -}; - - -#define AI_BLOBIO_MAGIC "$blobfile" - -// -------------------------------------------------------------------------------------------- -/** Redirect IOSystem to a blob */ -// -------------------------------------------------------------------------------------------- -class BlobIOSystem : public IOSystem -{ - - friend class BlobIOStream; - typedef std::pair BlobEntry; - -public: - - BlobIOSystem() - { - } - - virtual ~BlobIOSystem() - { - for(BlobEntry& blobby : blobs) { - delete blobby.second; - } - } - -public: - - // ------------------------------------------------------------------- - const char* GetMagicFileName() const - { - return AI_BLOBIO_MAGIC; - } - - - // ------------------------------------------------------------------- - aiExportDataBlob* GetBlobChain() - { - // one must be the master - aiExportDataBlob* master = NULL, *cur; - for(const BlobEntry& blobby : blobs) { - if (blobby.first == AI_BLOBIO_MAGIC) { - master = blobby.second; - break; - } - } - if (!master) { - ASSIMP_LOG_ERROR("BlobIOSystem: no data written or master file was not closed properly."); - return NULL; - } - - master->name.Set(""); - - cur = master; - for(const BlobEntry& blobby : blobs) { - if (blobby.second == master) { - continue; - } - - cur->next = blobby.second; - cur = cur->next; - - // extract the file extension from the file written - const std::string::size_type s = blobby.first.find_first_of('.'); - cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1)); - } - - // give up blob ownership - blobs.clear(); - return master; - } - -public: - - // ------------------------------------------------------------------- - virtual bool Exists( const char* pFile) const { - return created.find(std::string(pFile)) != created.end(); - } - - - // ------------------------------------------------------------------- - virtual char getOsSeparator() const { - return '/'; - } - - - // ------------------------------------------------------------------- - virtual IOStream* Open(const char* pFile, - const char* pMode) - { - if (pMode[0] != 'w') { - return NULL; - } - - created.insert(std::string(pFile)); - return new BlobIOStream(this,std::string(pFile)); - } - - // ------------------------------------------------------------------- - virtual void Close( IOStream* pFile) - { - delete pFile; - } - -private: - - // ------------------------------------------------------------------- - void OnDestruct(const std::string& filename, BlobIOStream* child) - { - // we don't know in which the files are closed, so we - // can't reliably say that the first must be the master - // file ... - blobs.push_back( BlobEntry(filename,child->GetBlob()) ); - } - -private: - std::set created; - std::vector< BlobEntry > blobs; -}; - - -// -------------------------------------------------------------------------------------------- -BlobIOStream :: ~BlobIOStream() -{ - creator->OnDestruct(file,this); - delete[] buffer; -} - - -} // end Assimp - -#endif diff --git a/thirdparty/assimp/include/assimp/ByteSwapper.h b/thirdparty/assimp/include/assimp/ByteSwapper.h deleted file mode 100644 index 3f14c471a83c..000000000000 --- a/thirdparty/assimp/include/assimp/ByteSwapper.h +++ /dev/null @@ -1,292 +0,0 @@ -/* -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 Helper class tp perform various byte oder swappings - (e.g. little to big endian) */ -#pragma once -#ifndef AI_BYTESWAPPER_H_INC -#define AI_BYTESWAPPER_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#if _MSC_VER >= 1400 -#include -#endif - -namespace Assimp { -// -------------------------------------------------------------------------------------- -/** 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() AI_NO_EXCEPT {} - -public: - - // ---------------------------------------------------------------------- - /** Swap two bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap2(void* _szOut) - { - ai_assert(_szOut); - -#if _MSC_VER >= 1400 - uint16_t* const szOut = reinterpret_cast(_szOut); - *szOut = _byteswap_ushort(*szOut); -#else - uint8_t* const szOut = reinterpret_cast(_szOut); - std::swap(szOut[0],szOut[1]); -#endif - } - - // ---------------------------------------------------------------------- - /** Swap four bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap4(void* _szOut) - { - ai_assert(_szOut); - -#if _MSC_VER >= 1400 - uint32_t* const szOut = reinterpret_cast(_szOut); - *szOut = _byteswap_ulong(*szOut); -#else - uint8_t* const szOut = reinterpret_cast(_szOut); - std::swap(szOut[0],szOut[3]); - std::swap(szOut[1],szOut[2]); -#endif - } - - // ---------------------------------------------------------------------- - /** Swap eight bytes of data - * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap8(void* _szOut) - { - ai_assert(_szOut); - -#if _MSC_VER >= 1400 - uint64_t* const szOut = reinterpret_cast(_szOut); - *szOut = _byteswap_uint64(*szOut); -#else - uint8_t* const szOut = reinterpret_cast(_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]); -#endif - } - - // ---------------------------------------------------------------------- - /** 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 - static inline Type Swapped(Type tOut) - { - return _swapper()(tOut); - } - -private: - - template struct _swapper; -}; - -template struct ByteSwap::_swapper { - T operator() (T tOut) { - Swap2(&tOut); - return tOut; - } -}; - -template struct ByteSwap::_swapper { - T operator() (T tOut) { - Swap4(&tOut); - return tOut; - } -}; - -template struct ByteSwap::_swapper { - 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 -struct ByteSwapper { - void operator() (T* inout) { - ByteSwap::Swap(inout); - } -}; - -template -struct ByteSwapper { - void operator() (T*) { - } -}; - -// -------------------------------------------------------------------------------------------- -template -struct Getter { - void operator() (T* inout, bool le) { -#ifdef AI_BUILD_BIG_ENDIAN - le = le; -#else - le = !le; -#endif - if (le) { - ByteSwapper1?true:false)> () (inout); - } - else ByteSwapper () (inout); - } -}; - -template -struct Getter { - - void operator() (T* inout, bool /*le*/) { - // static branch - ByteSwapper1)> () (inout); - } -}; -} // end Intern -} // end Assimp - -#endif //!! AI_BYTESWAPPER_H_INC diff --git a/thirdparty/assimp/include/assimp/Compiler/poppack1.h b/thirdparty/assimp/include/assimp/Compiler/poppack1.h deleted file mode 100644 index e033bc1472ae..000000000000 --- a/thirdparty/assimp/include/assimp/Compiler/poppack1.h +++ /dev/null @@ -1,22 +0,0 @@ - -// =============================================================================== -// May be included multiple times - resets structure packing to the defaults -// for all supported compilers. Reverts the changes made by #include -// -// Currently this works on the following compilers: -// MSVC 7,8,9 -// GCC -// BORLAND (complains about 'pack state changed but not reverted', but works) -// =============================================================================== - -#ifndef AI_PUSHPACK_IS_DEFINED -# error pushpack1.h must be included after poppack1.h -#endif - -// reset packing to the original value -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( pop ) -#endif -#undef PACK_STRUCT - -#undef AI_PUSHPACK_IS_DEFINED diff --git a/thirdparty/assimp/include/assimp/Compiler/pstdint.h b/thirdparty/assimp/include/assimp/Compiler/pstdint.h deleted file mode 100644 index 4de4ce2a9044..000000000000 --- a/thirdparty/assimp/include/assimp/Compiler/pstdint.h +++ /dev/null @@ -1,912 +0,0 @@ -/* A portable stdint.h - **************************************************************************** - * BSD License: - **************************************************************************** - * - * Copyright (c) 2005-2016 Paul Hsieh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - * - **************************************************************************** - * - * Version 0.1.15.4 - * - * The ANSI C standard committee, for the C99 standard, specified the - * inclusion of a new standard include file called stdint.h. This is - * a very useful and long desired include file which contains several - * very precise definitions for integer scalar types that is - * critically important for making portable several classes of - * applications including cryptography, hashing, variable length - * integer libraries and so on. But for most developers its likely - * useful just for programming sanity. - * - * The problem is that some compiler vendors chose to ignore the C99 - * standard and some older compilers have no opportunity to be updated. - * Because of this situation, simply including stdint.h in your code - * makes it unportable. - * - * So that's what this file is all about. Its an attempt to build a - * single universal include file that works on as many platforms as - * possible to deliver what stdint.h is supposed to. Even compilers - * that already come with stdint.h can use this file instead without - * any loss of functionality. A few things that should be noted about - * this file: - * - * 1) It is not guaranteed to be portable and/or present an identical - * interface on all platforms. The extreme variability of the - * ANSI C standard makes this an impossibility right from the - * very get go. Its really only meant to be useful for the vast - * majority of platforms that possess the capability of - * implementing usefully and precisely defined, standard sized - * integer scalars. Systems which are not intrinsically 2s - * complement may produce invalid constants. - * - * 2) There is an unavoidable use of non-reserved symbols. - * - * 3) Other standard include files are invoked. - * - * 4) This file may come in conflict with future platforms that do - * include stdint.h. The hope is that one or the other can be - * used with no real difference. - * - * 5) In the current version, if your platform can't represent - * int32_t, int16_t and int8_t, it just dumps out with a compiler - * error. - * - * 6) 64 bit integers may or may not be defined. Test for their - * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX. - * Note that this is different from the C99 specification which - * requires the existence of 64 bit support in the compiler. If - * this is not defined for your platform, yet it is capable of - * dealing with 64 bits then it is because this file has not yet - * been extended to cover all of your system's capabilities. - * - * 7) (u)intptr_t may or may not be defined. Test for its presence - * with the test: #ifdef PTRDIFF_MAX. If this is not defined - * for your platform, then it is because this file has not yet - * been extended to cover all of your system's capabilities, not - * because its optional. - * - * 8) The following might not been defined even if your platform is - * capable of defining it: - * - * WCHAR_MIN - * WCHAR_MAX - * (u)int64_t - * PTRDIFF_MIN - * PTRDIFF_MAX - * (u)intptr_t - * - * 9) The following have not been defined: - * - * WINT_MIN - * WINT_MAX - * - * 10) The criteria for defining (u)int_least(*)_t isn't clear, - * except for systems which don't have a type that precisely - * defined 8, 16, or 32 bit types (which this include file does - * not support anyways). Default definitions have been given. - * - * 11) The criteria for defining (u)int_fast(*)_t isn't something I - * would trust to any particular compiler vendor or the ANSI C - * committee. It is well known that "compatible systems" are - * commonly created that have very different performance - * characteristics from the systems they are compatible with, - * especially those whose vendors make both the compiler and the - * system. Default definitions have been given, but its strongly - * recommended that users never use these definitions for any - * reason (they do *NOT* deliver any serious guarantee of - * improved performance -- not in this file, nor any vendor's - * stdint.h). - * - * 12) The following macros: - * - * PRINTF_INTMAX_MODIFIER - * PRINTF_INT64_MODIFIER - * PRINTF_INT32_MODIFIER - * PRINTF_INT16_MODIFIER - * PRINTF_LEAST64_MODIFIER - * PRINTF_LEAST32_MODIFIER - * PRINTF_LEAST16_MODIFIER - * PRINTF_INTPTR_MODIFIER - * - * are strings which have been defined as the modifiers required - * for the "d", "u" and "x" printf formats to correctly output - * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t, - * (u)least32_t, (u)least16_t and (u)intptr_t types respectively. - * PRINTF_INTPTR_MODIFIER is not defined for some systems which - * provide their own stdint.h. PRINTF_INT64_MODIFIER is not - * defined if INT64_MAX is not defined. These are an extension - * beyond what C99 specifies must be in stdint.h. - * - * In addition, the following macros are defined: - * - * PRINTF_INTMAX_HEX_WIDTH - * PRINTF_INT64_HEX_WIDTH - * PRINTF_INT32_HEX_WIDTH - * PRINTF_INT16_HEX_WIDTH - * PRINTF_INT8_HEX_WIDTH - * PRINTF_INTMAX_DEC_WIDTH - * PRINTF_INT64_DEC_WIDTH - * PRINTF_INT32_DEC_WIDTH - * PRINTF_INT16_DEC_WIDTH - * PRINTF_UINT8_DEC_WIDTH - * PRINTF_UINTMAX_DEC_WIDTH - * PRINTF_UINT64_DEC_WIDTH - * PRINTF_UINT32_DEC_WIDTH - * PRINTF_UINT16_DEC_WIDTH - * PRINTF_UINT8_DEC_WIDTH - * - * Which specifies the maximum number of characters required to - * print the number of that type in either hexadecimal or decimal. - * These are an extension beyond what C99 specifies must be in - * stdint.h. - * - * Compilers tested (all with 0 warnings at their highest respective - * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32 - * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio - * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3 - * - * This file should be considered a work in progress. Suggestions for - * improvements, especially those which increase coverage are strongly - * encouraged. - * - * Acknowledgements - * - * The following people have made significant contributions to the - * development and testing of this file: - * - * Chris Howie - * John Steele Scott - * Dave Thorup - * John Dill - * Florian Wobbe - * Christopher Sean Morrison - * Mikkel Fahnoe Jorgensen - * - */ - -#include -#include -#include - -/* - * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and - * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. - */ - -#if ((defined(__SUNPRO_C) && __SUNPRO_C >= 0x570) || (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (__GNUC__ > 3 || defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED) -#include -#define _PSTDINT_H_INCLUDED -# if defined(__GNUC__) && (defined(__x86_64__) || defined(__ppc64__)) && !(defined(__APPLE__) && defined(__MACH__)) -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "l" -# endif -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -# else -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# ifndef PRINTF_INT32_MODIFIER -# if (UINT_MAX == UINT32_MAX) -# define PRINTF_INT32_MODIFIER "" -# else -# define PRINTF_INT32_MODIFIER "l" -# endif -# endif -# endif -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER -# endif -# ifndef PRINTF_INT64_HEX_WIDTH -# define PRINTF_INT64_HEX_WIDTH "16" -# endif -# ifndef PRINTF_UINT64_HEX_WIDTH -# define PRINTF_UINT64_HEX_WIDTH "16" -# endif -# ifndef PRINTF_INT32_HEX_WIDTH -# define PRINTF_INT32_HEX_WIDTH "8" -# endif -# ifndef PRINTF_UINT32_HEX_WIDTH -# define PRINTF_UINT32_HEX_WIDTH "8" -# endif -# ifndef PRINTF_INT16_HEX_WIDTH -# define PRINTF_INT16_HEX_WIDTH "4" -# endif -# ifndef PRINTF_UINT16_HEX_WIDTH -# define PRINTF_UINT16_HEX_WIDTH "4" -# endif -# ifndef PRINTF_INT8_HEX_WIDTH -# define PRINTF_INT8_HEX_WIDTH "2" -# endif -# ifndef PRINTF_UINT8_HEX_WIDTH -# define PRINTF_UINT8_HEX_WIDTH "2" -# endif -# ifndef PRINTF_INT64_DEC_WIDTH -# define PRINTF_INT64_DEC_WIDTH "19" -# endif -# ifndef PRINTF_UINT64_DEC_WIDTH -# define PRINTF_UINT64_DEC_WIDTH "20" -# endif -# ifndef PRINTF_INT32_DEC_WIDTH -# define PRINTF_INT32_DEC_WIDTH "10" -# endif -# ifndef PRINTF_UINT32_DEC_WIDTH -# define PRINTF_UINT32_DEC_WIDTH "10" -# endif -# ifndef PRINTF_INT16_DEC_WIDTH -# define PRINTF_INT16_DEC_WIDTH "5" -# endif -# ifndef PRINTF_UINT16_DEC_WIDTH -# define PRINTF_UINT16_DEC_WIDTH "5" -# endif -# ifndef PRINTF_INT8_DEC_WIDTH -# define PRINTF_INT8_DEC_WIDTH "3" -# endif -# ifndef PRINTF_UINT8_DEC_WIDTH -# define PRINTF_UINT8_DEC_WIDTH "3" -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH -# endif -# ifndef PRINTF_UINTMAX_HEX_WIDTH -# define PRINTF_UINTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH -# endif -# ifndef PRINTF_UINTMAX_DEC_WIDTH -# define PRINTF_UINTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH -# endif - -/* - * Something really weird is going on with Open Watcom. Just pull some of - * these duplicated definitions from Open Watcom's stdint.h file for now. - */ - -# if defined (__WATCOMC__) && __WATCOMC__ >= 1250 -# if !defined (INT64_C) -# define INT64_C(x) (x + (INT64_MAX - INT64_MAX)) -# endif -# if !defined (UINT64_C) -# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) -# endif -# if !defined (INT32_C) -# define INT32_C(x) (x + (INT32_MAX - INT32_MAX)) -# endif -# if !defined (UINT32_C) -# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX)) -# endif -# if !defined (INT16_C) -# define INT16_C(x) (x) -# endif -# if !defined (UINT16_C) -# define UINT16_C(x) (x) -# endif -# if !defined (INT8_C) -# define INT8_C(x) (x) -# endif -# if !defined (UINT8_C) -# define UINT8_C(x) (x) -# endif -# if !defined (UINT64_MAX) -# define UINT64_MAX 18446744073709551615ULL -# endif -# if !defined (INT64_MAX) -# define INT64_MAX 9223372036854775807LL -# endif -# if !defined (UINT32_MAX) -# define UINT32_MAX 4294967295UL -# endif -# if !defined (INT32_MAX) -# define INT32_MAX 2147483647L -# endif -# if !defined (INTMAX_MAX) -# define INTMAX_MAX INT64_MAX -# endif -# if !defined (INTMAX_MIN) -# define INTMAX_MIN INT64_MIN -# endif -# endif -#endif - -/* - * I have no idea what is the truly correct thing to do on older Solaris. - * From some online discussions, this seems to be what is being - * recommended. For people who actually are developing on older Solaris, - * what I would like to know is, does this define all of the relevant - * macros of a complete stdint.h? Remember, in pstdint.h 64 bit is - * considered optional. - */ - -#if (defined(__SUNPRO_C) && __SUNPRO_C >= 0x420) && !defined(_PSTDINT_H_INCLUDED) -#include -#define _PSTDINT_H_INCLUDED -#endif - -#ifndef _PSTDINT_H_INCLUDED -#define _PSTDINT_H_INCLUDED - -#ifndef SIZE_MAX -# define SIZE_MAX (~(size_t)0) -#endif - -/* - * Deduce the type assignments from limits.h under the assumption that - * integer sizes in bits are powers of 2, and follow the ANSI - * definitions. - */ - -#ifndef UINT8_MAX -# define UINT8_MAX 0xff -#endif -#if !defined(uint8_t) && !defined(_UINT8_T) && !defined(vxWorks) -# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) - typedef unsigned char uint8_t; -# define UINT8_C(v) ((uint8_t) v) -# else -# error "Platform not supported" -# endif -#endif - -#ifndef INT8_MAX -# define INT8_MAX 0x7f -#endif -#ifndef INT8_MIN -# define INT8_MIN INT8_C(0x80) -#endif -#if !defined(int8_t) && !defined(_INT8_T) && !defined(vxWorks) -# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) - typedef signed char int8_t; -# define INT8_C(v) ((int8_t) v) -# else -# error "Platform not supported" -# endif -#endif - -#ifndef UINT16_MAX -# define UINT16_MAX 0xffff -#endif -#if !defined(uint16_t) && !defined(_UINT16_T) && !defined(vxWorks) -#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S) - typedef unsigned int uint16_t; -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "" -# endif -# define UINT16_C(v) ((uint16_t) (v)) -#elif (USHRT_MAX == UINT16_MAX) - typedef unsigned short uint16_t; -# define UINT16_C(v) ((uint16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef INT16_MAX -# define INT16_MAX 0x7fff -#endif -#ifndef INT16_MIN -# define INT16_MIN INT16_C(0x8000) -#endif -#if !defined(int16_t) && !defined(_INT16_T) && !defined(vxWorks) -#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) - typedef signed int int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "" -# endif -#elif (SHRT_MAX == INT16_MAX) - typedef signed short int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef UINT32_MAX -# define UINT32_MAX (0xffffffffUL) -#endif -#if !defined(uint32_t) && !defined(_UINT32_T) && !defined(vxWorks) -#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) - typedef unsigned long uint32_t; -# define UINT32_C(v) v ## UL -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -#elif (UINT_MAX == UINT32_MAX) - typedef unsigned int uint32_t; -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -# define UINT32_C(v) v ## U -#elif (USHRT_MAX == UINT32_MAX) - typedef unsigned short uint32_t; -# define UINT32_C(v) ((unsigned short) (v)) -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef INT32_MAX -# define INT32_MAX (0x7fffffffL) -#endif -#ifndef INT32_MIN -# define INT32_MIN INT32_C(0x80000000) -#endif -#if !defined(int32_t) && !defined(_INT32_T) && !defined(vxWorks) -#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) - typedef signed long int32_t; -# define INT32_C(v) v ## L -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -#elif (INT_MAX == INT32_MAX) - typedef signed int int32_t; -# define INT32_C(v) v -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#elif (SHRT_MAX == INT32_MAX) - typedef signed short int32_t; -# define INT32_C(v) ((short) (v)) -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#else -#error "Platform not supported" -#endif -#endif - -/* - * The macro stdint_int64_defined is temporarily used to record - * whether or not 64 integer support is available. It must be - * defined for any 64 integer extensions for new platforms that are - * added. - */ - -#undef stdint_int64_defined -#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) -# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S) -# define stdint_int64_defined - typedef long long int64_t; - typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# endif -#endif - -#if !defined (stdint_int64_defined) -# if defined(__GNUC__) && !defined(vxWorks) -# define stdint_int64_defined - __extension__ typedef long long int64_t; - __extension__ typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) -# define stdint_int64_defined - typedef long long int64_t; - typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) -# define stdint_int64_defined - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; -# define UINT64_C(v) v ## UI64 -# define INT64_C(v) v ## I64 -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "I64" -# endif -# endif -#endif - -#if !defined (LONG_LONG_MAX) && defined (INT64_C) -# define LONG_LONG_MAX INT64_C (9223372036854775807) -#endif -#ifndef ULONG_LONG_MAX -# define ULONG_LONG_MAX UINT64_C (18446744073709551615) -#endif - -#if !defined (INT64_MAX) && defined (INT64_C) -# define INT64_MAX INT64_C (9223372036854775807) -#endif -#if !defined (INT64_MIN) && defined (INT64_C) -# define INT64_MIN INT64_C (-9223372036854775808) -#endif -#if !defined (UINT64_MAX) && defined (INT64_C) -# define UINT64_MAX UINT64_C (18446744073709551615) -#endif - -/* - * Width of hexadecimal for number field. - */ - -#ifndef PRINTF_INT64_HEX_WIDTH -# define PRINTF_INT64_HEX_WIDTH "16" -#endif -#ifndef PRINTF_INT32_HEX_WIDTH -# define PRINTF_INT32_HEX_WIDTH "8" -#endif -#ifndef PRINTF_INT16_HEX_WIDTH -# define PRINTF_INT16_HEX_WIDTH "4" -#endif -#ifndef PRINTF_INT8_HEX_WIDTH -# define PRINTF_INT8_HEX_WIDTH "2" -#endif -#ifndef PRINTF_INT64_DEC_WIDTH -# define PRINTF_INT64_DEC_WIDTH "19" -#endif -#ifndef PRINTF_INT32_DEC_WIDTH -# define PRINTF_INT32_DEC_WIDTH "10" -#endif -#ifndef PRINTF_INT16_DEC_WIDTH -# define PRINTF_INT16_DEC_WIDTH "5" -#endif -#ifndef PRINTF_INT8_DEC_WIDTH -# define PRINTF_INT8_DEC_WIDTH "3" -#endif -#ifndef PRINTF_UINT64_DEC_WIDTH -# define PRINTF_UINT64_DEC_WIDTH "20" -#endif -#ifndef PRINTF_UINT32_DEC_WIDTH -# define PRINTF_UINT32_DEC_WIDTH "10" -#endif -#ifndef PRINTF_UINT16_DEC_WIDTH -# define PRINTF_UINT16_DEC_WIDTH "5" -#endif -#ifndef PRINTF_UINT8_DEC_WIDTH -# define PRINTF_UINT8_DEC_WIDTH "3" -#endif - -/* - * Ok, lets not worry about 128 bit integers for now. Moore's law says - * we don't need to worry about that until about 2040 at which point - * we'll have bigger things to worry about. - */ - -#ifdef stdint_int64_defined - typedef int64_t intmax_t; - typedef uint64_t uintmax_t; -# define INTMAX_MAX INT64_MAX -# define INTMAX_MIN INT64_MIN -# define UINTMAX_MAX UINT64_MAX -# define UINTMAX_C(v) UINT64_C(v) -# define INTMAX_C(v) INT64_C(v) -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH -# endif -#else - typedef int32_t intmax_t; - typedef uint32_t uintmax_t; -# define INTMAX_MAX INT32_MAX -# define UINTMAX_MAX UINT32_MAX -# define UINTMAX_C(v) UINT32_C(v) -# define INTMAX_C(v) INT32_C(v) -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH -# endif -#endif - -/* - * Because this file currently only supports platforms which have - * precise powers of 2 as bit sizes for the default integers, the - * least definitions are all trivial. Its possible that a future - * version of this file could have different definitions. - */ - -#ifndef stdint_least_defined - typedef int8_t int_least8_t; - typedef uint8_t uint_least8_t; - typedef int16_t int_least16_t; - typedef uint16_t uint_least16_t; - typedef int32_t int_least32_t; - typedef uint32_t uint_least32_t; -# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER -# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER -# define UINT_LEAST8_MAX UINT8_MAX -# define INT_LEAST8_MAX INT8_MAX -# define UINT_LEAST16_MAX UINT16_MAX -# define INT_LEAST16_MAX INT16_MAX -# define UINT_LEAST32_MAX UINT32_MAX -# define INT_LEAST32_MAX INT32_MAX -# define INT_LEAST8_MIN INT8_MIN -# define INT_LEAST16_MIN INT16_MIN -# define INT_LEAST32_MIN INT32_MIN -# ifdef stdint_int64_defined - typedef int64_t int_least64_t; - typedef uint64_t uint_least64_t; -# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER -# define UINT_LEAST64_MAX UINT64_MAX -# define INT_LEAST64_MAX INT64_MAX -# define INT_LEAST64_MIN INT64_MIN -# endif -#endif -#undef stdint_least_defined - -/* - * The ANSI C committee pretending to know or specify anything about - * performance is the epitome of misguided arrogance. The mandate of - * this file is to *ONLY* ever support that absolute minimum - * definition of the fast integer types, for compatibility purposes. - * No extensions, and no attempt to suggest what may or may not be a - * faster integer type will ever be made in this file. Developers are - * warned to stay away from these types when using this or any other - * stdint.h. - */ - -typedef int_least8_t int_fast8_t; -typedef uint_least8_t uint_fast8_t; -typedef int_least16_t int_fast16_t; -typedef uint_least16_t uint_fast16_t; -typedef int_least32_t int_fast32_t; -typedef uint_least32_t uint_fast32_t; -#define UINT_FAST8_MAX UINT_LEAST8_MAX -#define INT_FAST8_MAX INT_LEAST8_MAX -#define UINT_FAST16_MAX UINT_LEAST16_MAX -#define INT_FAST16_MAX INT_LEAST16_MAX -#define UINT_FAST32_MAX UINT_LEAST32_MAX -#define INT_FAST32_MAX INT_LEAST32_MAX -#define INT_FAST8_MIN INT_LEAST8_MIN -#define INT_FAST16_MIN INT_LEAST16_MIN -#define INT_FAST32_MIN INT_LEAST32_MIN -#ifdef stdint_int64_defined - typedef int_least64_t int_fast64_t; - typedef uint_least64_t uint_fast64_t; -# define UINT_FAST64_MAX UINT_LEAST64_MAX -# define INT_FAST64_MAX INT_LEAST64_MAX -# define INT_FAST64_MIN INT_LEAST64_MIN -#endif - -#undef stdint_int64_defined - -/* - * Whatever piecemeal, per compiler thing we can do about the wchar_t - * type limits. - */ - -#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) && !defined(vxWorks) -# include -# ifndef WCHAR_MIN -# define WCHAR_MIN 0 -# endif -# ifndef WCHAR_MAX -# define WCHAR_MAX ((wchar_t)-1) -# endif -#endif - -/* - * Whatever piecemeal, per compiler/platform thing we can do about the - * (u)intptr_t types and limits. - */ - -#if (defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)) || defined (_UINTPTR_T) -# define STDINT_H_UINTPTR_T_DEFINED -#endif - -#ifndef STDINT_H_UINTPTR_T_DEFINED -# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) || defined (__ppc64__) -# define stdint_intptr_bits 64 -# elif defined (__WATCOMC__) || defined (__TURBOC__) -# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) -# define stdint_intptr_bits 16 -# else -# define stdint_intptr_bits 32 -# endif -# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) || defined (__ppc64__) -# define stdint_intptr_bits 32 -# elif defined (__INTEL_COMPILER) -/* TODO -- what did Intel do about x86-64? */ -# else -/* #error "This platform might not be supported yet" */ -# endif - -# ifdef stdint_intptr_bits -# define stdint_intptr_glue3_i(a,b,c) a##b##c -# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c) -# ifndef PRINTF_INTPTR_MODIFIER -# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER) -# endif -# ifndef PTRDIFF_MAX -# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) -# endif -# ifndef PTRDIFF_MIN -# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) -# endif -# ifndef UINTPTR_MAX -# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX) -# endif -# ifndef INTPTR_MAX -# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) -# endif -# ifndef INTPTR_MIN -# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) -# endif -# ifndef INTPTR_C -# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x) -# endif -# ifndef UINTPTR_C -# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) -# endif - typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; - typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; -# else -/* TODO -- This following is likely wrong for some platforms, and does - nothing for the definition of uintptr_t. */ - typedef ptrdiff_t intptr_t; -# endif -# define STDINT_H_UINTPTR_T_DEFINED -#endif - -/* - * Assumes sig_atomic_t is signed and we have a 2s complement machine. - */ - -#ifndef SIG_ATOMIC_MAX -# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1) -#endif - -#endif - -#if defined (__TEST_PSTDINT_FOR_CORRECTNESS) - -/* - * Please compile with the maximum warning settings to make sure macros are - * not defined more than once. - */ - -#include -#include -#include - -#define glue3_aux(x,y,z) x ## y ## z -#define glue3(x,y,z) glue3_aux(x,y,z) - -#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,) = glue3(UINT,bits,_C) (0); -#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,) = glue3(INT,bits,_C) (0); - -#define DECL(us,bits) glue3(DECL,us,) (bits) - -#define TESTUMAX(bits) glue3(u,bits,) = ~glue3(u,bits,); if (glue3(UINT,bits,_MAX) != glue3(u,bits,)) printf ("Something wrong with UINT%d_MAX\n", bits) - -#define REPORTERROR(msg) { err_n++; if (err_first <= 0) err_first = __LINE__; printf msg; } - -int main () { - int err_n = 0; - int err_first = 0; - DECL(I,8) - DECL(U,8) - DECL(I,16) - DECL(U,16) - DECL(I,32) - DECL(U,32) -#ifdef INT64_MAX - DECL(I,64) - DECL(U,64) -#endif - intmax_t imax = INTMAX_C(0); - uintmax_t umax = UINTMAX_C(0); - char str0[256], str1[256]; - - sprintf (str0, "%" PRINTF_INT32_MODIFIER "d", INT32_C(2147483647)); - if (0 != strcmp (str0, "2147483647")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0)); - if (atoi(PRINTF_INT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_INT32_DEC_WIDTH : %s\n", PRINTF_INT32_DEC_WIDTH)); - sprintf (str0, "%" PRINTF_INT32_MODIFIER "u", UINT32_C(4294967295)); - if (0 != strcmp (str0, "4294967295")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0)); - if (atoi(PRINTF_UINT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_UINT32_DEC_WIDTH : %s\n", PRINTF_UINT32_DEC_WIDTH)); -#ifdef INT64_MAX - sprintf (str1, "%" PRINTF_INT64_MODIFIER "d", INT64_C(9223372036854775807)); - if (0 != strcmp (str1, "9223372036854775807")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1)); - if (atoi(PRINTF_INT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_INT64_DEC_WIDTH : %s, %d\n", PRINTF_INT64_DEC_WIDTH, (int) strlen(str1))); - sprintf (str1, "%" PRINTF_INT64_MODIFIER "u", UINT64_C(18446744073709550591)); - if (0 != strcmp (str1, "18446744073709550591")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1)); - if (atoi(PRINTF_UINT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_UINT64_DEC_WIDTH : %s, %d\n", PRINTF_UINT64_DEC_WIDTH, (int) strlen(str1))); -#endif - - sprintf (str0, "%d %x\n", 0, ~0); - - sprintf (str1, "%d %x\n", i8, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i8 : %s\n", str1)); - sprintf (str1, "%u %x\n", u8, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u8 : %s\n", str1)); - sprintf (str1, "%d %x\n", i16, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i16 : %s\n", str1)); - sprintf (str1, "%u %x\n", u16, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u16 : %s\n", str1)); - sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i32 : %s\n", str1)); - sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u32 : %s\n", str1)); -#ifdef INT64_MAX - sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i64 : %s\n", str1)); -#endif - sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with imax : %s\n", str1)); - sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0); - if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with umax : %s\n", str1)); - - TESTUMAX(8); - TESTUMAX(16); - TESTUMAX(32); -#ifdef INT64_MAX - TESTUMAX(64); -#endif - -#define STR(v) #v -#define Q(v) printf ("sizeof " STR(v) " = %u\n", (unsigned) sizeof (v)); - if (err_n) { - printf ("pstdint.h is not correct. Please use sizes below to correct it:\n"); - } - - Q(int) - Q(unsigned) - Q(long int) - Q(short int) - Q(int8_t) - Q(int16_t) - Q(int32_t) -#ifdef INT64_MAX - Q(int64_t) -#endif - - return EXIT_SUCCESS; -} - -#endif diff --git a/thirdparty/assimp/include/assimp/Compiler/pushpack1.h b/thirdparty/assimp/include/assimp/Compiler/pushpack1.h deleted file mode 100644 index 4c9fbb857f64..000000000000 --- a/thirdparty/assimp/include/assimp/Compiler/pushpack1.h +++ /dev/null @@ -1,43 +0,0 @@ - - -// =============================================================================== -// May be included multiple times - sets structure packing to 1 -// for all supported compilers. #include reverts the changes. -// -// Currently this works on the following compilers: -// MSVC 7,8,9 -// GCC -// BORLAND (complains about 'pack state changed but not reverted', but works) -// Clang -// -// -// USAGE: -// -// struct StructToBePacked { -// } PACK_STRUCT; -// -// =============================================================================== - -#ifdef AI_PUSHPACK_IS_DEFINED -# error poppack1.h must be included after pushpack1.h -#endif - -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack(push,1) -# define PACK_STRUCT -#elif defined( __GNUC__ ) || defined(__clang__) -# if !defined(HOST_MINGW) -# define PACK_STRUCT __attribute__((__packed__)) -# else -# define PACK_STRUCT __attribute__((gcc_struct, __packed__)) -# endif -#else -# error Compiler not supported -#endif - -#if defined(_MSC_VER) -// C4103: Packing was changed after the inclusion of the header, probably missing #pragma pop -# pragma warning (disable : 4103) -#endif - -#define AI_PUSHPACK_IS_DEFINED diff --git a/thirdparty/assimp/include/assimp/CreateAnimMesh.h b/thirdparty/assimp/include/assimp/CreateAnimMesh.h deleted file mode 100644 index 1266d1de1161..000000000000 --- a/thirdparty/assimp/include/assimp/CreateAnimMesh.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -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 CreateAnimMesh.h - * Create AnimMesh from Mesh - */ -#pragma once -#ifndef INCLUDED_AI_CREATE_ANIM_MESH_H -#define INCLUDED_AI_CREATE_ANIM_MESH_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -namespace Assimp { - -/** - * Create aiAnimMesh from aiMesh. - * @param mesh The input mesh to create an animated mesh from. - * @return The new created animated mesh. - */ -ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh); - -} // end of namespace Assimp - -#endif // INCLUDED_AI_CREATE_ANIM_MESH_H - diff --git a/thirdparty/assimp/include/assimp/DefaultIOStream.h b/thirdparty/assimp/include/assimp/DefaultIOStream.h deleted file mode 100644 index c6d382c1b5fc..000000000000 --- a/thirdparty/assimp/include/assimp/DefaultIOStream.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -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 Default file I/O using fXXX()-family of functions */ -#pragma once -#ifndef AI_DEFAULTIOSTREAM_H_INC -#define AI_DEFAULTIOSTREAM_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include -#include - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -//! @class DefaultIOStream -//! @brief Default IO implementation, use standard IO operations -//! @note An instance of this class can exist without a valid file handle -//! attached to it. All calls fail, but the instance can nevertheless be -//! used with no restrictions. -class ASSIMP_API DefaultIOStream : public IOStream { - friend class DefaultIOSystem; -#if __ANDROID__ -# if __ANDROID_API__ > 9 -# if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) - friend class AndroidJNIIOSystem; -# endif // defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) -# endif // __ANDROID_API__ > 9 -#endif // __ANDROID__ - -protected: - DefaultIOStream() AI_NO_EXCEPT; - DefaultIOStream(FILE* pFile, const std::string &strFilename); - -public: - /** Destructor public to allow simple deletion to close the file. */ - ~DefaultIOStream (); - - // ------------------------------------------------------------------- - /// Read from stream - size_t Read(void* pvBuffer, - size_t pSize, - size_t pCount); - - // ------------------------------------------------------------------- - /// Write to stream - size_t Write(const void* pvBuffer, - size_t pSize, - size_t pCount); - - // ------------------------------------------------------------------- - /// Seek specific position - aiReturn Seek(size_t pOffset, - aiOrigin pOrigin); - - // ------------------------------------------------------------------- - /// Get current seek position - size_t Tell() const; - - // ------------------------------------------------------------------- - /// Get size of file - size_t FileSize() const; - - // ------------------------------------------------------------------- - /// Flush file contents - void Flush(); - -private: - FILE* mFile; - std::string mFilename; - mutable size_t mCachedSize; -}; - -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT -: mFile(nullptr) -, mFilename("") -, mCachedSize(SIZE_MAX) { - // empty -} - -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename) -: mFile(pFile) -, mFilename(strFilename) -, mCachedSize(SIZE_MAX) { - // empty -} -// ---------------------------------------------------------------------------------- - -} // ns assimp - -#endif //!!AI_DEFAULTIOSTREAM_H_INC diff --git a/thirdparty/assimp/include/assimp/DefaultIOSystem.h b/thirdparty/assimp/include/assimp/DefaultIOSystem.h deleted file mode 100644 index 46f6d447c505..000000000000 --- a/thirdparty/assimp/include/assimp/DefaultIOSystem.h +++ /dev/null @@ -1,98 +0,0 @@ -/* -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 Default implementation of IOSystem using the standard C file functions */ -#pragma once -#ifndef AI_DEFAULTIOSYSTEM_H_INC -#define AI_DEFAULTIOSYSTEM_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** Default implementation of IOSystem using the standard C file functions */ -class ASSIMP_API DefaultIOSystem : public IOSystem { -public: - // ------------------------------------------------------------------- - /** Tests for the existence of a file at the given path. */ - bool Exists( const char* pFile) const; - - // ------------------------------------------------------------------- - /** Returns the directory separator. */ - char getOsSeparator() const; - - // ------------------------------------------------------------------- - /** Open a new file with a given path. */ - IOStream* Open( const char* pFile, const char* pMode = "rb"); - - // ------------------------------------------------------------------- - /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* pFile); - - // ------------------------------------------------------------------- - /** Compare two paths */ - bool ComparePaths (const char* one, const char* second) const; - - /** @brief get the file name of a full filepath - * example: /tmp/archive.tar.gz -> archive.tar.gz - */ - static std::string fileName( const std::string &path ); - - /** @brief get the complete base name of a full filepath - * example: /tmp/archive.tar.gz -> archive.tar - */ - static std::string completeBaseName( const std::string &path); - - /** @brief get the path of a full filepath - * example: /tmp/archive.tar.gz -> /tmp/ - */ - static std::string absolutePath( const std::string &path); -}; - -} //!ns Assimp - -#endif //AI_DEFAULTIOSYSTEM_H_INC diff --git a/thirdparty/assimp/include/assimp/DefaultLogger.hpp b/thirdparty/assimp/include/assimp/DefaultLogger.hpp deleted file mode 100644 index 1946e250a687..000000000000 --- a/thirdparty/assimp/include/assimp/DefaultLogger.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/* -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 DefaultLogger.hpp -*/ - -#ifndef INCLUDED_AI_DEFAULTLOGGER -#define INCLUDED_AI_DEFAULTLOGGER - -#include "Logger.hpp" -#include "LogStream.hpp" -#include "NullLogger.hpp" -#include - -namespace Assimp { -// ------------------------------------------------------------------------------------ -class IOStream; -struct LogStreamInfo; - -/** default name of logfile */ -#define ASSIMP_DEFAULT_LOG_NAME "AssimpLog.txt" - -// ------------------------------------------------------------------------------------ -/** @brief CPP-API: Primary logging facility of Assimp. - * - * The library stores its primary #Logger as a static member of this class. - * #get() returns this primary logger. By default the underlying implementation is - * just a #NullLogger which rejects all log messages. By calling #create(), logging - * is turned on. To capture the log output multiple log streams (#LogStream) can be - * attach to the logger. Some default streams for common streaming locations (such as - * a file, std::cout, OutputDebugString()) are also provided. - * - * If you wish to customize the logging at an even deeper level supply your own - * implementation of #Logger to #set(). - * @note The whole logging stuff causes a small extra overhead for all imports. */ -class ASSIMP_API DefaultLogger : - public Logger { - -public: - - // ---------------------------------------------------------------------- - /** @brief Creates a logging instance. - * @param name Name for log file. Only valid in combination - * with the aiDefaultLogStream_FILE flag. - * @param severity Log severity, VERBOSE turns on debug messages - * @param defStreams Default log streams to be attached. Any bitwise - * combination of the aiDefaultLogStream enumerated values. - * If #aiDefaultLogStream_FILE is specified but an empty string is - * passed for 'name', no log file is created at all. - * @param io IOSystem to be used to open external files (such as the - * log file). Pass NULL to rely on the default implementation. - * This replaces the default #NullLogger with a #DefaultLogger instance. */ - static Logger *create(const char* name = ASSIMP_DEFAULT_LOG_NAME, - LogSeverity severity = NORMAL, - unsigned int defStreams = aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE, - IOSystem* io = NULL); - - // ---------------------------------------------------------------------- - /** @brief Setup a custom #Logger implementation. - * - * Use this if the provided #DefaultLogger class doesn't fit into - * your needs. If the provided message formatting is OK for you, - * it's much easier to use #create() and to attach your own custom - * output streams to it. - * @param logger Pass NULL to setup a default NullLogger*/ - static void set (Logger *logger); - - // ---------------------------------------------------------------------- - /** @brief Getter for singleton instance - * @return Only instance. This is never null, but it could be a - * NullLogger. Use isNullLogger to check this.*/ - static Logger *get(); - - // ---------------------------------------------------------------------- - /** @brief Return whether a #NullLogger is currently active - * @return true if the current logger is a #NullLogger. - * Use create() or set() to setup a logger that does actually do - * something else than just rejecting all log messages. */ - static bool isNullLogger(); - - // ---------------------------------------------------------------------- - /** @brief Kills the current singleton logger and replaces it with a - * #NullLogger instance. */ - static void kill(); - - // ---------------------------------------------------------------------- - /** @copydoc Logger::attachStream */ - bool attachStream(LogStream *pStream, - unsigned int severity); - - // ---------------------------------------------------------------------- - /** @copydoc Logger::detatchStream */ - bool detatchStream(LogStream *pStream, - unsigned int severity); - -private: - // ---------------------------------------------------------------------- - /** @briefPrivate construction for internal use by create(). - * @param severity Logging granularity */ - explicit DefaultLogger(LogSeverity severity); - - // ---------------------------------------------------------------------- - /** @briefDestructor */ - ~DefaultLogger(); - - /** @brief Logs debug infos, only been written when severity level VERBOSE is set */ - void OnDebug(const char* message); - - /** @brief Logs an info message */ - void OnInfo(const char* message); - - /** @brief Logs a warning message */ - void OnWarn(const char* message); - - /** @brief Logs an error message */ - void OnError(const char* message); - - // ---------------------------------------------------------------------- - /** @brief Writes a message to all streams */ - void WriteToStreams(const char* message, ErrorSeverity ErrorSev ); - - // ---------------------------------------------------------------------- - /** @brief Returns the thread id. - * @note This is an OS specific feature, if not supported, a - * zero will be returned. - */ - unsigned int GetThreadID(); - -private: - // Aliases for stream container - typedef std::vector StreamArray; - typedef std::vector::iterator StreamIt; - typedef std::vector::const_iterator ConstStreamIt; - - //! only logging instance - static Logger *m_pLogger; - static NullLogger s_pNullLogger; - - //! Attached streams - StreamArray m_StreamArray; - - bool noRepeatMsg; - char lastMsg[MAX_LOG_MESSAGE_LENGTH*2]; - size_t lastLen; -}; -// ------------------------------------------------------------------------------------ - -} // Namespace Assimp - -#endif // !! INCLUDED_AI_DEFAULTLOGGER diff --git a/thirdparty/assimp/include/assimp/Defines.h b/thirdparty/assimp/include/assimp/Defines.h deleted file mode 100644 index be3e2fafd6d6..000000000000 --- a/thirdparty/assimp/include/assimp/Defines.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#pragma once -#ifndef AI_DEFINES_H_INC -#define AI_DEFINES_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -// We need those constants, workaround for any platforms where nobody defined them yet -#if (!defined SIZE_MAX) -# define SIZE_MAX (~((size_t)0)) -#endif - -#if (!defined UINT_MAX) -# define UINT_MAX (~((unsigned int)0)) -#endif - -#endif // AI_DEINES_H_INC diff --git a/thirdparty/assimp/include/assimp/Exceptional.h b/thirdparty/assimp/include/assimp/Exceptional.h deleted file mode 100644 index 6bb6ce1e39f8..000000000000 --- a/thirdparty/assimp/include/assimp/Exceptional.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2008, 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. - ----------------------------------------------------------------------- -*/ - -#pragma once -#ifndef AI_INCLUDED_EXCEPTIONAL_H -#define AI_INCLUDED_EXCEPTIONAL_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -using std::runtime_error; - -#ifdef _MSC_VER -# pragma warning(disable : 4275) -#endif - -// --------------------------------------------------------------------------- -/** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an - * unrecoverable error occurs while importing. Loading APIs return - * NULL instead of a valid aiScene then. */ -class DeadlyImportError : public runtime_error { -public: - /** Constructor with arguments */ - explicit DeadlyImportError( const std::string& errorText) - : runtime_error(errorText) { - // empty - } - -}; - -typedef DeadlyImportError DeadlyExportError; - -#ifdef _MSC_VER -# pragma warning(default : 4275) -#endif - -// --------------------------------------------------------------------------- -template -struct ExceptionSwallower { - T operator ()() const { - return T(); - } -}; - -// --------------------------------------------------------------------------- -template -struct ExceptionSwallower { - T* operator ()() const { - return nullptr; - } -}; - -// --------------------------------------------------------------------------- -template <> -struct ExceptionSwallower { - aiReturn operator ()() const { - try { - throw; - } - catch (std::bad_alloc&) { - return aiReturn_OUTOFMEMORY; - } - catch (...) { - return aiReturn_FAILURE; - } - } -}; - -// --------------------------------------------------------------------------- -template <> -struct ExceptionSwallower { - void operator ()() const { - return; - } -}; - -#define ASSIMP_BEGIN_EXCEPTION_REGION()\ -{\ - try { - -#define ASSIMP_END_EXCEPTION_REGION(type)\ - } catch(...) {\ - return ExceptionSwallower()();\ - }\ -} - -#endif // AI_INCLUDED_EXCEPTIONAL_H diff --git a/thirdparty/assimp/include/assimp/Exporter.hpp b/thirdparty/assimp/include/assimp/Exporter.hpp deleted file mode 100644 index 2612e1f9d275..000000000000 --- a/thirdparty/assimp/include/assimp/Exporter.hpp +++ /dev/null @@ -1,509 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Exporter.hpp -* @brief Defines the CPP-API for the Assimp export interface -*/ -#pragma once -#ifndef AI_EXPORT_HPP_INC -#define AI_EXPORT_HPP_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#ifndef ASSIMP_BUILD_NO_EXPORT - -#include "cexport.h" -#include - -namespace Assimp { - -class ExporterPimpl; -class IOSystem; -class ProgressHandler; - -// ---------------------------------------------------------------------------------- -/** CPP-API: The Exporter class forms an C++ interface to the export functionality - * of the Open Asset Import Library. Note that the export interface is available - * only if Assimp has been built with ASSIMP_BUILD_NO_EXPORT not defined. - * - * The interface is modeled after the importer interface and mostly - * symmetric. The same rules for threading etc. apply. - * - * In a nutshell, there are two export interfaces: #Export, which writes the - * output file(s) either to the regular file system or to a user-supplied - * #IOSystem, and #ExportToBlob which returns a linked list of memory - * buffers (blob), each referring to one output file (in most cases - * there will be only one output file of course, but this extra complexity is - * needed since Assimp aims at supporting a wide range of file formats). - * - * #ExportToBlob is especially useful if you intend to work - * with the data in-memory. -*/ -class ASSIMP_API ExportProperties; - -class ASSIMP_API Exporter { -public: - /** Function pointer type of a Export worker function */ - typedef void (*fpExportFunc)(const char*, IOSystem*, const aiScene*, const ExportProperties*); - - /** Internal description of an Assimp export format option */ - struct ExportFormatEntry { - /// Public description structure to be returned by aiGetExportFormatDescription() - aiExportFormatDesc mDescription; - - // Worker function to do the actual exporting - fpExportFunc mExportFunction; - - // Post-processing steps to be executed PRIOR to invoking mExportFunction - unsigned int mEnforcePP; - - // Constructor to fill all entries - ExportFormatEntry( const char* pId, const char* pDesc, const char* pExtension, fpExportFunc pFunction, unsigned int pEnforcePP = 0u) - { - mDescription.id = pId; - mDescription.description = pDesc; - mDescription.fileExtension = pExtension; - mExportFunction = pFunction; - mEnforcePP = pEnforcePP; - } - - ExportFormatEntry() : - mExportFunction() - , mEnforcePP() - { - mDescription.id = NULL; - mDescription.description = NULL; - mDescription.fileExtension = NULL; - } - }; - - /** - * @brief The class constructor. - */ - Exporter(); - - /** - * @brief The class destructor. - */ - ~Exporter(); - - // ------------------------------------------------------------------- - /** Supplies a custom IO handler to the exporter to use to open and - * access files. - * - * If you need #Export to use custom IO logic to access the files, - * you need to supply a custom implementation of IOSystem and - * IOFile to the exporter. - * - * #Exporter takes ownership of the object and will destroy it - * afterwards. The previously assigned handler will be deleted. - * Pass NULL to take again ownership of your IOSystem and reset Assimp - * to use its default implementation, which uses plain file IO. - * - * @param pIOHandler The IO handler to be used in all file accesses - * of the Importer. */ - void SetIOHandler( IOSystem* pIOHandler); - - // ------------------------------------------------------------------- - /** Retrieves the IO handler that is currently set. - * You can use #IsDefaultIOHandler() to check whether the returned - * interface is the default IO handler provided by ASSIMP. The default - * handler is active as long the application doesn't supply its own - * custom IO handler via #SetIOHandler(). - * @return A valid IOSystem interface, never NULL. */ - IOSystem* GetIOHandler() const; - - // ------------------------------------------------------------------- - /** Checks whether a default IO handler is active - * A default handler is active as long the application doesn't - * supply its own custom IO handler via #SetIOHandler(). - * @return true by default */ - bool IsDefaultIOHandler() const; - - // ------------------------------------------------------------------- - /** Supplies a custom progress handler to the exporter. This - * interface exposes an #Update() callback, which is called - * more or less periodically (please don't sue us if it - * isn't as periodically as you'd like it to have ...). - * This can be used to implement progress bars and loading - * timeouts. - * @param pHandler Progress callback interface. Pass nullptr to - * disable progress reporting. - * @note Progress handlers can be used to abort the loading - * at almost any time.*/ - void SetProgressHandler(ProgressHandler* pHandler); - - // ------------------------------------------------------------------- - /** Exports the given scene to a chosen file format. Returns the exported - * data as a binary blob which you can write into a file or something. - * When you're done with the data, simply let the #Exporter instance go - * out of scope to have it released automatically. - * @param pScene The scene to export. Stays in possession of the caller, - * is not changed by the function. - * @param pFormatId ID string to specify to which format you want to - * export to. Use - * #GetExportFormatCount / #GetExportFormatDescription to learn which - * export formats are available. - * @param pPreprocessing See the documentation for #Export - * @return the exported data or NULL in case of error. - * @note If the Exporter instance did already hold a blob from - * a previous call to #ExportToBlob, it will be disposed. - * Any IO handlers set via #SetIOHandler are ignored here. - * @note Use aiCopyScene() to get a modifiable copy of a previously - * imported scene. */ - const aiExportDataBlob* ExportToBlob(const aiScene* pScene, const char* pFormatId, - unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); - const aiExportDataBlob* ExportToBlob( const aiScene* pScene, const std::string& pFormatId, - unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); - - // ------------------------------------------------------------------- - /** Convenience function to export directly to a file. Use - * #SetIOSystem to supply a custom IOSystem to gain fine-grained control - * about the output data flow of the export process. - * @param pBlob A data blob obtained from a previous call to #aiExportScene. Must not be NULL. - * @param pPath Full target file name. Target must be accessible. - * @param pPreprocessing Accepts any choice of the #aiPostProcessSteps enumerated - * flags, but in reality only a subset of them makes sense here. Specifying - * 'preprocessing' flags is useful if the input scene does not conform to - * Assimp's default conventions as specified in the @link data Data Structures Page @endlink. - * In short, this means the geometry data should use a right-handed coordinate systems, face - * winding should be counter-clockwise and the UV coordinate origin is assumed to be in - * the upper left. The #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and - * #aiProcess_FlipWindingOrder flags are used in the import side to allow users - * to have those defaults automatically adapted to their conventions. Specifying those flags - * for exporting has the opposite effect, respectively. Some other of the - * #aiPostProcessSteps enumerated values may be useful as well, but you'll need - * to try out what their effect on the exported file is. Many formats impose - * their own restrictions on the structure of the geometry stored therein, - * so some preprocessing may have little or no effect at all, or may be - * redundant as exporters would apply them anyhow. A good example - * is triangulation - whilst you can enforce it by specifying - * the #aiProcess_Triangulate flag, most export formats support only - * triangulate data so they would run the step even if it wasn't requested. - * - * If assimp detects that the input scene was directly taken from the importer side of - * the library (i.e. not copied using aiCopyScene and potentially modified afterwards), - * any post-processing steps already applied to the scene will not be applied again, unless - * they show non-idempotent behavior (#aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and - * #aiProcess_FlipWindingOrder). - * @return AI_SUCCESS if everything was fine. - * @note Use aiCopyScene() to get a modifiable copy of a previously - * imported scene.*/ - aiReturn Export( const aiScene* pScene, const char* pFormatId, const char* pPath, - unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); - aiReturn Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, - unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); - - // ------------------------------------------------------------------- - /** Returns an error description of an error that occurred in #Export - * or #ExportToBlob - * - * Returns an empty string if no error occurred. - * @return A description of the last error, an empty string if no - * error occurred. The string is never NULL. - * - * @note The returned function remains valid until one of the - * following methods is called: #Export, #ExportToBlob, #FreeBlob */ - const char* GetErrorString() const; - - // ------------------------------------------------------------------- - /** Return the blob obtained from the last call to #ExportToBlob */ - const aiExportDataBlob* GetBlob() const; - - // ------------------------------------------------------------------- - /** Orphan the blob from the last call to #ExportToBlob. This means - * the caller takes ownership and is thus responsible for calling - * the C API function #aiReleaseExportBlob to release it. */ - const aiExportDataBlob* GetOrphanedBlob() const; - - // ------------------------------------------------------------------- - /** Frees the current blob. - * - * The function does nothing if no blob has previously been - * previously produced via #ExportToBlob. #FreeBlob is called - * automatically by the destructor. The only reason to call - * it manually would be to reclaim as much storage as possible - * without giving up the #Exporter instance yet. */ - void FreeBlob( ); - - // ------------------------------------------------------------------- - /** Returns the number of export file formats available in the current - * Assimp build. Use #Exporter::GetExportFormatDescription to - * retrieve infos of a specific export format. - * - * This includes built-in exporters as well as exporters registered - * using #RegisterExporter. - **/ - size_t GetExportFormatCount() const; - - // ------------------------------------------------------------------- - /** Returns a description of the nth export file format. Use # - * #Exporter::GetExportFormatCount to learn how many export - * formats are supported. - * - * The returned pointer is of static storage duration if the - * pIndex pertains to a built-in exporter (i.e. one not registered - * via #RegistrerExporter). It is restricted to the life-time of the - * #Exporter instance otherwise. - * - * @param pIndex Index of the export format to retrieve information - * for. Valid range is 0 to #Exporter::GetExportFormatCount - * @return A description of that specific export format. - * NULL if pIndex is out of range. */ - const aiExportFormatDesc* GetExportFormatDescription( size_t pIndex ) const; - - // ------------------------------------------------------------------- - /** Register a custom exporter. Custom export formats are limited to - * to the current #Exporter instance and do not affect the - * library globally. The indexes under which the format's - * export format description can be queried are assigned - * monotonously. - * @param desc Exporter description. - * @return aiReturn_SUCCESS if the export format was successfully - * registered. A common cause that would prevent an exporter - * from being registered is that its format id is already - * occupied by another format. */ - aiReturn RegisterExporter(const ExportFormatEntry& desc); - - // ------------------------------------------------------------------- - /** Remove an export format previously registered with #RegisterExporter - * from the #Exporter instance (this can also be used to drop - * built-in exporters because those are implicitly registered - * using #RegisterExporter). - * @param id Format id to be unregistered, this refers to the - * 'id' field of #aiExportFormatDesc. - * @note Calling this method on a format description not yet registered - * has no effect.*/ - void UnregisterExporter(const char* id); - -protected: - // Just because we don't want you to know how we're hacking around. - ExporterPimpl* pimpl; -}; - -class ASSIMP_API ExportProperties { -public: - // Data type to store the key hash - typedef unsigned int KeyType; - - // typedefs for our four configuration maps. - // We don't need more, so there is no need for a generic solution - typedef std::map IntPropertyMap; - typedef std::map FloatPropertyMap; - typedef std::map StringPropertyMap; - typedef std::map MatrixPropertyMap; - -public: - /** Standard constructor - * @see ExportProperties() - */ - ExportProperties(); - - // ------------------------------------------------------------------- - /** Copy constructor. - * - * This copies the configuration properties of another ExportProperties. - * @see ExportProperties(const ExportProperties& other) - */ - ExportProperties(const ExportProperties& other); - - // ------------------------------------------------------------------- - /** Set an integer configuration property. - * @param szName Name of the property. All supported properties - * are defined in the aiConfig.g header (all constants share the - * prefix AI_CONFIG_XXX and are simple strings). - * @param iValue New value of the property - * @return true if the property was set before. The new value replaces - * the previous value in this case. - * @note Property of different types (float, int, string ..) are kept - * on different stacks, so calling SetPropertyInteger() for a - * floating-point property has no effect - the loader will call - * GetPropertyFloat() to read the property, but it won't be there. - */ - bool SetPropertyInteger(const char* szName, int iValue); - - // ------------------------------------------------------------------- - /** Set a boolean configuration property. Boolean properties - * are stored on the integer stack internally so it's possible - * to set them via #SetPropertyBool and query them with - * #GetPropertyBool and vice versa. - * @see SetPropertyInteger() - */ - bool SetPropertyBool(const char* szName, bool value) { - return SetPropertyInteger(szName,value); - } - - // ------------------------------------------------------------------- - /** Set a floating-point configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyFloat(const char* szName, ai_real fValue); - - // ------------------------------------------------------------------- - /** Set a string configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyString(const char* szName, const std::string& sValue); - - // ------------------------------------------------------------------- - /** Set a matrix configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyMatrix(const char* szName, const aiMatrix4x4& sValue); - - // ------------------------------------------------------------------- - /** Get a configuration property. - * @param szName Name of the property. All supported properties - * are defined in the aiConfig.g header (all constants share the - * prefix AI_CONFIG_XXX). - * @param iErrorReturn Value that is returned if the property - * is not found. - * @return Current value of the property - * @note Property of different types (float, int, string ..) are kept - * on different lists, so calling SetPropertyInteger() for a - * floating-point property has no effect - the loader will call - * GetPropertyFloat() to read the property, but it won't be there. - */ - int GetPropertyInteger(const char* szName, - int iErrorReturn = 0xffffffff) const; - - // ------------------------------------------------------------------- - /** Get a boolean configuration property. Boolean properties - * are stored on the integer stack internally so it's possible - * to set them via #SetPropertyBool and query them with - * #GetPropertyBool and vice versa. - * @see GetPropertyInteger() - */ - bool GetPropertyBool(const char* szName, bool bErrorReturn = false) const { - return GetPropertyInteger(szName,bErrorReturn)!=0; - } - - // ------------------------------------------------------------------- - /** Get a floating-point configuration property - * @see GetPropertyInteger() - */ - ai_real GetPropertyFloat(const char* szName, - ai_real fErrorReturn = 10e10f) const; - - // ------------------------------------------------------------------- - /** Get a string configuration property - * - * The return value remains valid until the property is modified. - * @see GetPropertyInteger() - */ - const std::string GetPropertyString(const char* szName, - const std::string& sErrorReturn = "") const; - - // ------------------------------------------------------------------- - /** Get a matrix configuration property - * - * The return value remains valid until the property is modified. - * @see GetPropertyInteger() - */ - const aiMatrix4x4 GetPropertyMatrix(const char* szName, - const aiMatrix4x4& sErrorReturn = aiMatrix4x4()) const; - - // ------------------------------------------------------------------- - /** Determine a integer configuration property has been set. - * @see HasPropertyInteger() - */ - bool HasPropertyInteger(const char* szName) const; - - /** Determine a boolean configuration property has been set. - * @see HasPropertyBool() - */ - bool HasPropertyBool(const char* szName) const; - - /** Determine a boolean configuration property has been set. - * @see HasPropertyFloat() - */ - bool HasPropertyFloat(const char* szName) const; - - /** Determine a String configuration property has been set. - * @see HasPropertyString() - */ - bool HasPropertyString(const char* szName) const; - - /** Determine a Matrix configuration property has been set. - * @see HasPropertyMatrix() - */ - bool HasPropertyMatrix(const char* szName) const; - -protected: - - /** List of integer properties */ - IntPropertyMap mIntProperties; - - /** List of floating-point properties */ - FloatPropertyMap mFloatProperties; - - /** List of string properties */ - StringPropertyMap mStringProperties; - - /** List of Matrix properties */ - MatrixPropertyMap mMatrixProperties; -}; - -// ---------------------------------------------------------------------------------- -inline -const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const std::string& pFormatId, - unsigned int pPreprocessing, const ExportProperties* pProperties) -{ - return ExportToBlob(pScene,pFormatId.c_str(),pPreprocessing, pProperties); -} - -// ---------------------------------------------------------------------------------- -inline -aiReturn Exporter :: Export( const aiScene* pScene, const std::string& pFormatId, - const std::string& pPath, unsigned int pPreprocessing, - const ExportProperties* pProperties) -{ - return Export(pScene,pFormatId.c_str(),pPath.c_str(),pPreprocessing, pProperties); -} - -} // namespace Assimp - -#endif // ASSIMP_BUILD_NO_EXPORT -#endif // AI_EXPORT_HPP_INC diff --git a/thirdparty/assimp/include/assimp/GenericProperty.h b/thirdparty/assimp/include/assimp/GenericProperty.h deleted file mode 100644 index 7796d595b89e..000000000000 --- a/thirdparty/assimp/include/assimp/GenericProperty.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#pragma once -#ifndef AI_GENERIC_PROPERTY_H_INCLUDED -#define AI_GENERIC_PROPERTY_H_INCLUDED - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include - -// ------------------------------------------------------------------------------------------------ -template -inline -bool SetGenericProperty(std::map< unsigned int, T >& list, - const char* szName, const T& value) { - ai_assert(nullptr != szName); - const uint32_t hash = SuperFastHash(szName); - - typename std::map::iterator it = list.find(hash); - if (it == list.end()) { - list.insert(std::pair( hash, value )); - return false; - } - (*it).second = value; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -template -inline -const T& GetGenericProperty(const std::map< unsigned int, T >& list, - const char* szName, const T& errorReturn) { - ai_assert(nullptr != szName); - const uint32_t hash = SuperFastHash(szName); - - typename std::map::const_iterator it = list.find(hash); - if (it == list.end()) { - return errorReturn; - } - - return (*it).second; -} - -// ------------------------------------------------------------------------------------------------ -// Special version for pointer types - they will be deleted when replaced with another value -// passing NULL removes the whole property -template -inline -void SetGenericPropertyPtr(std::map< unsigned int, T* >& list, - const char* szName, T* value, bool* bWasExisting = nullptr ) { - ai_assert(nullptr != szName); - const uint32_t hash = SuperFastHash(szName); - - typename std::map::iterator it = list.find(hash); - if (it == list.end()) { - if (bWasExisting) { - *bWasExisting = false; - } - - list.insert(std::pair( hash, value )); - return; - } - if ((*it).second != value) { - delete (*it).second; - (*it).second = value; - } - if (!value) { - list.erase(it); - } - if (bWasExisting) { - *bWasExisting = true; - } -} - -// ------------------------------------------------------------------------------------------------ -template -inline -bool HasGenericProperty(const std::map< unsigned int, T >& list, - const char* szName) { - ai_assert(nullptr != szName); - const uint32_t hash = SuperFastHash(szName); - - typename std::map::const_iterator it = list.find(hash); - if (it == list.end()) { - return false; - } - - return true; -} - -#endif // !! AI_GENERIC_PROPERTY_H_INCLUDED diff --git a/thirdparty/assimp/include/assimp/Hash.h b/thirdparty/assimp/include/assimp/Hash.h deleted file mode 100644 index 905644078971..000000000000 --- a/thirdparty/assimp/include/assimp/Hash.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ -#pragma once -#ifndef AI_HASH_H_INCLUDED -#define AI_HASH_H_INCLUDED - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -// ------------------------------------------------------------------------------------------------ -// Hashing function taken from -// http://www.azillionmonkeys.com/qed/hash.html -// (incremental version) -// -// This code is Copyright 2004-2008 by Paul Hsieh. It is used here in the belief that -// Assimp's license is considered compatible with Pauls's derivative license as specified -// on his web page. -// -// (stdint.h should have been been included here) -// ------------------------------------------------------------------------------------------------ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif - -// ------------------------------------------------------------------------------------------------ -inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) { -uint32_t tmp; -int rem; - - if (!data) return 0; - if (!len)len = (uint32_t)::strlen(data); - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -#endif // !! AI_HASH_H_INCLUDED diff --git a/thirdparty/assimp/include/assimp/IOStream.hpp b/thirdparty/assimp/include/assimp/IOStream.hpp deleted file mode 100644 index 39932cd9496a..000000000000 --- a/thirdparty/assimp/include/assimp/IOStream.hpp +++ /dev/null @@ -1,146 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 IOStream.hpp - * @brief File I/O wrappers for C++. - */ - -#pragma once -#ifndef AI_IOSTREAM_H_INC -#define AI_IOSTREAM_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -#ifndef __cplusplus -# error This header requires C++ to be used. aiFileIO.h is the \ - corresponding C interface. -#endif - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** @brief CPP-API: Class to handle file I/O for C++ - * - * Derive an own implementation from this interface to provide custom IO handling - * to the Importer. If you implement this interface, be sure to also provide an - * implementation for IOSystem that creates instances of your custom IO class. -*/ -class ASSIMP_API IOStream -#ifndef SWIG - : public Intern::AllocateFromAssimpHeap -#endif -{ -protected: - /** Constructor protected, use IOSystem::Open() to create an instance. */ - IOStream() AI_NO_EXCEPT; - -public: - // ------------------------------------------------------------------- - /** @brief Destructor. Deleting the object closes the underlying file, - * alternatively you may use IOSystem::Close() to release the file. - */ - virtual ~IOStream(); - - // ------------------------------------------------------------------- - /** @brief Read from the file - * - * See fread() for more details - * This fails for write-only files */ - virtual size_t Read(void* pvBuffer, - size_t pSize, - size_t pCount) = 0; - - // ------------------------------------------------------------------- - /** @brief Write to the file - * - * See fwrite() for more details - * This fails for read-only files */ - virtual size_t Write(const void* pvBuffer, - size_t pSize, - size_t pCount) = 0; - - // ------------------------------------------------------------------- - /** @brief Set the read/write cursor of the file - * - * Note that the offset is _negative_ for aiOrigin_END. - * See fseek() for more details */ - virtual aiReturn Seek(size_t pOffset, - aiOrigin pOrigin) = 0; - - // ------------------------------------------------------------------- - /** @brief Get the current position of the read/write cursor - * - * See ftell() for more details */ - virtual size_t Tell() const = 0; - - // ------------------------------------------------------------------- - /** @brief Returns filesize - * Returns the filesize. */ - virtual size_t FileSize() const = 0; - - // ------------------------------------------------------------------- - /** @brief Flush the contents of the file buffer (for writers) - * See fflush() for more details. - */ - virtual void Flush() = 0; -}; //! class IOStream - -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -IOStream::IOStream() AI_NO_EXCEPT { - // empty -} - -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -IOStream::~IOStream() { - // empty -} -// ---------------------------------------------------------------------------------- - -} //!namespace Assimp - -#endif //!!AI_IOSTREAM_H_INC diff --git a/thirdparty/assimp/include/assimp/IOStreamBuffer.h b/thirdparty/assimp/include/assimp/IOStreamBuffer.h deleted file mode 100644 index 97c84b23e2e7..000000000000 --- a/thirdparty/assimp/include/assimp/IOStreamBuffer.h +++ /dev/null @@ -1,362 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#pragma once -#ifndef AI_IOSTREAMBUFFER_H_INC -#define AI_IOSTREAMBUFFER_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** - * Implementation of a cached stream buffer. - */ -template -class IOStreamBuffer { -public: - /// @brief The class constructor. - IOStreamBuffer( size_t cache = 4096 * 4096 ); - - /// @brief The class destructor. - ~IOStreamBuffer(); - - /// @brief Will open the cached access for a given stream. - /// @param stream The stream to cache. - /// @return true if successful. - bool open( IOStream *stream ); - - /// @brief Will close the cached access. - /// @return true if successful. - bool close(); - - /// @brief Returns the file-size. - /// @return The file-size. - size_t size() const; - - /// @brief Returns the cache size. - /// @return The cache size. - size_t cacheSize() const; - - /// @brief Will read the next block. - /// @return true if successful. - bool readNextBlock(); - - /// @brief Returns the number of blocks to read. - /// @return The number of blocks. - size_t getNumBlocks() const; - - /// @brief Returns the current block index. - /// @return The current block index. - size_t getCurrentBlockIndex() const; - - /// @brief Returns the current file pos. - /// @return The current file pos. - size_t getFilePos() const; - - /// @brief Will read the next line. - /// @param buffer The buffer for the next line. - /// @return true if successful. - bool getNextDataLine( std::vector &buffer, T continuationToken ); - - /// @brief Will read the next line ascii or binary end line char. - /// @param buffer The buffer for the next line. - /// @return true if successful. - bool getNextLine(std::vector &buffer); - - /// @brief Will read the next block. - /// @param buffer The buffer for the next block. - /// @return true if successful. - bool getNextBlock( std::vector &buffer ); - -private: - IOStream *m_stream; - size_t m_filesize; - size_t m_cacheSize; - size_t m_numBlocks; - size_t m_blockIdx; - std::vector m_cache; - size_t m_cachePos; - size_t m_filePos; -}; - -template -AI_FORCE_INLINE -IOStreamBuffer::IOStreamBuffer( size_t cache ) -: m_stream( nullptr ) -, m_filesize( 0 ) -, m_cacheSize( cache ) -, m_numBlocks( 0 ) -, m_blockIdx( 0 ) -, m_cachePos( 0 ) -, m_filePos( 0 ) { - m_cache.resize( cache ); - std::fill( m_cache.begin(), m_cache.end(), '\n' ); -} - -template -AI_FORCE_INLINE -IOStreamBuffer::~IOStreamBuffer() { - // empty -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::open( IOStream *stream ) { - // file still opened! - if ( nullptr != m_stream ) { - return false; - } - - // Invalid stream pointer - if ( nullptr == stream ) { - return false; - } - - m_stream = stream; - m_filesize = m_stream->FileSize(); - if ( m_filesize == 0 ) { - return false; - } - if ( m_filesize < m_cacheSize ) { - m_cacheSize = m_filesize; - } - - m_numBlocks = m_filesize / m_cacheSize; - if ( ( m_filesize % m_cacheSize ) > 0 ) { - m_numBlocks++; - } - - return true; -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::close() { - if ( nullptr == m_stream ) { - return false; - } - - // init counters and state vars - m_stream = nullptr; - m_filesize = 0; - m_numBlocks = 0; - m_blockIdx = 0; - m_cachePos = 0; - m_filePos = 0; - - return true; -} - -template -AI_FORCE_INLINE -size_t IOStreamBuffer::size() const { - return m_filesize; -} - -template -AI_FORCE_INLINE -size_t IOStreamBuffer::cacheSize() const { - return m_cacheSize; -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::readNextBlock() { - m_stream->Seek( m_filePos, aiOrigin_SET ); - size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize ); - if ( readLen == 0 ) { - return false; - } - if ( readLen < m_cacheSize ) { - m_cacheSize = readLen; - } - m_filePos += m_cacheSize; - m_cachePos = 0; - m_blockIdx++; - - return true; -} - -template -AI_FORCE_INLINE -size_t IOStreamBuffer::getNumBlocks() const { - return m_numBlocks; -} - -template -AI_FORCE_INLINE -size_t IOStreamBuffer::getCurrentBlockIndex() const { - return m_blockIdx; -} - -template -AI_FORCE_INLINE -size_t IOStreamBuffer::getFilePos() const { - return m_filePos; -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationToken ) { - buffer.resize( m_cacheSize ); - if ( m_cachePos >= m_cacheSize || 0 == m_filePos ) { - if ( !readNextBlock() ) { - return false; - } - } - - bool continuationFound( false ); - size_t i = 0; - for( ;; ) { - if ( continuationToken == m_cache[ m_cachePos ] ) { - continuationFound = true; - ++m_cachePos; - } - if ( IsLineEnd( m_cache[ m_cachePos ] ) ) { - if ( !continuationFound ) { - // the end of the data line - break; - } else { - // skip line end - while ( m_cache[m_cachePos] != '\n') { - ++m_cachePos; - } - ++m_cachePos; - continuationFound = false; - } - } - - buffer[ i ] = m_cache[ m_cachePos ]; - ++m_cachePos; - ++i; - if (m_cachePos >= size()) { - break; - } - if ( m_cachePos >= m_cacheSize ) { - if ( !readNextBlock() ) { - return false; - } - } - } - - buffer[ i ] = '\n'; - ++m_cachePos; - - return true; -} - -static AI_FORCE_INLINE -bool isEndOfCache( size_t pos, size_t cacheSize ) { - return ( pos == cacheSize ); -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::getNextLine(std::vector &buffer) { - buffer.resize(m_cacheSize); - if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) { - if (!readNextBlock()) { - return false; - } - } - - if (IsLineEnd(m_cache[m_cachePos])) { - // skip line end - while (m_cache[m_cachePos] != '\n') { - ++m_cachePos; - } - ++m_cachePos; - if ( isEndOfCache( m_cachePos, m_cacheSize ) ) { - if ( !readNextBlock() ) { - return false; - } - } - } - - size_t i( 0 ); - while (!IsLineEnd(m_cache[ m_cachePos ])) { - buffer[i] = m_cache[ m_cachePos ]; - ++m_cachePos; - ++i; - if (m_cachePos >= m_cacheSize) { - if (!readNextBlock()) { - return false; - } - } - } - buffer[i] = '\n'; - ++m_cachePos; - - return true; -} - -template -AI_FORCE_INLINE -bool IOStreamBuffer::getNextBlock( std::vector &buffer) { - // Return the last block-value if getNextLine was used before - if ( 0 != m_cachePos ) { - buffer = std::vector( m_cache.begin() + m_cachePos, m_cache.end() ); - m_cachePos = 0; - } else { - if ( !readNextBlock() ) { - return false; - } - - buffer = std::vector(m_cache.begin(), m_cache.end()); - } - - return true; -} - -} // !ns Assimp - -#endif // AI_IOSTREAMBUFFER_H_INC diff --git a/thirdparty/assimp/include/assimp/IOSystem.hpp b/thirdparty/assimp/include/assimp/IOSystem.hpp deleted file mode 100644 index f1fb3b0c2770..000000000000 --- a/thirdparty/assimp/include/assimp/IOSystem.hpp +++ /dev/null @@ -1,361 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 IOSystem.hpp - * @brief File system wrapper for C++. Inherit this class to supply - * custom file handling logic to the Import library. -*/ - -#pragma once -#ifndef AI_IOSYSTEM_H_INC -#define AI_IOSYSTEM_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#ifndef __cplusplus -# error This header requires C++ to be used. aiFileIO.h is the \ - corresponding C interface. -#endif - -#include "types.h" - -#ifdef _WIN32 -# include -# include -# include -#else -# include -# include -# include -#endif // _WIN32 - -#include - -namespace Assimp { - - class IOStream; - -// --------------------------------------------------------------------------- -/** @brief CPP-API: Interface to the file system. - * - * Derive an own implementation from this interface to supply custom file handling - * to the importer library. If you implement this interface, you also want to - * supply a custom implementation for IOStream. - * - * @see Importer::SetIOHandler() - */ -class ASSIMP_API IOSystem -#ifndef SWIG - : public Intern::AllocateFromAssimpHeap -#endif -{ -public: - - // ------------------------------------------------------------------- - /** @brief Default constructor. - * - * Create an instance of your derived class and assign it to an - * #Assimp::Importer instance by calling Importer::SetIOHandler(). - */ - IOSystem() AI_NO_EXCEPT; - - // ------------------------------------------------------------------- - /** @brief Virtual destructor. - * - * It is safe to be called from within DLL Assimp, we're constructed - * on Assimp's heap. - */ - virtual ~IOSystem(); - - // ------------------------------------------------------------------- - /** @brief For backward compatibility - * @see Exists(const char*) - */ - AI_FORCE_INLINE bool Exists( const std::string& pFile) const; - - // ------------------------------------------------------------------- - /** @brief Tests for the existence of a file at the given path. - * - * @param pFile Path to the file - * @return true if there is a file with this path, else false. - */ - virtual bool Exists( const char* pFile) const = 0; - - // ------------------------------------------------------------------- - /** @brief Returns the system specific directory separator - * @return System specific directory separator - */ - virtual char getOsSeparator() const = 0; - - // ------------------------------------------------------------------- - /** @brief Open a new file with a given path. - * - * When the access to the file is finished, call Close() to release - * all associated resources (or the virtual dtor of the IOStream). - * - * @param pFile Path to the file - * @param pMode Desired file I/O mode. Required are: "wb", "w", "wt", - * "rb", "r", "rt". - * - * @return New IOStream interface allowing the lib to access - * the underlying file. - * @note When implementing this class to provide custom IO handling, - * you probably have to supply an own implementation of IOStream as well. - */ - virtual IOStream* Open(const char* pFile, - const char* pMode = "rb") = 0; - - // ------------------------------------------------------------------- - /** @brief For backward compatibility - * @see Open(const char*, const char*) - */ - inline IOStream* Open(const std::string& pFile, - const std::string& pMode = std::string("rb")); - - // ------------------------------------------------------------------- - /** @brief Closes the given file and releases all resources - * associated with it. - * @param pFile The file instance previously created by Open(). - */ - virtual void Close( IOStream* pFile) = 0; - - // ------------------------------------------------------------------- - /** @brief Compares two paths and check whether the point to - * identical files. - * - * The dummy implementation of this virtual member performs a - * case-insensitive comparison of the given strings. The default IO - * system implementation uses OS mechanisms to convert relative into - * absolute paths, so the result can be trusted. - * @param one First file - * @param second Second file - * @return true if the paths point to the same file. The file needn't - * be existing, however. - */ - virtual bool ComparePaths (const char* one, - const char* second) const; - - // ------------------------------------------------------------------- - /** @brief For backward compatibility - * @see ComparePaths(const char*, const char*) - */ - inline bool ComparePaths (const std::string& one, - const std::string& second) const; - - // ------------------------------------------------------------------- - /** @brief Pushes a new directory onto the directory stack. - * @param path Path to push onto the stack. - * @return True, when push was successful, false if path is empty. - */ - virtual bool PushDirectory( const std::string &path ); - - // ------------------------------------------------------------------- - /** @brief Returns the top directory from the stack. - * @return The directory on the top of the stack. - * Returns empty when no directory was pushed to the stack. - */ - virtual const std::string &CurrentDirectory() const; - - // ------------------------------------------------------------------- - /** @brief Returns the number of directories stored on the stack. - * @return The number of directories of the stack. - */ - virtual size_t StackSize() const; - - // ------------------------------------------------------------------- - /** @brief Pops the top directory from the stack. - * @return True, when a directory was on the stack. False if no - * directory was on the stack. - */ - virtual bool PopDirectory(); - - // ------------------------------------------------------------------- - /** @brief CReates an new directory at the given path. - * @param path [in] The path to create. - * @return True, when a directory was created. False if the directory - * cannot be created. - */ - virtual bool CreateDirectory( const std::string &path ); - - // ------------------------------------------------------------------- - /** @brief Will change the current directory to the given path. - * @param path [in] The path to change to. - * @return True, when the directory has changed successfully. - */ - virtual bool ChangeDirectory( const std::string &path ); - - virtual bool DeleteFile( const std::string &file ); - -private: - std::vector m_pathStack; -}; - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -IOSystem::IOSystem() AI_NO_EXCEPT -: m_pathStack() { - // empty -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -IOSystem::~IOSystem() { - // empty -} - -// ---------------------------------------------------------------------------- -// For compatibility, the interface of some functions taking a std::string was -// changed to const char* to avoid crashes between binary incompatible STL -// versions. This code her is inlined, so it shouldn't cause any problems. -// ---------------------------------------------------------------------------- - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -IOStream* IOSystem::Open(const std::string& pFile, const std::string& pMode) { - // NOTE: - // For compatibility, interface was changed to const char* to - // avoid crashes between binary incompatible STL versions - return Open(pFile.c_str(),pMode.c_str()); -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::Exists( const std::string& pFile) const { - // NOTE: - // For compatibility, interface was changed to const char* to - // avoid crashes between binary incompatible STL versions - return Exists(pFile.c_str()); -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::ComparePaths (const std::string& one, const std::string& second) const { - // NOTE: - // For compatibility, interface was changed to const char* to - // avoid crashes between binary incompatible STL versions - return ComparePaths(one.c_str(),second.c_str()); -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::PushDirectory( const std::string &path ) { - if ( path.empty() ) { - return false; - } - - m_pathStack.push_back( path ); - - return true; -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -const std::string &IOSystem::CurrentDirectory() const { - if ( m_pathStack.empty() ) { - static const std::string Dummy(""); - return Dummy; - } - return m_pathStack[ m_pathStack.size()-1 ]; -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -size_t IOSystem::StackSize() const { - return m_pathStack.size(); -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::PopDirectory() { - if ( m_pathStack.empty() ) { - return false; - } - - m_pathStack.pop_back(); - - return true; -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::CreateDirectory( const std::string &path ) { - if ( path.empty() ) { - return false; - } - -#ifdef _WIN32 - return 0 != ::_mkdir( path.c_str() ); -#else - return 0 != ::mkdir( path.c_str(), 0777 ); -#endif // _WIN32 -} - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::ChangeDirectory( const std::string &path ) { - if ( path.empty() ) { - return false; - } - -#ifdef _WIN32 - return 0 != ::_chdir( path.c_str() ); -#else - return 0 != ::chdir( path.c_str() ); -#endif // _WIN32 -} - - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE -bool IOSystem::DeleteFile( const std::string &file ) { - if ( file.empty() ) { - return false; - } - const int retCode( ::remove( file.c_str() ) ); - return ( 0 == retCode ); -} -} //!ns Assimp - -#endif //AI_IOSYSTEM_H_INC diff --git a/thirdparty/assimp/include/assimp/Importer.hpp b/thirdparty/assimp/include/assimp/Importer.hpp deleted file mode 100644 index bf449a9a2576..000000000000 --- a/thirdparty/assimp/include/assimp/Importer.hpp +++ /dev/null @@ -1,663 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Importer.hpp - * @brief Defines the C++-API to the Open Asset Import Library. - */ -#pragma once -#ifndef AI_ASSIMP_HPP_INC -#define AI_ASSIMP_HPP_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#ifndef __cplusplus -# error This header requires C++ to be used. Use assimp.h for plain C. -#endif // __cplusplus - -// Public ASSIMP data structures -#include - -namespace Assimp { - // ======================================================================= - // Public interface to Assimp - class Importer; - class IOStream; - class IOSystem; - class ProgressHandler; - - // ======================================================================= - // Plugin development - // - // Include the following headers for the declarations: - // BaseImporter.h - // BaseProcess.h - class BaseImporter; - class BaseProcess; - class SharedPostProcessInfo; - class BatchLoader; - - // ======================================================================= - // Holy stuff, only for members of the high council of the Jedi. - class ImporterPimpl; -} //! namespace Assimp - -#define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff - -struct aiScene; - -// importerdesc.h -struct aiImporterDesc; - -/** @namespace Assimp Assimp's CPP-API and all internal APIs */ -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** CPP-API: The Importer class forms an C++ interface to the functionality of the -* Open Asset Import Library. -* -* Create an object of this class and call ReadFile() to import a file. -* If the import succeeds, the function returns a pointer to the imported data. -* The data remains property of the object, it is intended to be accessed -* read-only. The imported data will be destroyed along with the Importer -* object. If the import fails, ReadFile() returns a NULL pointer. In this -* case you can retrieve a human-readable error description be calling -* GetErrorString(). You can call ReadFile() multiple times with a single Importer -* instance. Actually, constructing Importer objects involves quite many -* allocations and may take some time, so it's better to reuse them as often as -* possible. -* -* If you need the Importer to do custom file handling to access the files, -* implement IOSystem and IOStream and supply an instance of your custom -* IOSystem implementation by calling SetIOHandler() before calling ReadFile(). -* If you do not assign a custion IO handler, a default handler using the -* standard C++ IO logic will be used. -* -* @note One Importer instance is not thread-safe. If you use multiple -* threads for loading, each thread should maintain its own Importer instance. -*/ -class ASSIMP_API Importer { -public: - /** - * @brief The upper limit for hints. - */ - static const unsigned int MaxLenHint = 200; - -public: - - // ------------------------------------------------------------------- - /** Constructor. Creates an empty importer object. - * - * Call ReadFile() to start the import process. The configuration - * property table is initially empty. - */ - Importer(); - - // ------------------------------------------------------------------- - /** Copy constructor. - * - * This copies the configuration properties of another Importer. - * If this Importer owns a scene it won't be copied. - * Call ReadFile() to start the import process. - */ - Importer(const Importer& other)=delete; - - // ------------------------------------------------------------------- - /** Assignment operator has been deleted - */ - Importer &operator=(const Importer &) = delete; - - // ------------------------------------------------------------------- - /** Destructor. The object kept ownership of the imported data, - * which now will be destroyed along with the object. - */ - ~Importer(); - - - // ------------------------------------------------------------------- - /** Registers a new loader. - * - * @param pImp Importer to be added. The Importer instance takes - * ownership of the pointer, so it will be automatically deleted - * with the Importer instance. - * @return AI_SUCCESS if the loader has been added. The registration - * fails if there is already a loader for a specific file extension. - */ - aiReturn RegisterLoader(BaseImporter* pImp); - - // ------------------------------------------------------------------- - /** Unregisters a loader. - * - * @param pImp Importer to be unregistered. - * @return AI_SUCCESS if the loader has been removed. The function - * fails if the loader is currently in use (this could happen - * if the #Importer instance is used by more than one thread) or - * if it has not yet been registered. - */ - aiReturn UnregisterLoader(BaseImporter* pImp); - - // ------------------------------------------------------------------- - /** Registers a new post-process step. - * - * At the moment, there's a small limitation: new post processing - * steps are added to end of the list, or in other words, executed - * last, after all built-in steps. - * @param pImp Post-process step to be added. The Importer instance - * takes ownership of the pointer, so it will be automatically - * deleted with the Importer instance. - * @return AI_SUCCESS if the step has been added correctly. - */ - aiReturn RegisterPPStep(BaseProcess* pImp); - - // ------------------------------------------------------------------- - /** Unregisters a post-process step. - * - * @param pImp Step to be unregistered. - * @return AI_SUCCESS if the step has been removed. The function - * fails if the step is currently in use (this could happen - * if the #Importer instance is used by more than one thread) or - * if it has not yet been registered. - */ - aiReturn UnregisterPPStep(BaseProcess* pImp); - - // ------------------------------------------------------------------- - /** Set an integer configuration property. - * @param szName Name of the property. All supported properties - * are defined in the aiConfig.g header (all constants share the - * prefix AI_CONFIG_XXX and are simple strings). - * @param iValue New value of the property - * @return true if the property was set before. The new value replaces - * the previous value in this case. - * @note Property of different types (float, int, string ..) are kept - * on different stacks, so calling SetPropertyInteger() for a - * floating-point property has no effect - the loader will call - * GetPropertyFloat() to read the property, but it won't be there. - */ - bool SetPropertyInteger(const char* szName, int iValue); - - // ------------------------------------------------------------------- - /** Set a boolean configuration property. Boolean properties - * are stored on the integer stack internally so it's possible - * to set them via #SetPropertyBool and query them with - * #GetPropertyBool and vice versa. - * @see SetPropertyInteger() - */ - bool SetPropertyBool(const char* szName, bool value) { - return SetPropertyInteger(szName,value); - } - - // ------------------------------------------------------------------- - /** Set a floating-point configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyFloat(const char* szName, ai_real fValue); - - // ------------------------------------------------------------------- - /** Set a string configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyString(const char* szName, const std::string& sValue); - - // ------------------------------------------------------------------- - /** Set a matrix configuration property. - * @see SetPropertyInteger() - */ - bool SetPropertyMatrix(const char* szName, const aiMatrix4x4& sValue); - - // ------------------------------------------------------------------- - /** Get a configuration property. - * @param szName Name of the property. All supported properties - * are defined in the aiConfig.g header (all constants share the - * prefix AI_CONFIG_XXX). - * @param iErrorReturn Value that is returned if the property - * is not found. - * @return Current value of the property - * @note Property of different types (float, int, string ..) are kept - * on different lists, so calling SetPropertyInteger() for a - * floating-point property has no effect - the loader will call - * GetPropertyFloat() to read the property, but it won't be there. - */ - int GetPropertyInteger(const char* szName, - int iErrorReturn = 0xffffffff) const; - - // ------------------------------------------------------------------- - /** Get a boolean configuration property. Boolean properties - * are stored on the integer stack internally so it's possible - * to set them via #SetPropertyBool and query them with - * #GetPropertyBool and vice versa. - * @see GetPropertyInteger() - */ - bool GetPropertyBool(const char* szName, bool bErrorReturn = false) const { - return GetPropertyInteger(szName,bErrorReturn)!=0; - } - - // ------------------------------------------------------------------- - /** Get a floating-point configuration property - * @see GetPropertyInteger() - */ - ai_real GetPropertyFloat(const char* szName, - ai_real fErrorReturn = 10e10) const; - - // ------------------------------------------------------------------- - /** Get a string configuration property - * - * The return value remains valid until the property is modified. - * @see GetPropertyInteger() - */ - const std::string GetPropertyString(const char* szName, - const std::string& sErrorReturn = "") const; - - // ------------------------------------------------------------------- - /** Get a matrix configuration property - * - * The return value remains valid until the property is modified. - * @see GetPropertyInteger() - */ - const aiMatrix4x4 GetPropertyMatrix(const char* szName, - const aiMatrix4x4& sErrorReturn = aiMatrix4x4()) const; - - // ------------------------------------------------------------------- - /** Supplies a custom IO handler to the importer to use to open and - * access files. If you need the importer to use custom IO logic to - * access the files, you need to provide a custom implementation of - * IOSystem and IOFile to the importer. Then create an instance of - * your custom IOSystem implementation and supply it by this function. - * - * The Importer takes ownership of the object and will destroy it - * afterwards. The previously assigned handler will be deleted. - * Pass NULL to take again ownership of your IOSystem and reset Assimp - * to use its default implementation. - * - * @param pIOHandler The IO handler to be used in all file accesses - * of the Importer. - */ - void SetIOHandler( IOSystem* pIOHandler); - - // ------------------------------------------------------------------- - /** Retrieves the IO handler that is currently set. - * You can use #IsDefaultIOHandler() to check whether the returned - * interface is the default IO handler provided by ASSIMP. The default - * handler is active as long the application doesn't supply its own - * custom IO handler via #SetIOHandler(). - * @return A valid IOSystem interface, never NULL. - */ - IOSystem* GetIOHandler() const; - - // ------------------------------------------------------------------- - /** Checks whether a default IO handler is active - * A default handler is active as long the application doesn't - * supply its own custom IO handler via #SetIOHandler(). - * @return true by default - */ - bool IsDefaultIOHandler() const; - - // ------------------------------------------------------------------- - /** Supplies a custom progress handler to the importer. This - * interface exposes an #Update() callback, which is called - * more or less periodically (please don't sue us if it - * isn't as periodically as you'd like it to have ...). - * This can be used to implement progress bars and loading - * timeouts. - * @param pHandler Progress callback interface. Pass NULL to - * disable progress reporting. - * @note Progress handlers can be used to abort the loading - * at almost any time.*/ - void SetProgressHandler ( ProgressHandler* pHandler ); - - // ------------------------------------------------------------------- - /** Retrieves the progress handler that is currently set. - * You can use #IsDefaultProgressHandler() to check whether the returned - * interface is the default handler provided by ASSIMP. The default - * handler is active as long the application doesn't supply its own - * custom handler via #SetProgressHandler(). - * @return A valid ProgressHandler interface, never NULL. - */ - ProgressHandler* GetProgressHandler() const; - - // ------------------------------------------------------------------- - /** Checks whether a default progress handler is active - * A default handler is active as long the application doesn't - * supply its own custom progress handler via #SetProgressHandler(). - * @return true by default - */ - bool IsDefaultProgressHandler() const; - - // ------------------------------------------------------------------- - /** @brief Check whether a given set of post-processing flags - * is supported. - * - * Some flags are mutually exclusive, others are probably - * not available because your excluded them from your - * Assimp builds. Calling this function is recommended if - * you're unsure. - * - * @param pFlags Bitwise combination of the aiPostProcess flags. - * @return true if this flag combination is fine. - */ - bool ValidateFlags(unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Reads the given file and returns its contents if successful. - * - * If the call succeeds, the contents of the file are returned as a - * pointer to an aiScene object. The returned data is intended to be - * read-only, the importer object keeps ownership of the data and will - * destroy it upon destruction. If the import fails, NULL is returned. - * A human-readable error description can be retrieved by calling - * GetErrorString(). The previous scene will be deleted during this call. - * @param pFile Path and filename to the file to be imported. - * @param pFlags Optional post processing steps to be executed after - * a successful import. Provide a bitwise combination of the - * #aiPostProcessSteps flags. If you wish to inspect the imported - * scene first in order to fine-tune your post-processing setup, - * consider to use #ApplyPostProcessing(). - * @return A pointer to the imported data, NULL if the import failed. - * The pointer to the scene remains in possession of the Importer - * instance. Use GetOrphanedScene() to take ownership of it. - * - * @note Assimp is able to determine the file format of a file - * automatically. - */ - const aiScene* ReadFile( - const char* pFile, - unsigned int pFlags); - - // ------------------------------------------------------------------- - /** Reads the given file from a memory buffer and returns its - * contents if successful. - * - * If the call succeeds, the contents of the file are returned as a - * pointer to an aiScene object. The returned data is intended to be - * read-only, the importer object keeps ownership of the data and will - * destroy it upon destruction. If the import fails, NULL is returned. - * A human-readable error description can be retrieved by calling - * GetErrorString(). The previous scene will be deleted during this call. - * Calling this method doesn't affect the active IOSystem. - * @param pBuffer Pointer to the file data - * @param pLength Length of pBuffer, in bytes - * @param pFlags Optional post processing steps to be executed after - * a successful import. Provide a bitwise combination of the - * #aiPostProcessSteps flags. If you wish to inspect the imported - * scene first in order to fine-tune your post-processing setup, - * consider to use #ApplyPostProcessing(). - * @param pHint An additional hint to the library. If this is a non - * empty string, the library looks for a loader to support - * the file extension specified by pHint and passes the file to - * the first matching loader. If this loader is unable to completely - * the request, the library continues and tries to determine the - * file format on its own, a task that may or may not be successful. - * Check the return value, and you'll know ... - * @return A pointer to the imported data, NULL if the import failed. - * The pointer to the scene remains in possession of the Importer - * instance. Use GetOrphanedScene() to take ownership of it. - * - * @note This is a straightforward way to decode models from memory - * buffers, but it doesn't handle model formats that spread their - * data across multiple files or even directories. Examples include - * OBJ or MD3, which outsource parts of their material info into - * external scripts. If you need full functionality, provide - * a custom IOSystem to make Assimp find these files and use - * the regular ReadFile() API. - */ - const aiScene* ReadFileFromMemory( - const void* pBuffer, - size_t pLength, - unsigned int pFlags, - const char* pHint = ""); - - // ------------------------------------------------------------------- - /** Apply post-processing to an already-imported scene. - * - * This is strictly equivalent to calling #ReadFile() with the same - * flags. However, you can use this separate function to inspect - * the imported scene first to fine-tune your post-processing setup. - * @param pFlags Provide a bitwise combination of the - * #aiPostProcessSteps flags. - * @return A pointer to the post-processed data. This is still the - * same as the pointer returned by #ReadFile(). However, if - * post-processing fails, the scene could now be NULL. - * That's quite a rare case, post processing steps are not really - * designed to 'fail'. To be exact, the #aiProcess_ValidateDS - * flag is currently the only post processing step which can actually - * cause the scene to be reset to NULL. - * - * @note The method does nothing if no scene is currently bound - * to the #Importer instance. */ - const aiScene* ApplyPostProcessing(unsigned int pFlags); - - const aiScene* ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ); - - // ------------------------------------------------------------------- - /** @brief Reads the given file and returns its contents if successful. - * - * This function is provided for backward compatibility. - * See the const char* version for detailed docs. - * @see ReadFile(const char*, pFlags) */ - const aiScene* ReadFile( - const std::string& pFile, - unsigned int pFlags); - - // ------------------------------------------------------------------- - /** Frees the current scene. - * - * The function does nothing if no scene has previously been - * read via ReadFile(). FreeScene() is called automatically by the - * destructor and ReadFile() itself. */ - void FreeScene( ); - - // ------------------------------------------------------------------- - /** Returns an error description of an error that occurred in ReadFile(). - * - * Returns an empty string if no error occurred. - * @return A description of the last error, an empty string if no - * error occurred. The string is never NULL. - * - * @note The returned function remains valid until one of the - * following methods is called: #ReadFile(), #FreeScene(). */ - const char* GetErrorString() const; - - // ------------------------------------------------------------------- - /** Returns the scene loaded by the last successful call to ReadFile() - * - * @return Current scene or NULL if there is currently no scene loaded */ - const aiScene* GetScene() const; - - // ------------------------------------------------------------------- - /** Returns the scene loaded by the last successful call to ReadFile() - * and releases the scene from the ownership of the Importer - * instance. The application is now responsible for deleting the - * scene. Any further calls to GetScene() or GetOrphanedScene() - * will return NULL - until a new scene has been loaded via ReadFile(). - * - * @return Current scene or NULL if there is currently no scene loaded - * @note Use this method with maximal caution, and only if you have to. - * By design, aiScene's are exclusively maintained, allocated and - * deallocated by Assimp and no one else. The reasoning behind this - * is the golden rule that deallocations should always be done - * by the module that did the original allocation because heaps - * are not necessarily shared. GetOrphanedScene() enforces you - * to delete the returned scene by yourself, but this will only - * be fine if and only if you're using the same heap as assimp. - * On Windows, it's typically fine provided everything is linked - * against the multithreaded-dll version of the runtime library. - * It will work as well for static linkage with Assimp.*/ - aiScene* GetOrphanedScene(); - - // ------------------------------------------------------------------- - /** Returns whether a given file extension is supported by ASSIMP. - * - * @param szExtension Extension to be checked. - * Must include a trailing dot '.'. Example: ".3ds", ".md3". - * Cases-insensitive. - * @return true if the extension is supported, false otherwise */ - bool IsExtensionSupported(const char* szExtension) const; - - // ------------------------------------------------------------------- - /** @brief Returns whether a given file extension is supported by ASSIMP. - * - * This function is provided for backward compatibility. - * See the const char* version for detailed and up-to-date docs. - * @see IsExtensionSupported(const char*) */ - inline bool IsExtensionSupported(const std::string& szExtension) const; - - // ------------------------------------------------------------------- - /** Get a full list of all file extensions supported by ASSIMP. - * - * If a file extension is contained in the list this does of course not - * mean that ASSIMP is able to load all files with this extension --- - * it simply means there is an importer loaded which claims to handle - * files with this file extension. - * @param szOut String to receive the extension list. - * Format of the list: "*.3ds;*.obj;*.dae". This is useful for - * use with the WinAPI call GetOpenFileName(Ex). */ - void GetExtensionList(aiString& szOut) const; - - // ------------------------------------------------------------------- - /** @brief Get a full list of all file extensions supported by ASSIMP. - * - * This function is provided for backward compatibility. - * See the aiString version for detailed and up-to-date docs. - * @see GetExtensionList(aiString&)*/ - inline void GetExtensionList(std::string& szOut) const; - - // ------------------------------------------------------------------- - /** Get the number of importers currently registered with Assimp. */ - size_t GetImporterCount() const; - - // ------------------------------------------------------------------- - /** Get meta data for the importer corresponding to a specific index.. - * - * For the declaration of #aiImporterDesc, include . - * @param index Index to query, must be within [0,GetImporterCount()) - * @return Importer meta data structure, NULL if the index does not - * exist or if the importer doesn't offer meta information ( - * importers may do this at the cost of being hated by their peers).*/ - const aiImporterDesc* GetImporterInfo(size_t index) const; - - // ------------------------------------------------------------------- - /** Find the importer corresponding to a specific index. - * - * @param index Index to query, must be within [0,GetImporterCount()) - * @return Importer instance. NULL if the index does not - * exist. */ - BaseImporter* GetImporter(size_t index) const; - - // ------------------------------------------------------------------- - /** Find the importer corresponding to a specific file extension. - * - * This is quite similar to #IsExtensionSupported except a - * BaseImporter instance is returned. - * @param szExtension Extension to check for. The following formats - * are recognized (BAH being the file extension): "BAH" (comparison - * is case-insensitive), ".bah", "*.bah" (wild card and dot - * characters at the beginning of the extension are skipped). - * @return NULL if no importer is found*/ - BaseImporter* GetImporter (const char* szExtension) const; - - // ------------------------------------------------------------------- - /** Find the importer index corresponding to a specific file extension. - * - * @param szExtension Extension to check for. The following formats - * are recognized (BAH being the file extension): "BAH" (comparison - * is case-insensitive), ".bah", "*.bah" (wild card and dot - * characters at the beginning of the extension are skipped). - * @return (size_t)-1 if no importer is found */ - size_t GetImporterIndex (const char* szExtension) const; - - // ------------------------------------------------------------------- - /** Returns the storage allocated by ASSIMP to hold the scene data - * in memory. - * - * This refers to the currently loaded file, see #ReadFile(). - * @param in Data structure to be filled. - * @note The returned memory statistics refer to the actual - * size of the use data of the aiScene. Heap-related overhead - * is (naturally) not included.*/ - void GetMemoryRequirements(aiMemoryInfo& in) const; - - // ------------------------------------------------------------------- - /** Enables "extra verbose" mode. - * - * 'Extra verbose' means the data structure is validated after *every* - * single post processing step to make sure everyone modifies the data - * structure in a well-defined manner. This is a debug feature and not - * intended for use in production environments. */ - void SetExtraVerbose(bool bDo); - - // ------------------------------------------------------------------- - /** Private, do not use. */ - ImporterPimpl* Pimpl() { return pimpl; } - const ImporterPimpl* Pimpl() const { return pimpl; } - -protected: - - // Just because we don't want you to know how we're hacking around. - ImporterPimpl* pimpl; -}; //! class Importer - - -// ---------------------------------------------------------------------------- -// For compatibility, the interface of some functions taking a std::string was -// changed to const char* to avoid crashes between binary incompatible STL -// versions. This code her is inlined, so it shouldn't cause any problems. -// ---------------------------------------------------------------------------- - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE const aiScene* Importer::ReadFile( const std::string& pFile,unsigned int pFlags){ - return ReadFile(pFile.c_str(),pFlags); -} -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE void Importer::GetExtensionList(std::string& szOut) const { - aiString s; - GetExtensionList(s); - szOut = s.data; -} -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE bool Importer::IsExtensionSupported(const std::string& szExtension) const { - return IsExtensionSupported(szExtension.c_str()); -} - -} // !namespace Assimp - -#endif // AI_ASSIMP_HPP_INC diff --git a/thirdparty/assimp/include/assimp/LineSplitter.h b/thirdparty/assimp/include/assimp/LineSplitter.h deleted file mode 100644 index 6c1097bb6d88..000000000000 --- a/thirdparty/assimp/include/assimp/LineSplitter.h +++ /dev/null @@ -1,289 +0,0 @@ -/* -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 LineSplitter.h - * @brief LineSplitter, a helper class to iterate through all lines - * of a file easily. Works with StreamReader. - */ -#pragma once -#ifndef INCLUDED_LINE_SPLITTER_H -#define INCLUDED_LINE_SPLITTER_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -/** Usage: -@code -for(LineSplitter splitter(stream);splitter;++splitter) { - - if (*splitter == "hi!") { - ... - } - else if (splitter->substr(0,5) == "hello") { - ... - // access the third token in the line (tokens are space-separated) - if (strtol(splitter[2]) > 5) { .. } - } - - std::cout << "Current line is: " << splitter.get_index() << std::endl; -} -@endcode -*/ -// ------------------------------------------------------------------------------------------------ -class LineSplitter { -public: - typedef size_t line_idx; - - // ----------------------------------------- - /** construct from existing stream reader - note: trim is *always* assumed true if skyp_empty_lines==true - */ - LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true); - - ~LineSplitter(); - - // ----------------------------------------- - /** pseudo-iterator increment */ - LineSplitter& operator++(); - - // ----------------------------------------- - LineSplitter& operator++(int); - - // ----------------------------------------- - /** get a pointer to the beginning of a particular token */ - const char* operator[] (size_t idx) const; - - // ----------------------------------------- - /** extract the start positions of N tokens from the current line*/ - template - void get_tokens(const char* (&tokens)[N]) const; - - // ----------------------------------------- - /** member access */ - const std::string* operator -> () const; - - std::string operator* () const; - - // ----------------------------------------- - /** boolean context */ - operator bool() const; - - // ----------------------------------------- - /** line indices are zero-based, empty lines are included */ - operator line_idx() const; - - line_idx get_index() const; - - // ----------------------------------------- - /** access the underlying stream object */ - StreamReaderLE& get_stream(); - - // ----------------------------------------- - /** !strcmp((*this)->substr(0,strlen(check)),check) */ - bool match_start(const char* check); - - // ----------------------------------------- - /** swallow the next call to ++, return the previous value. */ - void swallow_next_increment(); - - LineSplitter( const LineSplitter & ) = delete; - LineSplitter(LineSplitter &&) = delete; - LineSplitter &operator = ( const LineSplitter & ) = delete; - -private: - line_idx mIdx; - std::string mCur; - StreamReaderLE& mStream; - bool mSwallow, mSkip_empty_lines, mTrim; -}; - -AI_FORCE_INLINE -LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) -: mIdx(0) -, mCur() -, mStream(stream) -, mSwallow() -, mSkip_empty_lines(skip_empty_lines) -, mTrim(trim) { - mCur.reserve(1024); - operator++(); - mIdx = 0; -} - -AI_FORCE_INLINE -LineSplitter::~LineSplitter() { - // empty -} - -AI_FORCE_INLINE -LineSplitter& LineSplitter::operator++() { - if (mSwallow) { - mSwallow = false; - return *this; - } - - if (!*this) { - throw std::logic_error("End of file, no more lines to be retrieved."); - } - - char s; - mCur.clear(); - while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) { - if (s == '\n' || s == '\r') { - if (mSkip_empty_lines) { - while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\r' || s == '\n')); - if (mStream.GetRemainingSize()) { - mStream.IncPtr(-1); - } - } else { - // skip both potential line terminators but don't read past this line. - if (mStream.GetRemainingSize() && (s == '\r' && mStream.GetI1() != '\n')) { - mStream.IncPtr(-1); - } - if (mTrim) { - while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t')); - if (mStream.GetRemainingSize()) { - mStream.IncPtr(-1); - } - } - } - break; - } - mCur += s; - } - ++mIdx; - - return *this; -} - -AI_FORCE_INLINE -LineSplitter &LineSplitter::operator++(int) { - return ++(*this); -} - -AI_FORCE_INLINE -const char *LineSplitter::operator[] (size_t idx) const { - const char* s = operator->()->c_str(); - - SkipSpaces(&s); - for (size_t i = 0; i < idx; ++i) { - - for (; !IsSpace(*s); ++s) { - if (IsLineEnd(*s)) { - throw std::range_error("Token index out of range, EOL reached"); - } - } - SkipSpaces(&s); - } - return s; -} - -template -AI_FORCE_INLINE -void LineSplitter::get_tokens(const char* (&tokens)[N]) const { - const char* s = operator->()->c_str(); - - SkipSpaces(&s); - for (size_t i = 0; i < N; ++i) { - if (IsLineEnd(*s)) { - throw std::range_error("Token count out of range, EOL reached"); - } - tokens[i] = s; - - for (; *s && !IsSpace(*s); ++s); - SkipSpaces(&s); - } -} - -AI_FORCE_INLINE -const std::string* LineSplitter::operator -> () const { - return &mCur; -} - -AI_FORCE_INLINE -std::string LineSplitter::operator* () const { - return mCur; -} - -AI_FORCE_INLINE -LineSplitter::operator bool() const { - return mStream.GetRemainingSize() > 0; -} - -AI_FORCE_INLINE -LineSplitter::operator line_idx() const { - return mIdx; -} - -AI_FORCE_INLINE -LineSplitter::line_idx LineSplitter::get_index() const { - return mIdx; -} - -AI_FORCE_INLINE -StreamReaderLE &LineSplitter::get_stream() { - return mStream; -} - -AI_FORCE_INLINE -bool LineSplitter::match_start(const char* check) { - const size_t len = ::strlen(check); - - return len <= mCur.length() && std::equal(check, check + len, mCur.begin()); -} - -AI_FORCE_INLINE -void LineSplitter::swallow_next_increment() { - mSwallow = true; -} - -} // Namespace Assimp - -#endif // INCLUDED_LINE_SPLITTER_H diff --git a/thirdparty/assimp/include/assimp/LogAux.h b/thirdparty/assimp/include/assimp/LogAux.h deleted file mode 100644 index bcead78dd3d1..000000000000 --- a/thirdparty/assimp/include/assimp/LogAux.h +++ /dev/null @@ -1,136 +0,0 @@ -/* -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 LogAux.h - * @brief Common logging usage patterns for importer implementations - */ -#pragma once -#ifndef INCLUDED_AI_LOGAUX_H -#define INCLUDED_AI_LOGAUX_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -namespace Assimp { - -template -class LogFunctions { -public: - // ------------------------------------------------------------------------------------------------ - static void ThrowException(const std::string& msg) - { - throw DeadlyImportError(Prefix()+msg); - } - - // ------------------------------------------------------------------------------------------------ - static void LogWarn(const Formatter::format& message) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_WARN(Prefix()+(std::string)message); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogError(const Formatter::format& message) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_ERROR(Prefix()+(std::string)message); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogInfo(const Formatter::format& message) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO(Prefix()+(std::string)message); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogDebug(const Formatter::format& message) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_DEBUG(Prefix()+(std::string)message); - } - } - - // https://sourceforge.net/tracker/?func=detail&atid=1067632&aid=3358562&group_id=226462 -#if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - - // ------------------------------------------------------------------------------------------------ - static void LogWarn (const char* message) { - if (!DefaultLogger::isNullLogger()) { - LogWarn(Formatter::format(message)); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogError (const char* message) { - if (!DefaultLogger::isNullLogger()) { - LogError(Formatter::format(message)); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogInfo (const char* message) { - if (!DefaultLogger::isNullLogger()) { - LogInfo(Formatter::format(message)); - } - } - - // ------------------------------------------------------------------------------------------------ - static void LogDebug (const char* message) { - if (!DefaultLogger::isNullLogger()) { - LogDebug(Formatter::format(message)); - } - } - -#endif - -private: - static const char* Prefix(); - -}; -} // ! Assimp - -#endif diff --git a/thirdparty/assimp/include/assimp/LogStream.hpp b/thirdparty/assimp/include/assimp/LogStream.hpp deleted file mode 100644 index d0281e2d026c..000000000000 --- a/thirdparty/assimp/include/assimp/LogStream.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -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 LogStream.hpp - * @brief Abstract base class 'LogStream', representing an output log stream. - */ -#ifndef INCLUDED_AI_LOGSTREAM_H -#define INCLUDED_AI_LOGSTREAM_H - -#include "types.h" - -namespace Assimp { - -class IOSystem; - -// ------------------------------------------------------------------------------------ -/** @brief CPP-API: Abstract interface for log stream implementations. - * - * Several default implementations are provided, see #aiDefaultLogStream for more - * details. Writing your own implementation of LogStream is just necessary if these - * are not enough for your purpose. */ -class ASSIMP_API LogStream -#ifndef SWIG - : public Intern::AllocateFromAssimpHeap -#endif -{ -protected: - /** @brief Default constructor */ - LogStream() AI_NO_EXCEPT; - -public: - /** @brief Virtual destructor */ - virtual ~LogStream(); - - // ------------------------------------------------------------------- - /** @brief Overwrite this for your own output methods - * - * Log messages *may* consist of multiple lines and you shouldn't - * expect a consistent formatting. If you want custom formatting - * (e.g. generate HTML), supply a custom instance of Logger to - * #DefaultLogger:set(). Usually you can *expect* that a log message - * is exactly one line and terminated with a single \n character. - * @param message Message to be written */ - virtual void write(const char* message) = 0; - - // ------------------------------------------------------------------- - /** @brief Creates a default log stream - * @param streams Type of the default stream - * @param name For aiDefaultLogStream_FILE: name of the output file - * @param io For aiDefaultLogStream_FILE: IOSystem to be used to open the output - * file. Pass NULL for the default implementation. - * @return New LogStream instance. */ - static LogStream* createDefaultStream(aiDefaultLogStream stream, - const char* name = "AssimpLog.txt", - IOSystem* io = nullptr ); - -}; // !class LogStream - -inline -LogStream::LogStream() AI_NO_EXCEPT { - // empty -} - -inline -LogStream::~LogStream() { - // empty -} - -// ------------------------------------------------------------------------------------ -} // Namespace Assimp - -#endif diff --git a/thirdparty/assimp/include/assimp/Logger.hpp b/thirdparty/assimp/include/assimp/Logger.hpp deleted file mode 100644 index 89cade6c336e..000000000000 --- a/thirdparty/assimp/include/assimp/Logger.hpp +++ /dev/null @@ -1,305 +0,0 @@ -/* -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 Logger.hpp - * @brief Abstract base class 'Logger', base of the logging system. - */ -#ifndef INCLUDED_AI_LOGGER_H -#define INCLUDED_AI_LOGGER_H - -#include -#include - -namespace Assimp { - -class LogStream; - -// Maximum length of a log message. Longer messages are rejected. -#define MAX_LOG_MESSAGE_LENGTH 1024u - -// ---------------------------------------------------------------------------------- -/** @brief CPP-API: Abstract interface for logger implementations. - * Assimp provides a default implementation and uses it for almost all - * logging stuff ('DefaultLogger'). This class defines just basic logging - * behavior and is not of interest for you. Instead, take a look at #DefaultLogger. */ -class ASSIMP_API Logger -#ifndef SWIG - : public Intern::AllocateFromAssimpHeap -#endif -{ -public: - - // ---------------------------------------------------------------------- - /** @enum LogSeverity - * @brief Log severity to describe the granularity of logging. - */ - enum LogSeverity { - NORMAL, //!< Normal granularity of logging - VERBOSE //!< Debug infos will be logged, too - }; - - // ---------------------------------------------------------------------- - /** @enum ErrorSeverity - * @brief Description for severity of a log message. - * - * Every LogStream has a bitwise combination of these flags. - * A LogStream doesn't receive any messages of a specific type - * if it doesn't specify the corresponding ErrorSeverity flag. - */ - enum ErrorSeverity { - Debugging = 1, //!< Debug log message - Info = 2, //!< Info log message - Warn = 4, //!< Warn log message - Err = 8 //!< Error log message - }; - -public: - - /** @brief Virtual destructor */ - virtual ~Logger(); - - // ---------------------------------------------------------------------- - /** @brief Writes a debug message - * @param message Debug message*/ - void debug(const char* message); - void debug(const std::string &message); - - // ---------------------------------------------------------------------- - /** @brief Writes a info message - * @param message Info message*/ - void info(const char* message); - void info(const std::string &message); - - // ---------------------------------------------------------------------- - /** @brief Writes a warning message - * @param message Warn message*/ - void warn(const char* message); - void warn(const std::string &message); - - // ---------------------------------------------------------------------- - /** @brief Writes an error message - * @param message Error message*/ - void error(const char* message); - void error(const std::string &message); - - // ---------------------------------------------------------------------- - /** @brief Set a new log severity. - * @param log_severity New severity for logging*/ - void setLogSeverity(LogSeverity log_severity); - - // ---------------------------------------------------------------------- - /** @brief Get the current log severity*/ - LogSeverity getLogSeverity() const; - - // ---------------------------------------------------------------------- - /** @brief Attach a new log-stream - * - * The logger takes ownership of the stream and is responsible - * for its destruction (which is done using ::delete when the logger - * itself is destroyed). Call detachStream to detach a stream and to - * gain ownership of it again. - * @param pStream Log-stream to attach - * @param severity Message filter, specified which types of log - * messages are dispatched to the stream. Provide a bitwise - * combination of the ErrorSeverity flags. - * @return true if the stream has been attached, false otherwise.*/ - virtual bool attachStream(LogStream *pStream, - unsigned int severity = Debugging | Err | Warn | Info) = 0; - - // ---------------------------------------------------------------------- - /** @brief Detach a still attached stream from the logger (or - * modify the filter flags bits) - * @param pStream Log-stream instance for detaching - * @param severity Provide a bitwise combination of the ErrorSeverity - * flags. This value is &~ed with the current flags of the stream, - * if the result is 0 the stream is detached from the Logger and - * the caller retakes the possession of the stream. - * @return true if the stream has been detached, false otherwise.*/ - virtual bool detatchStream(LogStream *pStream, - unsigned int severity = Debugging | Err | Warn | Info) = 0; - -protected: - /** - * Default constructor - */ - Logger() AI_NO_EXCEPT; - - /** - * Construction with a given log severity - */ - explicit Logger(LogSeverity severity); - - // ---------------------------------------------------------------------- - /** - * @brief Called as a request to write a specific debug message - * @param message Debug message. Never longer than - * MAX_LOG_MESSAGE_LENGTH characters (excluding the '0'). - * @note The message string is only valid until the scope of - * the function is left. - */ - virtual void OnDebug(const char* message)= 0; - - // ---------------------------------------------------------------------- - /** - * @brief Called as a request to write a specific info message - * @param message Info message. Never longer than - * MAX_LOG_MESSAGE_LENGTH characters (ecxluding the '0'). - * @note The message string is only valid until the scope of - * the function is left. - */ - virtual void OnInfo(const char* message) = 0; - - // ---------------------------------------------------------------------- - /** - * @brief Called as a request to write a specific warn message - * @param message Warn message. Never longer than - * MAX_LOG_MESSAGE_LENGTH characters (exluding the '0'). - * @note The message string is only valid until the scope of - * the function is left. - */ - virtual void OnWarn(const char* essage) = 0; - - // ---------------------------------------------------------------------- - /** - * @brief Called as a request to write a specific error message - * @param message Error message. Never longer than - * MAX_LOG_MESSAGE_LENGTH characters (exluding the '0'). - * @note The message string is only valid until the scope of - * the function is left. - */ - virtual void OnError(const char* message) = 0; - -protected: - LogSeverity m_Severity; -}; - -// ---------------------------------------------------------------------------------- -// Default constructor -inline -Logger::Logger() AI_NO_EXCEPT -: m_Severity(NORMAL) { - // empty -} - -// ---------------------------------------------------------------------------------- -// Virtual destructor -inline -Logger::~Logger() { - // empty -} - -// ---------------------------------------------------------------------------------- -// Construction with given logging severity -inline -Logger::Logger(LogSeverity severity) -: m_Severity(severity) { - // empty -} - -// ---------------------------------------------------------------------------------- -// Log severity setter -inline -void Logger::setLogSeverity(LogSeverity log_severity){ - m_Severity = log_severity; -} - -// ---------------------------------------------------------------------------------- -// Log severity getter -inline -Logger::LogSeverity Logger::getLogSeverity() const { - return m_Severity; -} - -// ---------------------------------------------------------------------------------- -inline -void Logger::debug(const std::string &message) { - return debug(message.c_str()); -} - -// ---------------------------------------------------------------------------------- -inline -void Logger::error(const std::string &message) { - return error(message.c_str()); -} - -// ---------------------------------------------------------------------------------- -inline -void Logger::warn(const std::string &message) { - return warn(message.c_str()); -} - -// ---------------------------------------------------------------------------------- -inline -void Logger::info(const std::string &message) { - return info(message.c_str()); -} - -// ------------------------------------------------------------------------------------------------ -#define ASSIMP_LOG_WARN_F(string,...)\ - DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__)) - -#define ASSIMP_LOG_ERROR_F(string,...)\ - DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__)) - -#define ASSIMP_LOG_DEBUG_F(string,...)\ - DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__)) - -#define ASSIMP_LOG_INFO_F(string,...)\ - DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__)) - - -#define ASSIMP_LOG_WARN(string)\ - DefaultLogger::get()->warn(string) - -#define ASSIMP_LOG_ERROR(string)\ - DefaultLogger::get()->error(string) - -#define ASSIMP_LOG_DEBUG(string)\ - DefaultLogger::get()->debug(string) - -#define ASSIMP_LOG_INFO(string)\ - DefaultLogger::get()->info(string) - - -} // Namespace Assimp - -#endif // !! INCLUDED_AI_LOGGER_H diff --git a/thirdparty/assimp/include/assimp/MathFunctions.h b/thirdparty/assimp/include/assimp/MathFunctions.h deleted file mode 100644 index b6c5872a72ad..000000000000 --- a/thirdparty/assimp/include/assimp/MathFunctions.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2016, 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. ---------------------------------------------------------------------------- -*/ - -#pragma once - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -/** @file MathFunctions.h -* @brief Implementation of math utility functions. - * -*/ - -#include - -namespace Assimp { -namespace Math { - -// TODO: use binary GCD for unsigned integers .... -template < typename IntegerType > -inline -IntegerType gcd( IntegerType a, IntegerType b ) { - const IntegerType zero = (IntegerType)0; - while ( true ) { - if ( a == zero ) - return b; - b %= a; - - if ( b == zero ) - return a; - a %= b; - } -} - -template < typename IntegerType > -inline -IntegerType lcm( IntegerType a, IntegerType b ) { - const IntegerType t = gcd (a,b); - if (!t) - return t; - return a / t * b; -} - -template -inline -T getEpsilon() { - return std::numeric_limits::epsilon(); -} - -} -} diff --git a/thirdparty/assimp/include/assimp/MemoryIOWrapper.h b/thirdparty/assimp/include/assimp/MemoryIOWrapper.h deleted file mode 100644 index 5598d4fc5f9a..000000000000 --- a/thirdparty/assimp/include/assimp/MemoryIOWrapper.h +++ /dev/null @@ -1,250 +0,0 @@ -/* -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 MemoryIOWrapper.h - * Handy IOStream/IOSystem implemetation to read directly from a memory buffer */ -#pragma once -#ifndef AI_MEMORYIOSTREAM_H_INC -#define AI_MEMORYIOSTREAM_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include - -namespace Assimp { - -#define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$" -#define AI_MEMORYIO_MAGIC_FILENAME_LENGTH 17 - -// ---------------------------------------------------------------------------------- -/** Implementation of IOStream to read directly from a memory buffer */ -// ---------------------------------------------------------------------------------- -class MemoryIOStream : public IOStream { -public: - MemoryIOStream (const uint8_t* buff, size_t len, bool own = false) - : buffer (buff) - , length(len) - , pos((size_t)0) - , own(own) { - // empty - } - - ~MemoryIOStream () { - if(own) { - delete[] buffer; - } - } - - // ------------------------------------------------------------------- - // Read from stream - size_t Read(void* pvBuffer, size_t pSize, size_t pCount) { - ai_assert(nullptr != pvBuffer); - ai_assert(0 != pSize); - - const size_t cnt = std::min( pCount, (length-pos) / pSize); - const size_t ofs = pSize * cnt; - - ::memcpy(pvBuffer,buffer+pos,ofs); - pos += ofs; - - return cnt; - } - - // ------------------------------------------------------------------- - // Write to stream - size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/,size_t /*pCount*/) { - ai_assert(false); // won't be needed - return 0; - } - - // ------------------------------------------------------------------- - // Seek specific position - aiReturn Seek(size_t pOffset, aiOrigin pOrigin) { - if (aiOrigin_SET == pOrigin) { - if (pOffset > length) { - return AI_FAILURE; - } - pos = pOffset; - } else if (aiOrigin_END == pOrigin) { - if (pOffset > length) { - return AI_FAILURE; - } - pos = length-pOffset; - } else { - if (pOffset+pos > length) { - return AI_FAILURE; - } - pos += pOffset; - } - return AI_SUCCESS; - } - - // ------------------------------------------------------------------- - // Get current seek position - size_t Tell() const { - return pos; - } - - // ------------------------------------------------------------------- - // Get size of file - size_t FileSize() const { - return length; - } - - // ------------------------------------------------------------------- - // Flush file contents - void Flush() { - ai_assert(false); // won't be needed - } - -private: - const uint8_t* buffer; - size_t length,pos; - bool own; -}; - -// --------------------------------------------------------------------------- -/** Dummy IO system to read from a memory buffer */ -class MemoryIOSystem : public IOSystem { -public: - /** Constructor. */ - MemoryIOSystem(const uint8_t* buff, size_t len, IOSystem* io) - : buffer(buff) - , length(len) - , existing_io(io) - , created_streams() { - // empty - } - - /** Destructor. */ - ~MemoryIOSystem() { - } - - // ------------------------------------------------------------------- - /** Tests for the existence of a file at the given path. */ - bool Exists(const char* pFile) const override { - if (0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) { - return true; - } - return existing_io ? existing_io->Exists(pFile) : false; - } - - // ------------------------------------------------------------------- - /** Returns the directory separator. */ - char getOsSeparator() const override { - return existing_io ? existing_io->getOsSeparator() - : '/'; // why not? it doesn't care - } - - // ------------------------------------------------------------------- - /** Open a new file with a given path. */ - IOStream* Open(const char* pFile, const char* pMode = "rb") override { - if ( 0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) { - created_streams.emplace_back(new MemoryIOStream(buffer, length)); - return created_streams.back(); - } - return existing_io ? existing_io->Open(pFile, pMode) : NULL; - } - - // ------------------------------------------------------------------- - /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* pFile) override { - auto it = std::find(created_streams.begin(), created_streams.end(), pFile); - if (it != created_streams.end()) { - delete pFile; - created_streams.erase(it); - } else if (existing_io) { - existing_io->Close(pFile); - } - } - - // ------------------------------------------------------------------- - /** Compare two paths */ - bool ComparePaths(const char* one, const char* second) const override { - return existing_io ? existing_io->ComparePaths(one, second) : false; - } - - bool PushDirectory( const std::string &path ) override { - return existing_io ? existing_io->PushDirectory(path) : false; - } - - const std::string &CurrentDirectory() const override { - static std::string empty; - return existing_io ? existing_io->CurrentDirectory() : empty; - } - - size_t StackSize() const override { - return existing_io ? existing_io->StackSize() : 0; - } - - bool PopDirectory() override { - return existing_io ? existing_io->PopDirectory() : false; - } - - bool CreateDirectory( const std::string &path ) override { - return existing_io ? existing_io->CreateDirectory(path) : false; - } - - bool ChangeDirectory( const std::string &path ) override { - return existing_io ? existing_io->ChangeDirectory(path) : false; - } - - bool DeleteFile( const std::string &file ) override { - return existing_io ? existing_io->DeleteFile(file) : false; - } - -private: - const uint8_t* buffer; - size_t length; - IOSystem* existing_io; - std::vector created_streams; -}; - -} // end namespace Assimp - -#endif diff --git a/thirdparty/assimp/include/assimp/NullLogger.hpp b/thirdparty/assimp/include/assimp/NullLogger.hpp deleted file mode 100644 index c45d01bd48e3..000000000000 --- a/thirdparty/assimp/include/assimp/NullLogger.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -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 NullLogger.hpp - * @brief Dummy logger -*/ - -#ifndef INCLUDED_AI_NULLLOGGER_H -#define INCLUDED_AI_NULLLOGGER_H - -#include "Logger.hpp" - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @brief CPP-API: Empty logging implementation. - * - * Does nothing! Used by default if the application hasn't requested a - * custom logger via #DefaultLogger::set() or #DefaultLogger::create(); */ -class ASSIMP_API NullLogger - : public Logger { - -public: - - /** @brief Logs a debug message */ - void OnDebug(const char* message) { - (void)message; //this avoids compiler warnings - } - - /** @brief Logs an info message */ - void OnInfo(const char* message) { - (void)message; //this avoids compiler warnings - } - - /** @brief Logs a warning message */ - void OnWarn(const char* message) { - (void)message; //this avoids compiler warnings - } - - /** @brief Logs an error message */ - void OnError(const char* message) { - (void)message; //this avoids compiler warnings - } - - /** @brief Detach a still attached stream from logger */ - bool attachStream(LogStream *pStream, unsigned int severity) { - (void)pStream; (void)severity; //this avoids compiler warnings - return false; - } - - /** @brief Detach a still attached stream from logger */ - bool detatchStream(LogStream *pStream, unsigned int severity) { - (void)pStream; (void)severity; //this avoids compiler warnings - return false; - } - -private: -}; -} -#endif // !! AI_NULLLOGGER_H_INCLUDED diff --git a/thirdparty/assimp/include/assimp/ParsingUtils.h b/thirdparty/assimp/include/assimp/ParsingUtils.h deleted file mode 100644 index 30256012460e..000000000000 --- a/thirdparty/assimp/include/assimp/ParsingUtils.h +++ /dev/null @@ -1,264 +0,0 @@ -/* -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 ParsingUtils.h - * @brief Defines helper functions for text parsing - */ -#pragma once -#ifndef AI_PARSING_UTILS_H_INC -#define AI_PARSING_UTILS_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -namespace Assimp { - -// NOTE: the functions below are mostly intended as replacement for -// std::upper, std::lower, std::isupper, std::islower, std::isspace. -// we don't bother of locales. We don't want them. We want reliable -// (i.e. identical) results across all locales. - -// The functions below accept any character type, but know only -// about ASCII. However, UTF-32 is the only safe ASCII superset to -// use since it doesn't have multi-byte sequences. - -static const unsigned int BufferSize = 4096; - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -char_t ToLower( char_t in ) { - return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -char_t ToUpper( char_t in) { - return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool IsUpper( char_t in) { - return (in >= (char_t)'A' && in <= (char_t)'Z'); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool IsLower( char_t in) { - return (in >= (char_t)'a' && in <= (char_t)'z'); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool IsSpace( char_t in) { - return (in == (char_t)' ' || in == (char_t)'\t'); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool IsLineEnd( char_t in) { - return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f'); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool IsSpaceOrNewLine( char_t in) { - return IsSpace(in) || IsLineEnd(in); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipSpaces( const char_t* in, const char_t** out) { - while( *in == ( char_t )' ' || *in == ( char_t )'\t' ) { - ++in; - } - *out = in; - return !IsLineEnd(*in); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipSpaces( const char_t** inout) { - return SkipSpaces(*inout,inout); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipLine( const char_t* in, const char_t** out) { - while( *in != ( char_t )'\r' && *in != ( char_t )'\n' && *in != ( char_t )'\0' ) { - ++in; - } - - // files are opened in binary mode. Ergo there are both NL and CR - while( *in == ( char_t )'\r' || *in == ( char_t )'\n' ) { - ++in; - } - *out = in; - return *in != (char_t)'\0'; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipLine( const char_t** inout) { - return SkipLine(*inout,inout); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out) { - while( *in == ( char_t )' ' || *in == ( char_t )'\t' || *in == ( char_t )'\r' || *in == ( char_t )'\n' ) { - ++in; - } - *out = in; - return *in != '\0'; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool SkipSpacesAndLineEnd( const char_t** inout) { - return SkipSpacesAndLineEnd(*inout,inout); -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) { - if( ( char_t )'\0' == *buffer ) { - return false; - } - - char* _out = out; - char* const end = _out + BufferSize; - while( !IsLineEnd( *buffer ) && _out < end ) { - *_out++ = *buffer++; - } - *_out = (char_t)'\0'; - - while( IsLineEnd( *buffer ) && '\0' != *buffer ) { - ++buffer; - } - - return true; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE bool IsNumeric( char_t in) { - return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in; -} - -// --------------------------------------------------------------------------------- -template -AI_FORCE_INLINE -bool TokenMatch(char_t*& in, const char* token, unsigned int len) -{ - if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) { - if (in[len] != '\0') { - in += len+1; - } else { - // If EOF after the token make sure we don't go past end of buffer - in += len; - } - return true; - } - - return false; -} -// --------------------------------------------------------------------------------- -/** @brief Case-ignoring version of TokenMatch - * @param in Input - * @param token Token to check for - * @param len Number of characters to check - */ -AI_FORCE_INLINE -bool TokenMatchI(const char*& in, const char* token, unsigned int len) { - if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) { - in += len+1; - return true; - } - return false; -} - -// --------------------------------------------------------------------------------- -AI_FORCE_INLINE -void SkipToken(const char*& in) { - SkipSpaces(&in); - while ( !IsSpaceOrNewLine( *in ) ) { - ++in; - } -} - -// --------------------------------------------------------------------------------- -AI_FORCE_INLINE -std::string GetNextToken(const char*& in) { - SkipSpacesAndLineEnd(&in); - const char* cur = in; - while ( !IsSpaceOrNewLine( *in ) ) { - ++in; - } - return std::string(cur,(size_t)(in-cur)); -} - -// --------------------------------------------------------------------------------- - -} // ! namespace Assimp - -#endif // ! AI_PARSING_UTILS_H_INC diff --git a/thirdparty/assimp/include/assimp/Profiler.h b/thirdparty/assimp/include/assimp/Profiler.h deleted file mode 100644 index 624029be9980..000000000000 --- a/thirdparty/assimp/include/assimp/Profiler.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -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 Profiler.h - * @brief Utility to measure the respective runtime of each import step - */ -#pragma once -#ifndef AI_INCLUDED_PROFILER_H -#define AI_INCLUDED_PROFILER_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include - -namespace Assimp { -namespace Profiling { - -using namespace Formatter; - -// ------------------------------------------------------------------------------------------------ -/** Simple wrapper around boost::timer to simplify reporting. Timings are automatically - * dumped to the log file. - */ -class Profiler { -public: - Profiler() { - // empty - } - - - /** Start a named timer */ - void BeginRegion(const std::string& region) { - regions[region] = std::chrono::system_clock::now(); - ASSIMP_LOG_DEBUG((format("START `"),region,"`")); - } - - - /** End a specific named timer and write its end time to the log */ - void EndRegion(const std::string& region) { - RegionMap::const_iterator it = regions.find(region); - if (it == regions.end()) { - return; - } - - std::chrono::duration elapsedSeconds = std::chrono::system_clock::now() - regions[region]; - ASSIMP_LOG_DEBUG((format("END `"),region,"`, dt= ", elapsedSeconds.count()," s")); - } - -private: - typedef std::map> RegionMap; - RegionMap regions; -}; - -} -} - -#endif // AI_INCLUDED_PROFILER_H - diff --git a/thirdparty/assimp/include/assimp/ProgressHandler.hpp b/thirdparty/assimp/include/assimp/ProgressHandler.hpp deleted file mode 100644 index 8991a6461808..000000000000 --- a/thirdparty/assimp/include/assimp/ProgressHandler.hpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -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 ProgressHandler.hpp - * @brief Abstract base class 'ProgressHandler'. - */ -#pragma once -#ifndef AI_PROGRESSHANDLER_H_INC -#define AI_PROGRESSHANDLER_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------------ -/** @brief CPP-API: Abstract interface for custom progress report receivers. - * - * Each #Importer instance maintains its own #ProgressHandler. The default - * implementation provided by Assimp doesn't do anything at all. */ -class ASSIMP_API ProgressHandler -#ifndef SWIG - : public Intern::AllocateFromAssimpHeap -#endif -{ -protected: - /// @brief Default constructor - ProgressHandler () AI_NO_EXCEPT { - // empty - } - -public: - /// @brief Virtual destructor. - virtual ~ProgressHandler () { - } - - // ------------------------------------------------------------------- - /** @brief Progress callback. - * @param percentage An estimate of the current loading progress, - * in percent. Or -1.f if such an estimate is not available. - * - * There are restriction on what you may do from within your - * implementation of this method: no exceptions may be thrown and no - * non-const #Importer methods may be called. It is - * not generally possible to predict the number of callbacks - * fired during a single import. - * - * @return Return false to abort loading at the next possible - * occasion (loaders and Assimp are generally allowed to perform - * all needed cleanup tasks prior to returning control to the - * caller). If the loading is aborted, #Importer::ReadFile() - * returns always NULL. - * */ - virtual bool Update(float percentage = -1.f) = 0; - - // ------------------------------------------------------------------- - /** @brief Progress callback for file loading steps - * @param numberOfSteps The number of total post-processing - * steps - * @param currentStep The index of the current post-processing - * step that will run, or equal to numberOfSteps if all of - * them has finished. This number is always strictly monotone - * increasing, although not necessarily linearly. - * - * @note This is currently only used at the start and the end - * of the file parsing. - * */ - virtual void UpdateFileRead(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { - float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; - Update( f * 0.5f ); - } - - // ------------------------------------------------------------------- - /** @brief Progress callback for post-processing steps - * @param numberOfSteps The number of total post-processing - * steps - * @param currentStep The index of the current post-processing - * step that will run, or equal to numberOfSteps if all of - * them has finished. This number is always strictly monotone - * increasing, although not necessarily linearly. - * */ - virtual void UpdatePostProcess(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { - float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; - Update( f * 0.5f + 0.5f ); - } - - - // ------------------------------------------------------------------- - /** @brief Progress callback for export steps. - * @param numberOfSteps The number of total processing - * steps - * @param currentStep The index of the current post-processing - * step that will run, or equal to numberOfSteps if all of - * them has finished. This number is always strictly monotone - * increasing, although not necessarily linearly. - * */ - virtual void UpdateFileWrite(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { - float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; - Update(f * 0.5f); - } -}; // !class ProgressHandler - -// ------------------------------------------------------------------------------------ - -} // Namespace Assimp - -#endif // AI_PROGRESSHANDLER_H_INC diff --git a/thirdparty/assimp/include/assimp/RemoveComments.h b/thirdparty/assimp/include/assimp/RemoveComments.h deleted file mode 100644 index f129420535c6..000000000000 --- a/thirdparty/assimp/include/assimp/RemoveComments.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -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 Declares a helper class, "CommentRemover", which can be - * used to remove comments (single and multi line) from a text file. - */ -#pragma once -#ifndef AI_REMOVE_COMMENTS_H_INC -#define AI_REMOVE_COMMENTS_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** \brief Helper class to remove single and multi line comments from a file - * - * Some mesh formats like MD5 have comments that are quite similar - * to those in C or C++ so this code has been moved to a separate - * module. - */ -class ASSIMP_API CommentRemover { - // class cannot be instanced - CommentRemover() {} - -public: - - //! Remove single-line comments. The end of a line is - //! expected to be either NL or CR or NLCR. - //! \param szComment The start sequence of the comment, e.g. "//" - //! \param szBuffer Buffer to work with - //! \param chReplacement Character to be used as replacement - //! for commented lines. By default this is ' ' - static void RemoveLineComments(const char* szComment, - char* szBuffer, char chReplacement = ' '); - - //! Remove multi-line comments. The end of a line is - //! expected to be either NL or CR or NLCR. Multi-line comments - //! may not be nested (as in C). - //! \param szCommentStart The start sequence of the comment, e.g. "/*" - //! \param szCommentEnd The end sequence of the comment, e.g. "*/" - //! \param szBuffer Buffer to work with - //! \param chReplacement Character to be used as replacement - //! for commented lines. By default this is ' ' - static void RemoveMultiLineComments(const char* szCommentStart, - const char* szCommentEnd,char* szBuffer, - char chReplacement = ' '); -}; -} // ! Assimp - -#endif // !! AI_REMOVE_COMMENTS_H_INC diff --git a/thirdparty/assimp/include/assimp/SGSpatialSort.h b/thirdparty/assimp/include/assimp/SGSpatialSort.h deleted file mode 100644 index fdb5ce817459..000000000000 --- a/thirdparty/assimp/include/assimp/SGSpatialSort.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -/** Small helper classes to optimize finding vertices close to a given location - */ -#pragma once -#ifndef AI_D3DSSPATIALSORT_H_INC -#define AI_D3DSSPATIALSORT_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** Specialized version of SpatialSort to support smoothing groups - * This is used in by the 3DS, ASE and LWO loaders. 3DS and ASE share their - * normal computation code in SmoothingGroups.inl, the LWO loader has its own - * implementation to handle all details of its file format correctly. - */ -// ---------------------------------------------------------------------------------- -class ASSIMP_API SGSpatialSort -{ -public: - - SGSpatialSort(); - - // ------------------------------------------------------------------- - /** Construction from a given face array, handling smoothing groups - * properly - */ - explicit SGSpatialSort(const std::vector& vPositions); - - // ------------------------------------------------------------------- - /** Add a vertex to the spatial sort - * @param vPosition Vertex position to be added - * @param index Index of the vrtex - * @param smoothingGroup SmoothingGroup for this vertex - */ - void Add(const aiVector3D& vPosition, unsigned int index, - unsigned int smoothingGroup); - - // ------------------------------------------------------------------- - /** Prepare the spatial sorter for use. This step runs in O(logn) - */ - void Prepare(); - - /** Destructor */ - ~SGSpatialSort(); - - // ------------------------------------------------------------------- - /** Returns an iterator for all positions close to the given position. - * @param pPosition The position to look for vertices. - * @param pSG Only included vertices with at least one shared smooth group - * @param pRadius Maximal distance from the position a vertex may have - * to be counted in. - * @param poResults The container to store the indices of the found - * positions. Will be emptied by the call so it may contain anything. - * @param exactMatch Specifies whether smoothing groups are bit masks - * (false) or integral values (true). In the latter case, a vertex - * cannot belong to more than one smoothing group. - * @return An iterator to iterate over all vertices in the given area. - */ - // ------------------------------------------------------------------- - void FindPositions( const aiVector3D& pPosition, uint32_t pSG, - float pRadius, std::vector& poResults, - bool exactMatch = false) const; - -protected: - /** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */ - aiVector3D mPlaneNormal; - - // ------------------------------------------------------------------- - /** An entry in a spatially sorted position array. Consists of a - * vertex index, its position and its pre-calculated distance from - * the reference plane */ - // ------------------------------------------------------------------- - struct Entry { - unsigned int mIndex; ///< The vertex referred by this entry - aiVector3D mPosition; ///< Position - uint32_t mSmoothGroups; - float mDistance; ///< Distance of this vertex to the sorting plane - - Entry() AI_NO_EXCEPT - : mIndex(0) - , mPosition() - , mSmoothGroups(0) - , mDistance(0.0f) { - // empty - } - - Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG) - : mIndex( pIndex) - , mPosition( pPosition) - , mSmoothGroups(pSG) - , mDistance( pDistance) { - // empty - } - - bool operator < (const Entry& e) const { - return mDistance < e.mDistance; - } - }; - - // all positions, sorted by distance to the sorting plane - std::vector mPositions; -}; - -} // end of namespace Assimp - -#endif // AI_SPATIALSORT_H_INC diff --git a/thirdparty/assimp/include/assimp/SceneCombiner.h b/thirdparty/assimp/include/assimp/SceneCombiner.h deleted file mode 100644 index 0683c1e052e7..000000000000 --- a/thirdparty/assimp/include/assimp/SceneCombiner.h +++ /dev/null @@ -1,410 +0,0 @@ -/* -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 Declares a helper class, "SceneCombiner" providing various - * utilities to merge scenes. - */ -#pragma once -#ifndef AI_SCENE_COMBINER_H_INC -#define AI_SCENE_COMBINER_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -struct aiScene; -struct aiNode; -struct aiMaterial; -struct aiTexture; -struct aiCamera; -struct aiLight; -struct aiMetadata; -struct aiBone; -struct aiMesh; -struct aiAnimMesh; -struct aiAnimation; -struct aiNodeAnim; -struct aiMeshMorphAnim; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** \brief Helper data structure for SceneCombiner. - * - * Describes to which node a scene must be attached to. - */ -struct AttachmentInfo -{ - AttachmentInfo() - : scene (NULL) - , attachToNode (NULL) - {} - - AttachmentInfo(aiScene* _scene, aiNode* _attachToNode) - : scene (_scene) - , attachToNode (_attachToNode) - {} - - aiScene* scene; - aiNode* attachToNode; -}; - -// --------------------------------------------------------------------------- -struct NodeAttachmentInfo -{ - NodeAttachmentInfo() - : node (NULL) - , attachToNode (NULL) - , resolved (false) - , src_idx (SIZE_MAX) - {} - - NodeAttachmentInfo(aiNode* _scene, aiNode* _attachToNode,size_t idx) - : node (_scene) - , attachToNode (_attachToNode) - , resolved (false) - , src_idx (idx) - {} - - aiNode* node; - aiNode* attachToNode; - bool resolved; - size_t src_idx; -}; - -// --------------------------------------------------------------------------- -/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES - * Generate unique names for all named scene items - */ -#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES 0x1 - -/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES - * Generate unique names for materials, too. - * This is not absolutely required to pass the validation. - */ -#define AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES 0x2 - -/** @def AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY - * Use deep copies of duplicate scenes - */ -#define AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY 0x4 - -/** @def AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS - * If attachment nodes are not found in the given master scene, - * search the other imported scenes for them in an any order. - */ -#define AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS 0x8 - -/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY - * Can be combined with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES. - * Unique names are generated, but only if this is absolutely - * required to avoid name conflicts. - */ -#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10 - -typedef std::pair BoneSrcIndex; - -// --------------------------------------------------------------------------- -/** @brief Helper data structure for SceneCombiner::MergeBones. - */ -struct BoneWithHash : public std::pair { - std::vector pSrcBones; -}; - -// --------------------------------------------------------------------------- -/** @brief Utility for SceneCombiner - */ -struct SceneHelper -{ - SceneHelper () - : scene (NULL) - , idlen (0) - { - id[0] = 0; - } - - explicit SceneHelper (aiScene* _scene) - : scene (_scene) - , idlen (0) - { - id[0] = 0; - } - - AI_FORCE_INLINE aiScene* operator-> () const - { - return scene; - } - - // scene we're working on - aiScene* scene; - - // prefix to be added to all identifiers in the scene ... - char id [32]; - - // and its strlen() - unsigned int idlen; - - // hash table to quickly check whether a name is contained in the scene - std::set hashes; -}; - -// --------------------------------------------------------------------------- -/** \brief Static helper class providing various utilities to merge two - * scenes. It is intended as internal utility and NOT for use by - * applications. - * - * The class is currently being used by various postprocessing steps - * and loaders (ie. LWS). - */ -class ASSIMP_API SceneCombiner { - // class cannot be instanced - SceneCombiner() { - // empty - } - - ~SceneCombiner() { - // empty - } - -public: - // ------------------------------------------------------------------- - /** Merges two or more scenes. - * - * @param dest Receives a pointer to the destination scene. If the - * pointer doesn't point to NULL when the function is called, the - * existing scene is cleared and refilled. - * @param src Non-empty list of scenes to be merged. The function - * deletes the input scenes afterwards. There may be duplicate scenes. - * @param flags Combination of the AI_INT_MERGE_SCENE flags defined above - */ - static void MergeScenes(aiScene** dest,std::vector& src, - unsigned int flags = 0); - - // ------------------------------------------------------------------- - /** Merges two or more scenes and attaches all scenes to a specific - * position in the node graph of the master scene. - * - * @param dest Receives a pointer to the destination scene. If the - * pointer doesn't point to NULL when the function is called, the - * existing scene is cleared and refilled. - * @param master Master scene. It will be deleted afterwards. All - * other scenes will be inserted in its node graph. - * @param src Non-empty list of scenes to be merged along with their - * corresponding attachment points in the master scene. The function - * deletes the input scenes afterwards. There may be duplicate scenes. - * @param flags Combination of the AI_INT_MERGE_SCENE flags defined above - */ - static void MergeScenes(aiScene** dest, aiScene* master, - std::vector& src, - unsigned int flags = 0); - - // ------------------------------------------------------------------- - /** Merges two or more meshes - * - * The meshes should have equal vertex formats. Only components - * that are provided by ALL meshes will be present in the output mesh. - * An exception is made for VColors - they are set to black. The - * meshes should have the same material indices, too. The output - * material index is always the material index of the first mesh. - * - * @param dest Destination mesh. Must be empty. - * @param flags Currently no parameters - * @param begin First mesh to be processed - * @param end Points to the mesh after the last mesh to be processed - */ - static void MergeMeshes(aiMesh** dest,unsigned int flags, - std::vector::const_iterator begin, - std::vector::const_iterator end); - - // ------------------------------------------------------------------- - /** Merges two or more bones - * - * @param out Mesh to receive the output bone list - * @param flags Currently no parameters - * @param begin First mesh to be processed - * @param end Points to the mesh after the last mesh to be processed - */ - static void MergeBones(aiMesh* out,std::vector::const_iterator it, - std::vector::const_iterator end); - - // ------------------------------------------------------------------- - /** Merges two or more materials - * - * The materials should be complementary as much as possible. In case - * of a property present in different materials, the first occurrence - * is used. - * - * @param dest Destination material. Must be empty. - * @param begin First material to be processed - * @param end Points to the material after the last material to be processed - */ - static void MergeMaterials(aiMaterial** dest, - std::vector::const_iterator begin, - std::vector::const_iterator end); - - // ------------------------------------------------------------------- - /** Builds a list of uniquely named bones in a mesh list - * - * @param asBones Receives the output list - * @param it First mesh to be processed - * @param end Last mesh to be processed - */ - static void BuildUniqueBoneList(std::list& asBones, - std::vector::const_iterator it, - std::vector::const_iterator end); - - // ------------------------------------------------------------------- - /** Add a name prefix to all nodes in a scene. - * - * @param Current node. This function is called recursively. - * @param prefix Prefix to be added to all nodes - * @param len STring length - */ - static void AddNodePrefixes(aiNode* node, const char* prefix, - unsigned int len); - - // ------------------------------------------------------------------- - /** Add an offset to all mesh indices in a node graph - * - * @param Current node. This function is called recursively. - * @param offset Offset to be added to all mesh indices - */ - static void OffsetNodeMeshIndices (aiNode* node, unsigned int offset); - - // ------------------------------------------------------------------- - /** Attach a list of node graphs to well-defined nodes in a master - * graph. This is a helper for MergeScenes() - * - * @param master Master scene - * @param srcList List of source scenes along with their attachment - * points. If an attachment point is NULL (or does not exist in - * the master graph), a scene is attached to the root of the master - * graph (as an additional child node) - * @duplicates List of duplicates. If elem[n] == n the scene is not - * a duplicate. Otherwise elem[n] links scene n to its first occurrence. - */ - static void AttachToGraph ( aiScene* master, - std::vector& srcList); - - static void AttachToGraph (aiNode* attach, - std::vector& srcList); - - - // ------------------------------------------------------------------- - /** Get a deep copy of a scene - * - * @param dest Receives a pointer to the destination scene - * @param src Source scene - remains unmodified. - */ - static void CopyScene(aiScene** dest,const aiScene* source,bool allocate = true); - - - // ------------------------------------------------------------------- - /** Get a flat copy of a scene - * - * Only the first hierarchy layer is copied. All pointer members of - * aiScene are shared by source and destination scene. If the - * pointer doesn't point to NULL when the function is called, the - * existing scene is cleared and refilled. - * @param dest Receives a pointer to the destination scene - * @param src Source scene - remains unmodified. - */ - static void CopySceneFlat(aiScene** dest,const aiScene* source); - - - // ------------------------------------------------------------------- - /** Get a deep copy of a mesh - * - * @param dest Receives a pointer to the destination mesh - * @param src Source mesh - remains unmodified. - */ - static void Copy (aiMesh** dest, const aiMesh* src); - - // similar to Copy(): - static void Copy (aiAnimMesh** dest, const aiAnimMesh* src); - static void Copy (aiMaterial** dest, const aiMaterial* src); - static void Copy (aiTexture** dest, const aiTexture* src); - static void Copy (aiAnimation** dest, const aiAnimation* src); - static void Copy (aiCamera** dest, const aiCamera* src); - static void Copy (aiBone** dest, const aiBone* src); - static void Copy (aiLight** dest, const aiLight* src); - static void Copy (aiNodeAnim** dest, const aiNodeAnim* src); - static void Copy (aiMeshMorphAnim** dest, const aiMeshMorphAnim* src); - static void Copy (aiMetadata** dest, const aiMetadata* src); - - // recursive, of course - static void Copy (aiNode** dest, const aiNode* src); - - -private: - - // ------------------------------------------------------------------- - // Same as AddNodePrefixes, but with an additional check - static void AddNodePrefixesChecked(aiNode* node, const char* prefix, - unsigned int len, - std::vector& input, - unsigned int cur); - - // ------------------------------------------------------------------- - // Add node identifiers to a hashing set - static void AddNodeHashes(aiNode* node, std::set& hashes); - - - // ------------------------------------------------------------------- - // Search for duplicate names - static bool FindNameMatch(const aiString& name, - std::vector& input, unsigned int cur); -}; - -} - -#endif // !! AI_SCENE_COMBINER_H_INC diff --git a/thirdparty/assimp/include/assimp/SkeletonMeshBuilder.h b/thirdparty/assimp/include/assimp/SkeletonMeshBuilder.h deleted file mode 100644 index ad979a33fa3f..000000000000 --- a/thirdparty/assimp/include/assimp/SkeletonMeshBuilder.h +++ /dev/null @@ -1,130 +0,0 @@ -/** Helper class to construct a dummy mesh for file formats containing only motion data */ - -/* -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 SkeletonMeshBuilder.h - * Declares SkeletonMeshBuilder, a tiny utility to build dummy meshes - * for animation skeletons. - */ - -#pragma once -#ifndef AI_SKELETONMESHBUILDER_H_INC -#define AI_SKELETONMESHBUILDER_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -struct aiMaterial; -struct aiScene; -struct aiNode; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** - * This little helper class constructs a dummy mesh for a given scene - * the resembles the node hierarchy. This is useful for file formats - * that don't carry any mesh data but only animation data. - */ -class ASSIMP_API SkeletonMeshBuilder -{ -public: - - // ------------------------------------------------------------------- - /** The constructor processes the given scene and adds a mesh there. - * - * Does nothing if the scene already has mesh data. - * @param pScene The scene for which a skeleton mesh should be constructed. - * @param root The node to start with. NULL is the scene root - * @param bKnobsOnly Set this to true if you don't want the connectors - * between the knobs representing the nodes. - */ - SkeletonMeshBuilder( aiScene* pScene, aiNode* root = NULL, - bool bKnobsOnly = false); - -protected: - - // ------------------------------------------------------------------- - /** Recursively builds a simple mesh representation for the given node - * and also creates a joint for the node that affects this part of - * the mesh. - * @param pNode The node to build geometry for. - */ - void CreateGeometry( const aiNode* pNode); - - // ------------------------------------------------------------------- - /** Creates the mesh from the internally accumulated stuff and returns it. - */ - aiMesh* CreateMesh(); - - // ------------------------------------------------------------------- - /** Creates a dummy material and returns it. */ - aiMaterial* CreateMaterial(); - -protected: - /** space to assemble the mesh data: points */ - std::vector mVertices; - - /** faces */ - struct Face - { - unsigned int mIndices[3]; - Face(); - Face( unsigned int p0, unsigned int p1, unsigned int p2) - { mIndices[0] = p0; mIndices[1] = p1; mIndices[2] = p2; } - }; - std::vector mFaces; - - /** bones */ - std::vector mBones; - - bool mKnobsOnly; -}; - -} // end of namespace Assimp - -#endif // AI_SKELETONMESHBUILDER_H_INC diff --git a/thirdparty/assimp/include/assimp/SmoothingGroups.h b/thirdparty/assimp/include/assimp/SmoothingGroups.h deleted file mode 100644 index c1a93947f160..000000000000 --- a/thirdparty/assimp/include/assimp/SmoothingGroups.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -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 Defines the helper data structures for importing 3DS files. -http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */ - -#pragma once -#ifndef AI_SMOOTHINGGROUPS_H_INC -#define AI_SMOOTHINGGROUPS_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -#include -#include - -// --------------------------------------------------------------------------- -/** Helper structure representing a face with smoothing groups assigned */ -struct FaceWithSmoothingGroup { - FaceWithSmoothingGroup() AI_NO_EXCEPT - : mIndices() - , iSmoothGroup(0) { - // in debug builds set all indices to a common magic value -#ifdef ASSIMP_BUILD_DEBUG - this->mIndices[0] = 0xffffffff; - this->mIndices[1] = 0xffffffff; - this->mIndices[2] = 0xffffffff; -#endif - } - - - //! Indices. .3ds is using uint16. However, after - //! an unique vertex set has been generated, - //! individual index values might exceed 2^16 - uint32_t mIndices[3]; - - //! specifies to which smoothing group the face belongs to - uint32_t iSmoothGroup; -}; - -// --------------------------------------------------------------------------- -/** Helper structure representing a mesh whose faces have smoothing - groups assigned. This allows us to reuse the code for normal computations - from smoothings groups for several loaders (3DS, ASE). All of them - use face structures which inherit from #FaceWithSmoothingGroup, - but as they add extra members and need to be copied by value we - need to use a template here. - */ -template -struct MeshWithSmoothingGroups -{ - //! Vertex positions - std::vector mPositions; - - //! Face lists - std::vector mFaces; - - //! List of normal vectors - std::vector mNormals; -}; - -// --------------------------------------------------------------------------- -/** Computes normal vectors for the mesh - */ -template -void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups& sMesh); - - -// include implementations -#include "SmoothingGroups.inl" - -#endif // !! AI_SMOOTHINGGROUPS_H_INC diff --git a/thirdparty/assimp/include/assimp/SmoothingGroups.inl b/thirdparty/assimp/include/assimp/SmoothingGroups.inl deleted file mode 100644 index 37ea083dbeed..000000000000 --- a/thirdparty/assimp/include/assimp/SmoothingGroups.inl +++ /dev/null @@ -1,141 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Generation of normal vectors basing on smoothing groups */ - -#pragma once -#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED -#define AI_SMOOTHINGGROUPS_INL_INCLUDED - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -template -void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups& sMesh) -{ - // First generate face normals - sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D()); - for( unsigned int a = 0; a < sMesh.mFaces.size(); a++) - { - T& face = sMesh.mFaces[a]; - - aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]]; - aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]]; - aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]]; - - aiVector3D pDelta1 = *pV2 - *pV1; - aiVector3D pDelta2 = *pV3 - *pV1; - aiVector3D vNor = pDelta1 ^ pDelta2; - - for (unsigned int c = 0; c < 3;++c) - sMesh.mNormals[face.mIndices[c]] = vNor; - } - - // calculate the position bounds so we have a reliable epsilon to check position differences against - aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f); - for( unsigned int a = 0; a < sMesh.mPositions.size(); a++) - { - minVec.x = std::min( minVec.x, sMesh.mPositions[a].x); - minVec.y = std::min( minVec.y, sMesh.mPositions[a].y); - minVec.z = std::min( minVec.z, sMesh.mPositions[a].z); - maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x); - maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y); - maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z); - } - const float posEpsilon = (maxVec - minVec).Length() * 1e-5f; - std::vector avNormals; - avNormals.resize(sMesh.mNormals.size()); - - // now generate the spatial sort tree - SGSpatialSort sSort; - for( typename std::vector::iterator i = sMesh.mFaces.begin(); - i != sMesh.mFaces.end();++i) - { - for (unsigned int c = 0; c < 3;++c) - sSort.Add(sMesh.mPositions[(*i).mIndices[c]],(*i).mIndices[c],(*i).iSmoothGroup); - } - sSort.Prepare(); - - std::vector vertexDone(sMesh.mPositions.size(),false); - for( typename std::vector::iterator i = sMesh.mFaces.begin(); - i != sMesh.mFaces.end();++i) - { - std::vector poResult; - for (unsigned int c = 0; c < 3;++c) - { - unsigned int idx = (*i).mIndices[c]; - if (vertexDone[idx])continue; - - sSort.FindPositions(sMesh.mPositions[idx],(*i).iSmoothGroup, - posEpsilon,poResult); - - aiVector3D vNormals; - for (std::vector::const_iterator - a = poResult.begin(); - a != poResult.end();++a) - { - vNormals += sMesh.mNormals[(*a)]; - } - vNormals.NormalizeSafe(); - - // write back into all affected normals - for (std::vector::const_iterator - a = poResult.begin(); - a != poResult.end();++a) - { - idx = *a; - avNormals [idx] = vNormals; - vertexDone[idx] = true; - } - } - } - sMesh.mNormals = avNormals; -} - -#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED diff --git a/thirdparty/assimp/include/assimp/SpatialSort.h b/thirdparty/assimp/include/assimp/SpatialSort.h deleted file mode 100644 index 9f9354315085..000000000000 --- a/thirdparty/assimp/include/assimp/SpatialSort.h +++ /dev/null @@ -1,179 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -/** Small helper classes to optimise finding vertizes close to a given location */ -#pragma once -#ifndef AI_SPATIALSORT_H_INC -#define AI_SPATIALSORT_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -/** A little helper class to quickly find all vertices in the epsilon environment of a given - * position. Construct an instance with an array of positions. The class stores the given positions - * by their indices and sorts them by their distance to an arbitrary chosen plane. - * You can then query the instance for all vertices close to a given position in an average O(log n) - * time, with O(n) worst case complexity when all vertices lay on the plane. The plane is chosen - * so that it avoids common planes in usual data sets. */ -// ------------------------------------------------------------------------------------------------ -class ASSIMP_API SpatialSort -{ -public: - - SpatialSort(); - - // ------------------------------------------------------------------------------------ - /** Constructs a spatially sorted representation from the given position array. - * Supply the positions in its layout in memory, the class will only refer to them - * by index. - * @param pPositions Pointer to the first position vector of the array. - * @param pNumPositions Number of vectors to expect in that array. - * @param pElementOffset Offset in bytes from the beginning of one vector in memory - * to the beginning of the next vector. */ - SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset); - - /** Destructor */ - ~SpatialSort(); - -public: - - // ------------------------------------------------------------------------------------ - /** Sets the input data for the SpatialSort. This replaces existing data, if any. - * The new data receives new indices in ascending order. - * - * @param pPositions Pointer to the first position vector of the array. - * @param pNumPositions Number of vectors to expect in that array. - * @param pElementOffset Offset in bytes from the beginning of one vector in memory - * to the beginning of the next vector. - * @param pFinalize Specifies whether the SpatialSort's internal representation - * is finalized after the new data has been added. Finalization is - * required in order to use #FindPosition() or #GenerateMappingTable(). - * If you don't finalize yet, you can use #Append() to add data from - * other sources.*/ - void Fill( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize = true); - - - // ------------------------------------------------------------------------------------ - /** Same as #Fill(), except the method appends to existing data in the #SpatialSort. */ - void Append( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize = true); - - - // ------------------------------------------------------------------------------------ - /** Finalize the spatial hash data structure. This can be useful after - * multiple calls to #Append() with the pFinalize parameter set to false. - * This is finally required before one of #FindPositions() and #GenerateMappingTable() - * can be called to query the spatial sort.*/ - void Finalize(); - - // ------------------------------------------------------------------------------------ - /** Returns an iterator for all positions close to the given position. - * @param pPosition The position to look for vertices. - * @param pRadius Maximal distance from the position a vertex may have to be counted in. - * @param poResults The container to store the indices of the found positions. - * Will be emptied by the call so it may contain anything. - * @return An iterator to iterate over all vertices in the given area.*/ - void FindPositions( const aiVector3D& pPosition, ai_real pRadius, - std::vector& poResults) const; - - // ------------------------------------------------------------------------------------ - /** Fills an array with indices of all positions identical to the given position. In - * opposite to FindPositions(), not an epsilon is used but a (very low) tolerance of - * four floating-point units. - * @param pPosition The position to look for vertices. - * @param poResults The container to store the indices of the found positions. - * Will be emptied by the call so it may contain anything.*/ - void FindIdenticalPositions( const aiVector3D& pPosition, - std::vector& poResults) const; - - // ------------------------------------------------------------------------------------ - /** Compute a table that maps each vertex ID referring to a spatially close - * enough position to the same output ID. Output IDs are assigned in ascending order - * from 0...n. - * @param fill Will be filled with numPositions entries. - * @param pRadius Maximal distance from the position a vertex may have to - * be counted in. - * @return Number of unique vertices (n). */ - unsigned int GenerateMappingTable(std::vector& fill, - ai_real pRadius) const; - -protected: - /** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */ - aiVector3D mPlaneNormal; - - /** An entry in a spatially sorted position array. Consists of a vertex index, - * its position and its pre-calculated distance from the reference plane */ - struct Entry { - unsigned int mIndex; ///< The vertex referred by this entry - aiVector3D mPosition; ///< Position - ai_real mDistance; ///< Distance of this vertex to the sorting plane - - Entry() AI_NO_EXCEPT - : mIndex( 999999999 ), mPosition(), mDistance( 99999. ) { - // empty - } - Entry( unsigned int pIndex, const aiVector3D& pPosition, ai_real pDistance) - : mIndex( pIndex), mPosition( pPosition), mDistance( pDistance) { - // empty - } - - bool operator < (const Entry& e) const { return mDistance < e.mDistance; } - }; - - // all positions, sorted by distance to the sorting plane - std::vector mPositions; -}; - -} // end of namespace Assimp - -#endif // AI_SPATIALSORT_H_INC diff --git a/thirdparty/assimp/include/assimp/StandardShapes.h b/thirdparty/assimp/include/assimp/StandardShapes.h deleted file mode 100644 index c594cb63f4ca..000000000000 --- a/thirdparty/assimp/include/assimp/StandardShapes.h +++ /dev/null @@ -1,205 +0,0 @@ -/* -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 Declares a helper class, "StandardShapes" which generates - * vertices for standard shapes, such as cylinders, cones, spheres .. - */ -#pragma once -#ifndef AI_STANDARD_SHAPES_H_INC -#define AI_STANDARD_SHAPES_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -struct aiMesh; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** \brief Helper class to generate vertex buffers for standard geometric - * shapes, such as cylinders, cones, boxes, spheres, elipsoids ... . - */ -class ASSIMP_API StandardShapes -{ - // class cannot be instanced - StandardShapes() {} - -public: - - - // ---------------------------------------------------------------- - /** Generates a mesh from an array of vertex positions. - * - * @param positions List of vertex positions - * @param numIndices Number of indices per primitive - * @return Output mesh - */ - static aiMesh* MakeMesh(const std::vector& positions, - unsigned int numIndices); - - - static aiMesh* MakeMesh ( unsigned int (*GenerateFunc) - (std::vector&)); - - static aiMesh* MakeMesh ( unsigned int (*GenerateFunc) - (std::vector&, bool)); - - static aiMesh* MakeMesh ( unsigned int n, void (*GenerateFunc) - (unsigned int,std::vector&)); - - // ---------------------------------------------------------------- - /** @brief Generates a hexahedron (cube) - * - * Hexahedrons can be scaled on all axes. - * @param positions Receives output triangles. - * @param polygons If you pass true here quads will be returned - * @return Number of vertices per face - */ - static unsigned int MakeHexahedron( - std::vector& positions, - bool polygons = false); - - // ---------------------------------------------------------------- - /** @brief Generates an icosahedron - * - * @param positions Receives output triangles. - * @return Number of vertices per face - */ - static unsigned int MakeIcosahedron( - std::vector& positions); - - - // ---------------------------------------------------------------- - /** @brief Generates a dodecahedron - * - * @param positions Receives output triangles - * @param polygons If you pass true here pentagons will be returned - * @return Number of vertices per face - */ - static unsigned int MakeDodecahedron( - std::vector& positions, - bool polygons = false); - - - // ---------------------------------------------------------------- - /** @brief Generates an octahedron - * - * @param positions Receives output triangles. - * @return Number of vertices per face - */ - static unsigned int MakeOctahedron( - std::vector& positions); - - - // ---------------------------------------------------------------- - /** @brief Generates a tetrahedron - * - * @param positions Receives output triangles. - * @return Number of vertices per face - */ - static unsigned int MakeTetrahedron( - std::vector& positions); - - - - // ---------------------------------------------------------------- - /** @brief Generates a sphere - * - * @param tess Number of subdivions - 0 generates a octahedron - * @param positions Receives output triangles. - */ - static void MakeSphere(unsigned int tess, - std::vector& positions); - - - // ---------------------------------------------------------------- - /** @brief Generates a cone or a cylinder, either open or closed. - * - * @code - * - * |-----| <- radius 1 - * - * __x__ <- ] ^ - * / \ | height | - * / \ | Y - * / \ | - * / \ | - * /______x______\ <- ] <- end cap - * - * |-------------| <- radius 2 - * - * @endcode - * - * @param height Height of the cone - * @param radius1 First radius - * @param radius2 Second radius - * @param tess Number of triangles. - * @param bOpened true for an open cone/cylinder. An open shape has - * no 'end caps' - * @param positions Receives output triangles - */ - static void MakeCone(ai_real height,ai_real radius1, - ai_real radius2,unsigned int tess, - std::vector& positions,bool bOpen= false); - - - // ---------------------------------------------------------------- - /** @brief Generates a flat circle - * - * The circle is constructed in the planned formed by the x,z - * axes of the cartesian coordinate system. - * - * @param radius Radius of the circle - * @param tess Number of segments. - * @param positions Receives output triangles. - */ - static void MakeCircle(ai_real radius, unsigned int tess, - std::vector& positions); - -}; -} // ! Assimp - -#endif // !! AI_STANDARD_SHAPES_H_INC diff --git a/thirdparty/assimp/include/assimp/StreamReader.h b/thirdparty/assimp/include/assimp/StreamReader.h deleted file mode 100644 index cb24f1595b25..000000000000 --- a/thirdparty/assimp/include/assimp/StreamReader.h +++ /dev/null @@ -1,347 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Defines the StreamReader class which reads data from - * a binary stream with a well-defined endianness. - */ -#pragma once -#ifndef AI_STREAMREADER_H_INCLUDED -#define AI_STREAMREADER_H_INCLUDED - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include -#include - -#include - -namespace Assimp { - -// -------------------------------------------------------------------------------------------- -/** Wrapper class around IOStream to allow for consistent reading of binary data in both - * little and big endian format. Don't attempt to instance the template directly. Use - * StreamReaderLE to read from a little-endian stream and StreamReaderBE to read from a - * BE stream. The class expects that the endianness of any input data is known at - * compile-time, which should usually be true (#BaseImporter::ConvertToUTF8 implements - * runtime endianness conversions for text files). - * - * XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/ -// -------------------------------------------------------------------------------------------- -template -class StreamReader { -public: - // FIXME: use these data types throughout the whole library, - // then change them to 64 bit values :-) - using diff = int; - using pos = unsigned int; - - // --------------------------------------------------------------------- - /** Construction from a given stream with a well-defined endianness. - * - * The StreamReader holds a permanent strong reference to the - * stream, which is released upon destruction. - * @param stream Input stream. The stream is not restarted if - * its file pointer is not at 0. Instead, the stream reader - * reads from the current position to the end of the stream. - * @param le If @c RuntimeSwitch is true: specifies whether the - * stream is in little endian byte order. Otherwise the - * endianness information is contained in the @c SwapEndianess - * template parameter and this parameter is meaningless. */ - StreamReader(std::shared_ptr stream, bool le = false) - : stream(stream) - , le(le) - { - ai_assert(stream); - InternBegin(); - } - - // --------------------------------------------------------------------- - StreamReader(IOStream* stream, bool le = false) - : stream(std::shared_ptr(stream)) - , le(le) - { - ai_assert(stream); - InternBegin(); - } - - // --------------------------------------------------------------------- - ~StreamReader() { - delete[] buffer; - } - - // deprecated, use overloaded operator>> instead - - // --------------------------------------------------------------------- - /** Read a float from the stream */ - float GetF4() - { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a double from the stream */ - double GetF8() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a signed 16 bit integer from the stream */ - int16_t GetI2() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a signed 8 bit integer from the stream */ - int8_t GetI1() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read an signed 32 bit integer from the stream */ - int32_t GetI4() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a signed 64 bit integer from the stream */ - int64_t GetI8() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a unsigned 16 bit integer from the stream */ - uint16_t GetU2() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a unsigned 8 bit integer from the stream */ - uint8_t GetU1() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read an unsigned 32 bit integer from the stream */ - uint32_t GetU4() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Read a unsigned 64 bit integer from the stream */ - uint64_t GetU8() { - return Get(); - } - - // --------------------------------------------------------------------- - /** Get the remaining stream size (to the end of the stream) */ - unsigned int GetRemainingSize() const { - return (unsigned int)(end - current); - } - - // --------------------------------------------------------------------- - /** Get the remaining stream size (to the current read limit). The - * return value is the remaining size of the stream if no custom - * read limit has been set. */ - unsigned int GetRemainingSizeToLimit() const { - return (unsigned int)(limit - current); - } - - // --------------------------------------------------------------------- - /** Increase the file pointer (relative seeking) */ - void IncPtr(intptr_t plus) { - current += plus; - if (current > limit) { - throw DeadlyImportError("End of file or read limit was reached"); - } - } - - // --------------------------------------------------------------------- - /** Get the current file pointer */ - int8_t* GetPtr() const { - return current; - } - - // --------------------------------------------------------------------- - /** Set current file pointer (Get it from #GetPtr). This is if you - * prefer to do pointer arithmetics on your own or want to copy - * large chunks of data at once. - * @param p The new pointer, which is validated against the size - * limit and buffer boundaries. */ - void SetPtr(int8_t* p) { - current = p; - if (current > limit || current < buffer) { - throw DeadlyImportError("End of file or read limit was reached"); - } - } - - // --------------------------------------------------------------------- - /** Copy n bytes to an external buffer - * @param out Destination for copying - * @param bytes Number of bytes to copy */ - void CopyAndAdvance(void* out, size_t bytes) { - int8_t* ur = GetPtr(); - SetPtr(ur+bytes); // fire exception if eof - - ::memcpy(out,ur,bytes); - } - - // --------------------------------------------------------------------- - /** Get the current offset from the beginning of the file */ - int GetCurrentPos() const { - return (unsigned int)(current - buffer); - } - - void SetCurrentPos(size_t pos) { - SetPtr(buffer + pos); - } - - // --------------------------------------------------------------------- - /** Setup a temporary read limit - * - * @param limit Maximum number of bytes to be read from - * the beginning of the file. Specifying UINT_MAX - * resets the limit to the original end of the stream. - * Returns the previously set limit. */ - unsigned int SetReadLimit(unsigned int _limit) { - unsigned int prev = GetReadLimit(); - if (UINT_MAX == _limit) { - limit = end; - return prev; - } - - limit = buffer + _limit; - if (limit > end) { - throw DeadlyImportError("StreamReader: Invalid read limit"); - } - return prev; - } - - // --------------------------------------------------------------------- - /** Get the current read limit in bytes. Reading over this limit - * accidentally raises an exception. */ - unsigned int GetReadLimit() const { - return (unsigned int)(limit - buffer); - } - - // --------------------------------------------------------------------- - /** Skip to the read limit in bytes. Reading over this limit - * accidentally raises an exception. */ - void SkipToReadLimit() { - current = limit; - } - - // --------------------------------------------------------------------- - /** overload operator>> and allow chaining of >> ops. */ - template - StreamReader& operator >> (T& f) { - f = Get(); - return *this; - } - - // --------------------------------------------------------------------- - /** Generic read method. ByteSwap::Swap(T*) *must* be defined */ - template - T Get() { - if ( current + sizeof(T) > limit) { - throw DeadlyImportError("End of file or stream limit was reached"); - } - - T f; - ::memcpy (&f, current, sizeof(T)); - Intern::Getter() (&f,le); - current += sizeof(T); - - return f; - } - -private: - // --------------------------------------------------------------------- - void InternBegin() { - if (!stream) { - // in case someone wonders: StreamReader is frequently invoked with - // no prior validation whether the input stream is valid. Since - // no one bothers changing the error message, this message here - // is passed down to the caller and 'unable to open file' - // simply describes best what happened. - throw DeadlyImportError("StreamReader: Unable to open file"); - } - - const size_t s = stream->FileSize() - stream->Tell(); - if (!s) { - throw DeadlyImportError("StreamReader: File is empty or EOF is already reached"); - } - - current = buffer = new int8_t[s]; - const size_t read = stream->Read(current,1,s); - // (read < s) can only happen if the stream was opened in text mode, in which case FileSize() is not reliable - ai_assert(read <= s); - end = limit = &buffer[read-1] + 1; - } - -private: - std::shared_ptr stream; - int8_t *buffer, *current, *end, *limit; - bool le; -}; - -// -------------------------------------------------------------------------------------------- -// `static` StreamReaders. Their byte order is fixed and they might be a little bit faster. -#ifdef AI_BUILD_BIG_ENDIAN - typedef StreamReader StreamReaderLE; - typedef StreamReader StreamReaderBE; -#else - typedef StreamReader StreamReaderBE; - typedef StreamReader StreamReaderLE; -#endif - -// `dynamic` StreamReader. The byte order of the input data is specified in the -// c'tor. This involves runtime branching and might be a little bit slower. -typedef StreamReader StreamReaderAny; - -} // end namespace Assimp - -#endif // !! AI_STREAMREADER_H_INCLUDED diff --git a/thirdparty/assimp/include/assimp/StreamWriter.h b/thirdparty/assimp/include/assimp/StreamWriter.h deleted file mode 100644 index 489e8adfe335..000000000000 --- a/thirdparty/assimp/include/assimp/StreamWriter.h +++ /dev/null @@ -1,307 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 Defines the StreamWriter class which writes data to - * a binary stream with a well-defined endianness. */ -#pragma once -#ifndef AI_STREAMWRITER_H_INCLUDED -#define AI_STREAMWRITER_H_INCLUDED - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include - -#include -#include - -namespace Assimp { - -// -------------------------------------------------------------------------------------------- -/** Wrapper class around IOStream to allow for consistent writing of binary data in both - * little and big endian format. Don't attempt to instance the template directly. Use - * StreamWriterLE to write to a little-endian stream and StreamWriterBE to write to a - * BE stream. Alternatively, there is StreamWriterAny if the endianness of the output - * stream is to be determined at runtime. - */ -// -------------------------------------------------------------------------------------------- -template -class StreamWriter -{ - enum { - INITIAL_CAPACITY = 1024 - }; - -public: - - // --------------------------------------------------------------------- - /** Construction from a given stream with a well-defined endianness. - * - * The StreamReader holds a permanent strong reference to the - * stream, which is released upon destruction. - * @param stream Input stream. The stream is not re-seeked and writing - continues at the current position of the stream cursor. - * @param le If @c RuntimeSwitch is true: specifies whether the - * stream is in little endian byte order. Otherwise the - * endianness information is defined by the @c SwapEndianess - * template parameter and this parameter is meaningless. */ - StreamWriter(std::shared_ptr stream, bool le = false) - : stream(stream) - , le(le) - , cursor() - { - ai_assert(stream); - buffer.reserve(INITIAL_CAPACITY); - } - - // --------------------------------------------------------------------- - StreamWriter(IOStream* stream, bool le = false) - : stream(std::shared_ptr(stream)) - , le(le) - , cursor() - { - ai_assert(stream); - buffer.reserve(INITIAL_CAPACITY); - } - - // --------------------------------------------------------------------- - ~StreamWriter() { - stream->Write(buffer.data(), 1, buffer.size()); - stream->Flush(); - } - -public: - - // --------------------------------------------------------------------- - /** Flush the contents of the internal buffer, and the output IOStream */ - void Flush() - { - stream->Write(buffer.data(), 1, buffer.size()); - stream->Flush(); - buffer.clear(); - cursor = 0; - } - - // --------------------------------------------------------------------- - /** Seek to the given offset / origin in the output IOStream. - * - * Flushes the internal buffer and the output IOStream prior to seeking. */ - aiReturn Seek(size_t pOffset, aiOrigin pOrigin=aiOrigin_SET) - { - Flush(); - return stream->Seek(pOffset, pOrigin); - } - - // --------------------------------------------------------------------- - /** Tell the current position in the output IOStream. - * - * First flushes the internal buffer and the output IOStream. */ - size_t Tell() - { - Flush(); - return stream->Tell(); - } - -public: - - // --------------------------------------------------------------------- - /** Write a float to the stream */ - void PutF4(float f) - { - Put(f); - } - - // --------------------------------------------------------------------- - /** Write a double to the stream */ - void PutF8(double d) { - Put(d); - } - - // --------------------------------------------------------------------- - /** Write a signed 16 bit integer to the stream */ - void PutI2(int16_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a signed 8 bit integer to the stream */ - void PutI1(int8_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write an signed 32 bit integer to the stream */ - void PutI4(int32_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a signed 64 bit integer to the stream */ - void PutI8(int64_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a unsigned 16 bit integer to the stream */ - void PutU2(uint16_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a unsigned 8 bit integer to the stream */ - void PutU1(uint8_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write an unsigned 32 bit integer to the stream */ - void PutU4(uint32_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a unsigned 64 bit integer to the stream */ - void PutU8(uint64_t n) { - Put(n); - } - - // --------------------------------------------------------------------- - /** Write a single character to the stream */ - void PutChar(char c) { - Put(c); - } - - // --------------------------------------------------------------------- - /** Write an aiString to the stream */ - void PutString(const aiString& s) - { - // as Put(T f) below - if (cursor + s.length >= buffer.size()) { - buffer.resize(cursor + s.length); - } - void* dest = &buffer[cursor]; - ::memcpy(dest, s.C_Str(), s.length); - cursor += s.length; - } - - // --------------------------------------------------------------------- - /** Write a std::string to the stream */ - void PutString(const std::string& s) - { - // as Put(T f) below - if (cursor + s.size() >= buffer.size()) { - buffer.resize(cursor + s.size()); - } - void* dest = &buffer[cursor]; - ::memcpy(dest, s.c_str(), s.size()); - cursor += s.size(); - } - -public: - - // --------------------------------------------------------------------- - /** overload operator<< and allow chaining of MM ops. */ - template - StreamWriter& operator << (T f) { - Put(f); - return *this; - } - - // --------------------------------------------------------------------- - std::size_t GetCurrentPos() const { - return cursor; - } - - // --------------------------------------------------------------------- - void SetCurrentPos(std::size_t new_cursor) { - cursor = new_cursor; - } - - // --------------------------------------------------------------------- - /** Generic write method. ByteSwap::Swap(T*) *must* be defined */ - template - void Put(T f) { - Intern :: Getter() (&f, le); - - if (cursor + sizeof(T) >= buffer.size()) { - buffer.resize(cursor + sizeof(T)); - } - - void* dest = &buffer[cursor]; - - // reinterpret_cast + assignment breaks strict aliasing rules - // and generally causes trouble on platforms such as ARM that - // do not silently ignore alignment faults. - ::memcpy(dest, &f, sizeof(T)); - cursor += sizeof(T); - } - -private: - - std::shared_ptr stream; - bool le; - - std::vector buffer; - std::size_t cursor; -}; - - -// -------------------------------------------------------------------------------------------- -// `static` StreamWriter. Their byte order is fixed and they might be a little bit faster. -#ifdef AI_BUILD_BIG_ENDIAN - typedef StreamWriter StreamWriterLE; - typedef StreamWriter StreamWriterBE; -#else - typedef StreamWriter StreamWriterBE; - typedef StreamWriter StreamWriterLE; -#endif - -// `dynamic` StreamWriter. The byte order of the input data is specified in the -// c'tor. This involves runtime branching and might be a little bit slower. -typedef StreamWriter StreamWriterAny; - -} // end namespace Assimp - -#endif // !! AI_STREAMWriter_H_INCLUDED diff --git a/thirdparty/assimp/include/assimp/StringComparison.h b/thirdparty/assimp/include/assimp/StringComparison.h deleted file mode 100644 index d3ca3e971439..000000000000 --- a/thirdparty/assimp/include/assimp/StringComparison.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -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 Definition of platform independent string workers: - - ASSIMP_itoa10 - ASSIMP_stricmp - ASSIMP_strincmp - - These functions are not consistently available on all platforms, - or the provided implementations behave too differently. -*/ -#pragma once -#ifndef INCLUDED_AI_STRING_WORKERS_H -#define INCLUDED_AI_STRING_WORKERS_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include -#include -#include - -namespace Assimp { - -// ------------------------------------------------------------------------------- -/** @brief itoa with a fixed base 10 - * 'itoa' is not consistently available on all platforms so it is quite useful - * to have a small replacement function here. No need to use a full sprintf() - * if we just want to print a number ... - * @param out Output buffer - * @param max Maximum number of characters to be written, including '\0'. - * This parameter may not be 0. - * @param number Number to be written - * @return Length of the output string, excluding the '\0' - */ -AI_FORCE_INLINE -unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number) { - ai_assert(NULL != out); - - // write the unary minus to indicate we have a negative number - unsigned int written = 1u; - if (number < 0 && written < max) { - *out++ = '-'; - ++written; - number = -number; - } - - // We begin with the largest number that is not zero. - int32_t cur = 1000000000; // 2147483648 - bool mustPrint = false; - while (written < max) { - - const unsigned int digit = number / cur; - if (mustPrint || digit > 0 || 1 == cur) { - // print all future zeroe's from now - mustPrint = true; - - *out++ = '0'+static_cast(digit); - - ++written; - number -= digit*cur; - if (1 == cur) { - break; - } - } - cur /= 10; - } - - // append a terminal zero - *out++ = '\0'; - return written-1; -} - -// ------------------------------------------------------------------------------- -/** @brief itoa with a fixed base 10 (Secure template overload) - * The compiler should choose this function if he or she is able to determine the - * size of the array automatically. - */ -template -AI_FORCE_INLINE -unsigned int ASSIMP_itoa10( char(& out)[length], int32_t number) { - return ASSIMP_itoa10(out,length,number); -} - -// ------------------------------------------------------------------------------- -/** @brief Helper function to do platform independent string comparison. - * - * This is required since stricmp() is not consistently available on - * all platforms. Some platforms use the '_' prefix, others don't even - * have such a function. - * - * @param s1 First input string - * @param s2 Second input string - * @return 0 if the given strings are identical - */ -AI_FORCE_INLINE -int ASSIMP_stricmp(const char *s1, const char *s2) { - ai_assert( NULL != s1 ); - ai_assert( NULL != s2 ); - -#if (defined _MSC_VER) - - return ::_stricmp(s1,s2); -#elif defined( __GNUC__ ) - - return ::strcasecmp(s1,s2); -#else - - char c1, c2; - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } - while ( c1 && (c1 == c2) ); - return c1 - c2; -#endif -} - -// ------------------------------------------------------------------------------- -/** @brief Case independent comparison of two std::strings - * - * @param a First string - * @param b Second string - * @return 0 if a == b - */ -AI_FORCE_INLINE -int ASSIMP_stricmp(const std::string& a, const std::string& b) { - int i = (int)b.length()-(int)a.length(); - return (i ? i : ASSIMP_stricmp(a.c_str(),b.c_str())); -} - -// ------------------------------------------------------------------------------- -/** @brief Helper function to do platform independent string comparison. - * - * This is required since strincmp() is not consistently available on - * all platforms. Some platforms use the '_' prefix, others don't even - * have such a function. - * - * @param s1 First input string - * @param s2 Second input string - * @param n Macimum number of characters to compare - * @return 0 if the given strings are identical - */ -AI_FORCE_INLINE -int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) { - ai_assert( NULL != s1 ); - ai_assert( NULL != s2 ); - if ( !n ) { - return 0; - } - -#if (defined _MSC_VER) - - return ::_strnicmp(s1,s2,n); - -#elif defined( __GNUC__ ) - - return ::strncasecmp(s1,s2, n); - -#else - char c1, c2; - unsigned int p = 0; - do - { - if (p++ >= n)return 0; - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } - while ( c1 && (c1 == c2) ); - - return c1 - c2; -#endif -} - - -// ------------------------------------------------------------------------------- -/** @brief Evaluates an integer power - * - * todo: move somewhere where it fits better in than here - */ -AI_FORCE_INLINE -unsigned int integer_pow( unsigned int base, unsigned int power ) { - unsigned int res = 1; - for ( unsigned int i = 0; i < power; ++i ) { - res *= base; - } - - return res; -} - -} // end of namespace - -#endif // ! AI_STRINGCOMPARISON_H_INC diff --git a/thirdparty/assimp/include/assimp/StringUtils.h b/thirdparty/assimp/include/assimp/StringUtils.h deleted file mode 100644 index af481f819eae..000000000000 --- a/thirdparty/assimp/include/assimp/StringUtils.h +++ /dev/null @@ -1,148 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ -#pragma once -#ifndef INCLUDED_AI_STRINGUTILS_H -#define INCLUDED_AI_STRINGUTILS_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -#include -#include -#include - -/// @fn ai_snprintf -/// @brief The portable version of the function snprintf ( C99 standard ), which works on visual studio compilers 2013 and earlier. -/// @param outBuf The buffer to write in -/// @param size The buffer size -/// @param format The format string -/// @param ap The additional arguments. -/// @return The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned. -#if defined(_MSC_VER) && _MSC_VER < 1900 - - AI_FORCE_INLINE - int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { - int count(-1); - if (0 != size) { - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - } - if (count == -1) { - count = _vscprintf(format, ap); - } - - return count; - } - - AI_FORCE_INLINE - int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { - int count; - va_list ap; - - va_start(ap, format); - count = c99_ai_vsnprintf(outBuf, size, format, ap); - va_end(ap); - - return count; - } - -#else -# define ai_snprintf snprintf -#endif - -/// @fn to_string -/// @brief The portable version of to_string ( some gcc-versions on embedded devices are not supporting this). -/// @param value The value to write into the std::string. -/// @return The value as a std::string -template -AI_FORCE_INLINE -std::string to_string( T value ) { - std::ostringstream os; - os << value; - - return os.str(); -} - -/// @fn ai_strtof -/// @brief The portable version of strtof. -/// @param begin The first character of the string. -/// @param end The last character -/// @return The float value, 0.0f in cas of an error. -AI_FORCE_INLINE -float ai_strtof( const char *begin, const char *end ) { - if ( nullptr == begin ) { - return 0.0f; - } - float val( 0.0f ); - if ( nullptr == end ) { - val = static_cast< float >( ::atof( begin ) ); - } else { - std::string::size_type len( end - begin ); - std::string token( begin, len ); - val = static_cast< float >( ::atof( token.c_str() ) ); - } - - return val; -} - -/// @fn DecimalToHexa -/// @brief The portable to convert a decimal value into a hexadecimal string. -/// @param toConvert Value to convert -/// @return The hexadecimal string, is empty in case of an error. -template -AI_FORCE_INLINE -std::string DecimalToHexa( T toConvert ) { - std::string result; - std::stringstream ss; - ss << std::hex << toConvert; - ss >> result; - - for ( size_t i = 0; i < result.size(); ++i ) { - result[ i ] = toupper( result[ i ] ); - } - - return result; -} - -#endif // INCLUDED_AI_STRINGUTILS_H diff --git a/thirdparty/assimp/include/assimp/Subdivision.h b/thirdparty/assimp/include/assimp/Subdivision.h deleted file mode 100644 index e9450267ecde..000000000000 --- a/thirdparty/assimp/include/assimp/Subdivision.h +++ /dev/null @@ -1,134 +0,0 @@ -/* -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 Defines a helper class to evaluate subdivision surfaces.*/ -#pragma once -#ifndef AI_SUBDISIVION_H_INC -#define AI_SUBDISIVION_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -struct aiMesh; - -namespace Assimp { - -// ------------------------------------------------------------------------------ -/** Helper class to evaluate subdivision surfaces. Different algorithms - * are provided for choice. */ -// ------------------------------------------------------------------------------ -class ASSIMP_API Subdivider { -public: - - /** Enumerates all supported subvidision algorithms */ - enum Algorithm { - CATMULL_CLARKE = 0x1 - }; - - virtual ~Subdivider(); - - // --------------------------------------------------------------- - /** Create a subdivider of a specific type - * - * @param algo Algorithm to be used for subdivision - * @return Subdivider instance. */ - static Subdivider* Create (Algorithm algo); - - // --------------------------------------------------------------- - /** Subdivide a mesh using the selected algorithm - * - * @param mesh First mesh to be subdivided. Must be in verbose - * format. - * @param out Receives the output mesh, allocated by me. - * @param num Number of subdivisions to perform. - * @param discard_input If true is passed, the input mesh is - * deleted after the subdivision is complete. This can - * improve performance because it allows the optimization - * to reuse the existing mesh for intermediate results. - * @pre out!=mesh*/ - virtual void Subdivide ( aiMesh* mesh, - aiMesh*& out, unsigned int num, - bool discard_input = false) = 0; - - // --------------------------------------------------------------- - /** Subdivide multiple meshes using the selected algorithm. This - * avoids erroneous smoothing on objects consisting of multiple - * per-material meshes. Usually, most 3d modellers smooth on a - * per-object base, regardless the materials assigned to the - * meshes. - * - * @param smesh Array of meshes to be subdivided. Must be in - * verbose format. - * @param nmesh Number of meshes in smesh. - * @param out Receives the output meshes. The array must be - * sufficiently large (at least @c nmesh elements) and may not - * overlap the input array. Output meshes map one-to-one to - * their corresponding input meshes. The meshes are allocated - * by the function. - * @param discard_input If true is passed, input meshes are - * deleted after the subdivision is complete. This can - * improve performance because it allows the optimization - * of reusing existing meshes for intermediate results. - * @param num Number of subdivisions to perform. - * @pre nmesh != 0, smesh and out may not overlap*/ - virtual void Subdivide ( - aiMesh** smesh, - size_t nmesh, - aiMesh** out, - unsigned int num, - bool discard_input = false) = 0; - -}; - -inline -Subdivider::~Subdivider() { - // empty -} - -} // end namespace Assimp - - -#endif // !! AI_SUBDISIVION_H_INC - diff --git a/thirdparty/assimp/include/assimp/TinyFormatter.h b/thirdparty/assimp/include/assimp/TinyFormatter.h deleted file mode 100644 index 6227e42c5207..000000000000 --- a/thirdparty/assimp/include/assimp/TinyFormatter.h +++ /dev/null @@ -1,158 +0,0 @@ -/* -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 TinyFormatter.h - * @brief Utility to format log messages more easily. Introduced - * to get rid of the boost::format dependency. Much slinker, - * basically just extends stringstream. - */ -#pragma once -#ifndef INCLUDED_TINY_FORMATTER_H -#define INCLUDED_TINY_FORMATTER_H - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include - -namespace Assimp { -namespace Formatter { - -// ------------------------------------------------------------------------------------------------ -/** stringstream utility. Usage: - * @code - * void writelog(const std::string&s); - * void writelog(const std::wstring&s); - * ... - * writelog(format()<< "hi! this is a number: " << 4); - * writelog(wformat()<< L"hi! this is a number: " << 4); - * - * @endcode */ -template < typename T, - typename CharTraits = std::char_traits, - typename Allocator = std::allocator > -class basic_formatter { -public: - typedef class std::basic_string string; - typedef class std::basic_ostringstream stringstream; - - basic_formatter() { - // empty - } - - /* Allow basic_formatter's to be used almost interchangeably - * with std::(w)string or const (w)char* arguments because the - * conversion c'tor is called implicitly. */ - template - basic_formatter(const TT& sin) { - underlying << sin; - } - - - // The problem described here: - // https://sourceforge.net/tracker/?func=detail&atid=1067632&aid=3358562&group_id=226462 - // can also cause trouble here. Apparently, older gcc versions sometimes copy temporaries - // being bound to const ref& function parameters. Copying streams is not permitted, though. - // This workaround avoids this by manually specifying a copy ctor. -#if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - explicit basic_formatter(const basic_formatter& other) { - underlying << (string)other; - } -#endif - - operator string () const { - return underlying.str(); - } - - /* note - this is declared const because binding temporaries does only - * work for const references, so many function prototypes will - * include const basic_formatter& s but might still want to - * modify the formatted string without the need for a full copy.*/ - template - const basic_formatter& operator << (const TToken& s) const { - underlying << s; - return *this; - } - - template - basic_formatter& operator << (const TToken& s) { - underlying << s; - return *this; - } - - - // comma operator overloaded as well, choose your preferred way. - template - const basic_formatter& operator, (const TToken& s) const { - underlying << s; - return *this; - } - - template - basic_formatter& operator, (const TToken& s) { - underlying << s; - return *this; - } - - // Fix for MSVC8 - // See https://sourceforge.net/projects/assimp/forums/forum/817654/topic/4372824 - template - basic_formatter& operator, (TToken& s) { - underlying << s; - return *this; - } - - -private: - mutable stringstream underlying; -}; - - -typedef basic_formatter< char > format; -typedef basic_formatter< wchar_t > wformat; - -} // ! namespace Formatter - -} // ! namespace Assimp - -#endif diff --git a/thirdparty/assimp/include/assimp/Vertex.h b/thirdparty/assimp/include/assimp/Vertex.h deleted file mode 100644 index 5e63db5fe4aa..000000000000 --- a/thirdparty/assimp/include/assimp/Vertex.h +++ /dev/null @@ -1,297 +0,0 @@ -/* -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 Defines a helper class to represent an interleaved vertex - along with arithmetic operations to support vertex operations - such as subdivision, smoothing etc. - - While the code is kept as general as possible, arithmetic operations - that are not currently well-defined (and would cause compile errors - due to missing operators in the math library), are commented. - */ -#pragma once -#ifndef AI_VERTEX_H_INC -#define AI_VERTEX_H_INC - -#ifdef __GNUC__ -# pragma GCC system_header -#endif - -#include -#include -#include - -#include - -namespace Assimp { - - /////////////////////////////////////////////////////////////////////////// - // std::plus-family operates on operands with identical types - we need to - // support all the (vectype op float) combinations in vector maths. - // Providing T(float) would open the way to endless implicit conversions. - /////////////////////////////////////////////////////////////////////////// - namespace Intern { - template struct plus { - TRES operator() (const T0& t0, const T1& t1) const { - return t0+t1; - } - }; - template struct minus { - TRES operator() (const T0& t0, const T1& t1) const { - return t0-t1; - } - }; - template struct multiplies { - TRES operator() (const T0& t0, const T1& t1) const { - return t0*t1; - } - }; - template struct divides { - TRES operator() (const T0& t0, const T1& t1) const { - return t0/t1; - } - }; - } - -// ------------------------------------------------------------------------------------------------ -/** Intermediate description a vertex with all possible components. Defines a full set of - * operators, so you may use such a 'Vertex' in basic arithmetics. All operators are applied - * to *all* vertex components equally. This is useful for stuff like interpolation - * or subdivision, but won't work if special handling is required for some vertex components. */ -// ------------------------------------------------------------------------------------------------ -class Vertex { - friend Vertex operator + (const Vertex&,const Vertex&); - friend Vertex operator - (const Vertex&,const Vertex&); - friend Vertex operator * (const Vertex&,ai_real); - friend Vertex operator / (const Vertex&,ai_real); - friend Vertex operator * (ai_real, const Vertex&); - -public: - Vertex() {} - - // ---------------------------------------------------------------------------- - /** Extract a particular vertex from a mesh and interleave all components */ - explicit Vertex(const aiMesh* msh, unsigned int idx) { - ai_assert(idx < msh->mNumVertices); - position = msh->mVertices[idx]; - - if (msh->HasNormals()) { - normal = msh->mNormals[idx]; - } - - if (msh->HasTangentsAndBitangents()) { - tangent = msh->mTangents[idx]; - bitangent = msh->mBitangents[idx]; - } - - for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) { - texcoords[i] = msh->mTextureCoords[i][idx]; - } - - for (unsigned int i = 0; msh->HasVertexColors(i); ++i) { - colors[i] = msh->mColors[i][idx]; - } - } - - // ---------------------------------------------------------------------------- - /** Extract a particular vertex from a anim mesh and interleave all components */ - explicit Vertex(const aiAnimMesh* msh, unsigned int idx) { - ai_assert(idx < msh->mNumVertices); - position = msh->mVertices[idx]; - - if (msh->HasNormals()) { - normal = msh->mNormals[idx]; - } - - if (msh->HasTangentsAndBitangents()) { - tangent = msh->mTangents[idx]; - bitangent = msh->mBitangents[idx]; - } - - for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) { - texcoords[i] = msh->mTextureCoords[i][idx]; - } - - for (unsigned int i = 0; msh->HasVertexColors(i); ++i) { - colors[i] = msh->mColors[i][idx]; - } - } - - Vertex& operator += (const Vertex& v) { - *this = *this+v; - return *this; - } - - Vertex& operator -= (const Vertex& v) { - *this = *this-v; - return *this; - } - - Vertex& operator *= (ai_real v) { - *this = *this*v; - return *this; - } - - Vertex& operator /= (ai_real v) { - *this = *this/v; - return *this; - } - - // ---------------------------------------------------------------------------- - /** Convert back to non-interleaved storage */ - void SortBack(aiMesh* out, unsigned int idx) const { - ai_assert(idxmNumVertices); - out->mVertices[idx] = position; - - if (out->HasNormals()) { - out->mNormals[idx] = normal; - } - - if (out->HasTangentsAndBitangents()) { - out->mTangents[idx] = tangent; - out->mBitangents[idx] = bitangent; - } - - for(unsigned int i = 0; out->HasTextureCoords(i); ++i) { - out->mTextureCoords[i][idx] = texcoords[i]; - } - - for(unsigned int i = 0; out->HasVertexColors(i); ++i) { - out->mColors[i][idx] = colors[i]; - } - } - -private: - - // ---------------------------------------------------------------------------- - /** Construct from two operands and a binary operation to combine them */ - template