remove assimp pending fbx upgrade

This commit is contained in:
Gordon MacPherson 2020-12-22 21:31:06 +00:00
parent 30d469a5e0
commit 5b5fdb0adf
241 changed files with 0 additions and 72567 deletions

View file

@ -1,108 +0,0 @@
#!/usr/bin/env python
Import("env")
Import("env_modules")
env_assimp = env_modules.Clone()
# Thirdparty source files
thirdparty_obj = []
# 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"] == "linuxbsd":
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(thirdparty_obj, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Common/*.cpp"))
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Material/*.cpp"))
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
env.modules_sources += thirdparty_obj
# Godot source files
module_obj = []
env_assimp.add_source_files(module_obj, "*.cpp")
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)

View file

@ -1,6 +0,0 @@
def can_build(env, platform):
return env["tools"]
def configure(env):
pass

File diff suppressed because it is too large Load diff

View file

@ -1,149 +0,0 @@
/*************************************************************************/
/* editor_scene_importer_assimp.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_IMPORTER_ASSIMP_H
#define EDITOR_SCENE_IMPORTER_ASSIMP_H
#ifdef TOOLS_ENABLED
#include "core/core_bind.h"
#include "core/io/resource_importer.h"
#include "core/templates/vector.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/project_settings_editor.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/surface_tool.h"
#include <assimp/matrix4x4.h>
#include <assimp/scene.h>
#include <assimp/types.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/Logger.hpp>
#include <map>
#include "import_state.h"
#include "import_utils.h"
using namespace AssimpImporter;
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 {
private:
GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter);
struct AssetImportAnimation {
enum Interpolation {
INTERP_LINEAR,
INTERP_STEP,
INTERP_CATMULLROMSPLINE,
INTERP_CUBIC_SPLINE
};
};
struct BoneInfo {
uint32_t bone;
float weight;
};
Ref<Mesh> _generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
const aiNode *assimp_node, Ref<Skin> &skin,
Skeleton3D *&skeleton_assigned);
// simple object creation functions
Node3D *create_light(ImportState &state,
const String &node_name,
Transform &look_at_transform);
Node3D *create_camera(
ImportState &state,
const String &node_name,
Transform &look_at_transform);
// non recursive - linear so must not use recursive arguments
MeshInstance3D *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> animation, float ticks_per_second,
Skeleton3D *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);
Node3D *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const;
struct ImportFormat {
Vector<String> extensions;
bool is_default;
};
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);
}
~EditorSceneImporterAssimp() {
Assimp::DefaultLogger::kill();
}
virtual void get_extensions(List<String> *r_extensions) const override;
virtual uint32_t get_import_flags() const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path);
static void RegenerateBoneStack(ImportState &state);
void RegenerateBoneStack(ImportState &state, aiMesh *mesh);
};
#endif
#endif

View file

@ -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*

View file

@ -1,132 +0,0 @@
/*************************************************************************/
/* import_state.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_IMPORT_STATE_H
#define EDITOR_SCENE_IMPORT_STATE_H
#include "core/core_bind.h"
#include "core/io/resource_importer.h"
#include "core/templates/vector.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/project_settings_editor.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/surface_tool.h"
#include <assimp/matrix4x4.h>
#include <assimp/scene.h>
#include <assimp/types.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/Logger.hpp>
namespace AssimpImporter {
/** Import state is for global scene import data
* This makes the code simpler and contains useful lookups.
*/
struct ImportState {
String path;
Node3D *root;
const aiScene *assimp_scene;
uint32_t max_bone_weights;
Map<String, Ref<Mesh>> mesh_cache;
Map<int, Ref<Material>> material_cache;
Map<String, int> light_cache;
Map<String, int> camera_cache;
// very useful for when you need to ask assimp for the bone mesh
Map<const aiNode *, Node *> assimp_node_map;
Map<String, Ref<Image>> path_to_image_cache;
// Generation 3 - determinisitic iteration
// to lower potential recursion errors
List<const aiNode *> nodes;
Map<const aiNode *, Node3D *> flat_node_map;
AnimationPlayer *animation_player;
// Generation 3 - deterministic armatures
// list of armature nodes - flat and simple to parse
// assimp node, node in godot
List<aiNode *> armature_nodes;
Map<const aiNode *, Skeleton3D *> armature_skeletons;
Map<aiBone *, Skeleton3D *> 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<aiBone *> bone_stack;
// EditorSceneImporter::ImportFlags
uint32_t import_flags;
};
struct AssimpImageData {
Ref<Image> raw_image;
Ref<ImageTexture> texture;
aiTextureMapMode map_mode[2];
};
/** 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,
Skeleton3D *_skeleton,
Node3D *_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) {}
Transform node_transform;
Skeleton3D *skeleton = nullptr;
Node3D *new_node = nullptr;
String node_name;
aiNode *assimp_node = nullptr;
Node *parent_node = nullptr;
aiBone *bone = nullptr;
};
} // namespace AssimpImporter
#endif // EDITOR_SCENE_IMPORT_STATE_H

View file

@ -1,463 +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 <assimp/SceneCombiner.h>
#include <assimp/cexport.h>
#include <assimp/cimport.h>
#include <assimp/matrix4x4.h>
#include <assimp/pbrmaterial.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/Logger.hpp>
#include <string>
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, Color *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<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return Ref<Animation>();
}
/**
* 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 != nullptr) {
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<String> 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<String> exts;
ImageLoader::get_recognized_extensions(&exts);
Vector<String> 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<ImageTexture> texture) {
ERR_FAIL_COND(texture.is_null());
ERR_FAIL_COND(map_mode == nullptr);
// FIXME: Commented out during Vulkan port.
/*
aiTextureMapMode tex_mode = map_mode[0];
int32_t flags = Texture2D::FLAGS_DEFAULT;
if (tex_mode == aiTextureMapMode_Wrap) {
//Default
} else if (tex_mode == aiTextureMapMode_Clamp) {
flags = flags & ~Texture2D::FLAG_REPEAT;
} else if (tex_mode == aiTextureMapMode_Mirror) {
flags = flags | Texture2D::FLAG_MIRRORED_REPEAT;
}
texture->set_flags(flags);
*/
}
/**
* Load or load from cache image :)
*/
static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path) {
Map<String, Ref<Image>>::Element *match = state.path_to_image_cache.find(p_path);
// if our cache contains this image then don't bother
if (match) {
return match->get();
}
Vector<String> split_path = p_path.get_basename().split("*");
if (split_path.size() == 2) {
size_t texture_idx = split_path[1].to_int();
ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
aiTexture *tex = p_scene->mTextures[texture_idx];
String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
filename = filename.get_file();
print_verbose("Open Asset Import: Loading embedded texture " + filename);
if (tex->mHeight == 0) {
if (tex->CheckFormat("png")) {
ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, Ref<Image>());
Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, img);
return img;
} else if (tex->CheckFormat("jpg")) {
ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, Ref<Image>());
Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, img);
return img;
} else if (tex->CheckFormat("dds")) {
ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
}
} else {
Ref<Image> img;
img.instance();
PackedByteArray arr;
uint32_t size = tex->mWidth * tex->mHeight;
arr.resize(size);
memcpy(arr.ptrw(), tex->pcData, size);
ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
//ARGB8888 to RGBA8888
for (int32_t i = 0; i < arr.size() / 4; i++) {
arr.ptrw()[(4 * i) + 3] = arr[(4 * i) + 0];
arr.ptrw()[(4 * i) + 0] = arr[(4 * i) + 1];
arr.ptrw()[(4 * i) + 1] = arr[(4 * i) + 2];
arr.ptrw()[(4 * i) + 2] = arr[(4 * i) + 3];
}
img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, img);
return img;
}
return Ref<Image>();
} else {
Ref<Texture2D> texture = ResourceLoader::load(p_path);
ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
Ref<Image> image = texture->get_data();
ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, image);
return image;
}
return Ref<Image>();
}
/* create texture from assimp data, if found in path */
static bool CreateAssimpTexture(
AssimpImporter::ImportState &state,
aiString texture_path,
String &filename,
String &path,
AssimpImageData &image_state) {
filename = get_raw_string_from_assimp(texture_path);
path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
find_texture_path(state.path, path, found);
if (found) {
image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
if (image_state.raw_image.is_valid()) {
image_state.texture.instance();
image_state.texture->create_from_image(image_state.raw_image);
// FIXME: Commented out during Vulkan port.
//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, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
}
return false;
}
};
#endif // IMPORT_UTILS_IMPORTER_ASSIMP_H

View file

@ -1,58 +0,0 @@
/*************************************************************************/
/* register_types.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 "register_types.h"
#include "editor/editor_node.h"
#include "editor_scene_importer_assimp.h"
#ifdef TOOLS_ENABLED
static void _editor_init() {
Ref<EditorSceneImporterAssimp> import_assimp;
import_assimp.instance();
ResourceImporterScene::get_singleton()->add_importer(import_assimp);
}
#endif
void register_assimp_types() {
#ifdef TOOLS_ENABLED
ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR);
ClassDB::register_class<EditorSceneImporterAssimp>();
ClassDB::set_current_api(prev_api);
EditorNode::add_init_callback(_editor_init);
#endif
}
void unregister_assimp_types() {
}

View file

@ -1,37 +0,0 @@
/*************************************************************************/
/* register_types.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 ASSIMP_REGISTER_TYPES_H
#define ASSIMP_REGISTER_TYPES_H
void register_assimp_types();
void unregister_assimp_types();
#endif // ASSIMP_REGISTER_TYPES_H

18
thirdparty/README.md vendored
View file

@ -6,24 +6,6 @@ readability.
Subcategories (`###` level) where needed are separated by a single empty line.
## assimp
- Upstream: http://github.com/assimp/assimp
- Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
- License: BSD-3-Clause
Files extracted from upstream source:
- Run `cmake .` in root folder to generate files
- `code/{CApi,Common,FBX,Material,PostProcessing}/`
- `contrib/utf8cpp/source/`
- `include/`
- `revision.h`
- `CREDITS` and `LICENSE` files
- `rm -f code/Common/ZipArchiveIOSystem.cpp include/assimp/ZipArchiveIOSystem.h
include/assimp/irrXMLWrapper.h`
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal

View file

@ -1,183 +0,0 @@
===============================================================
Open Asset Import Library (Assimp)
Developers and Contributors
===============================================================
The following is a non-exhaustive list of all constributors over the years.
If you think your name should be listed here, drop us a line and we'll add you.
- Alexander Gessler,
3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
- Thomas Schulze,
X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
- Kim Kulling,
Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
- R.Schmidt,
Linux build, eclipse support.
- Matthias Gubisch,
Assimp.net
Visual Studio 9 support, bugfixes.
- Mark Sibly
B3D-Loader, Assimp testing
- Jonathan Klein
Ogre Loader, VC2010 fixes and CMake fixes.
- Sebastian Hempel,
PyAssimp (first version)
Compile-Bugfixes for mingw, add environment for static library support in make.
- Jonathan Pokrass
Supplied a bugfix concerning the scaling in the md3 loader.
- Andrew Galante,
Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
- Andreas Nagel
First Assimp testing & verification under Windows Vista 64 Bit.
- Marius Schr<68>der
Allowed us to use many of his models for screenshots and testing.
- Christian Schubert
Supplied various XFiles for testing purposes.
- Tizian Wieland
Searched the web for hundreds of test models for internal use
- John Connors
Supplied patches for linux and SCons.
- T. R.
The GUY who performed some of the CSM mocaps.
- Andy Maloney
Contributed fixes for the documentation and the doxygen markup
- Zhao Lei
Contributed several bugfixes fixing memory leaks and improving float parsing
- sueastside
Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
- Tobias Rittig
Collada testing with Cinema 4D
- Brad Grantham
Improvements in OpenGL-Sample.
- Robert Ramirez
Add group loading feature to Obj-Loader.
- Chris Maiwald
Many bugreports, improving Assimp's portability, regular testing & feedback.
- Stepan Hrbek
Bugreport and fix for a obj-materialloader crash.
- David Nadlinger
D bindings, CMake install support.
- Dario Accornero
Contributed several patches regarding Mac OS/XCode targets, bug reports.
- Martin Walser (Samhayne)
Contributed the 'SimpleTexturedOpenGl' sample.
- Matthias Fauconneau
Contributed a fix for the Q3-BSP loader.
- Jørgen P. Tjernø
Contributed updated and improved xcode workspaces
- drparallax
Contributed the /samples/SimpleAssimpViewX sample
- Carsten Fuchs
Contributed a fix for the Normalize method in aiQuaternion.
- dbburgess
Contributes a Android-specific build issue: log the hardware architecture for ARM.
- alfiereinre7
Contributes a obj-fileparser fix: missing tokens in the obj-token list.
- Roman Kharitonov
Contributes a fix for the configure script environment.
- Ed Diana
Contributed AssimpDelphi (/port/AssimpDelphi).
- rdb
Contributes a bundle of fixes and improvements for the bsp-importer.
- Mick P
For contributing the De-bone postprocessing step and filing various bug reports.
- Rosen Diankov
Contributed patches to build assimp debian packages using cmake.
- Mark Page
Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
- IOhannes
Contributed the Debian build fixes ( architecture macro ).
- gellule
Several LWO and LWS fixes (pivoting).
- Marcel Metz
GCC/Linux fixes for the SimpleOpenGL sample.
- Brian Miller
Bugfix for a compiler fix for iOS on arm.
- Séverin Lemaignan
Rewrite of PyAssimp, distutils and Python3 support
- albert-wang
Bugfixes for the collada parser
- Ya ping Jin
Bugfixes for uv-tanget calculation.
- Jonne Nauha
Ogre Binary format support
- Filip Wasil, Tieto Poland Sp. z o.o.
Android JNI asset extraction support
- Richard Steffen
Contributed ExportProperties interface
Contributed X File exporter
Contributed Step (stp) exporter
- Thomas Iorns (mesilliac)
Initial FBX Export support
For a more detailed list just check: https://github.com/assimp/assimp/network/members
========
Patreons
========
Huge thanks to our Patreons!
- migenius
- Marcus
- Cort
- elect
- Steffen
===================
Commercial Sponsors
===================
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support

View file

@ -1,78 +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.
******************************************************************************
AN EXCEPTION applies to all files in the ./test/models-nonbsd folder.
These are 3d models for testing purposes, from various free sources
on the internet. They are - unless otherwise stated - copyright of
their respective creators, which may impose additional requirements
on the use of their work. For any of these models, see
<model-name>.source.txt for more legal information. Contact us if you
are a copyright holder and believe that we credited you inproperly or
if you don't want your files to appear in the repository.
******************************************************************************
Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
http://code.google.com/p/poly2tri/
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Poly2Tri nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -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 <assimp/SceneCombiner.h>
#include "Common/ScenePrivate.h"
#include <assimp/Exporter.hpp>
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

View file

@ -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;
}
}

View file

@ -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 <assimp/cfileio.h>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
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

View file

@ -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 <assimp/cimport.h>
#include <assimp/LogStream.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/GenericProperty.h>
#include <assimp/Exceptional.h>
#include <assimp/BaseImporter.h>
#include "CApi/CInterfaceIOWrapper.h"
#include "Importer.h"
#include "ScenePrivate.h"
#include <list>
// ------------------------------------------------------------------------------------------------
#ifndef ASSIMP_BUILD_SINGLETHREADED
# include <thread>
# include <mutex>
#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<s1.callback&&s0.user<s1.user;
}
};
typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
typedef std::list<Assimp::LogStream*> 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<std::mutex> 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<const PropertyMap*>(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<ScenePrivateData*>( 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<const PropertyMap*>(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<ScenePrivateData*>( 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<aiPropertyStore*>( new PropertyMap() );
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
{
delete reinterpret_cast<PropertyMap*>(p);
}
// ------------------------------------------------------------------------------------------------
// Importer::SetPropertyInteger
ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
SetGenericProperty<int>(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<PropertyMap*>(p);
SetGenericProperty<ai_real>(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<PropertyMap*>(p);
SetGenericProperty<std::string>(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<PropertyMap*>(p);
SetGenericProperty<aiMatrix4x4>(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;
}
// ------------------------------------------------------------------------------------------------

View file

@ -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 <assimp/BaseImporter.h>
#include <assimp/ParsingUtils.h>
#include "FileSystemFilter.h"
#include "Importer.h"
#include <assimp/ByteSwapper.h>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/importerdesc.h>
#include <ios>
#include <list>
#include <memory>
#include <sstream>
#include <cctype>
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<float>( 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<aiScene> 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<std::string>& 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<IOStream> pStream (pIOHandler->Open(pFile));
if (pStream.get() ) {
// read 200 characters from the file
std::unique_ptr<char[]> _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<char>( ::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<char>( 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<char>);
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<const char*>(_magic);
std::unique_ptr<IOStream> 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 <utf8/utf8.h>
#else
# include "../contrib/utf8cpp/source/utf8.h"
#endif
// ------------------------------------------------------------------------------------------------
// Convert to UTF8 data
void BaseImporter::ConvertToUTF8(std::vector<char>& 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<char> 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<unsigned char> 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<char>& 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<LoadRequest> requests;
// Base path
std::string pathBase;
// Id for next item
unsigned int next_id;
// Validation enabled state
bool validate;
};
typedef std::list<LoadRequest>::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 %%%");
}
}

View file

@ -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 <assimp/BaseImporter.h>
#include "BaseProcess.h"
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#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;
}

View file

@ -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 <map>
#include <assimp/GenericProperty.h>
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 <typename T>
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 <typename T>
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<KeyType, Base*> 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 <typename T>
void AddProperty( const char* name, T* in ){
AddProperty(name,(Base*)new THeapData<T>(in));
}
//! Add a static by-value property to the list
template <typename T>
void AddProperty( const char* name, T in ){
AddProperty(name,(Base*)new TStaticData<T>(in));
}
//! Get a heap property
template <typename T>
bool GetProperty( const char* name, T*& out ) const
{
THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
if(!t)
{
out = NULL;
return false;
}
out = t->data;
return true;
}
//! Get a static, by-value property
template <typename T>
bool GetProperty( const char* name, T& out ) const
{
TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
if(!t)return false;
out = t->data;
return true;
}
//! Remove a property of a specific type
void RemoveProperty( const char* name) {
SetGenericPropertyPtr<Base>(pmap,name,NULL);
}
private:
void AddProperty( const char* name, Base* data) {
SetGenericPropertyPtr<Base>(pmap,name,data);
}
Base* GetPropertyInternal( const char* name) const {
return GetGenericProperty<Base*>(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

View file

@ -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 <assimp/Bitmap.h>
#include <assimp/texture.h>
#include <assimp/IOStream.hpp>
#include <assimp/ByteSwapper.h>
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<typename T>
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);
}
}
}

View file

@ -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 <assimp/CreateAnimMesh.h>
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

View file

@ -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 <assimp/ai_assert.h>
#include <assimp/DefaultIOStream.h>
#include <sys/types.h>
#include <sys/stat.h>
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);
}
}
// ----------------------------------------------------------------------------------

View file

@ -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 <assimp/StringComparison.h>
#include <assimp/DefaultIOSystem.h>
#include <assimp/DefaultIOStream.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include <stdlib.h>
#ifdef __unix__
#include <sys/param.h>
#include <stdlib.h>
#endif
#ifdef _WIN32
#include <windows.h>
#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_t>(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_t>(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;
}
// ------------------------------------------------------------------------------------------------

View file

@ -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 <assimp/StringUtils.h>
#include <assimp/DefaultIOSystem.h>
#include <assimp/NullLogger.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include <iostream>
#include <stdio.h>
#ifndef ASSIMP_BUILD_SINGLETHREADED
# include <thread>
# include <mutex>
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<std::mutex> 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<std::mutex> 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<std::mutex> 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

View file

@ -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 <assimp/ProgressHandler.hpp>
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

View file

@ -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 <assimp/BlobIOSystem.h>
#include <assimp/SceneCombiner.h>
#include <assimp/DefaultIOSystem.h>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/Exceptional.h>
#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 <memory>
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<Exporter::ExportFormatEntry> 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<IOSystem> old = pimpl->mIOSystem;
BlobIOSystem* blobio = new BlobIOSystem();
pimpl->mIOSystem = std::shared_ptr<IOSystem>( 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<aiScene> 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<FlipUVsProcess*>(p)
&& !dynamic_cast<FlipWindingOrderProcess*>(p)
&& !dynamic_cast<MakeLeftHandedProcess*>(p)) {
if (dynamic_cast<PretransformVertices*>(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<ExportFormatEntry>::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<int>(mIntProperties, szName,iValue);
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) {
return SetGenericProperty<ai_real>(mFloatProperties, szName,iValue);
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) {
return SetGenericProperty<std::string>(mStringProperties, szName,value);
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
const std::string ExportProperties::GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const {
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName,
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties::HasPropertyInteger(const char* szName) const {
return HasGenericProperty<int>(mIntProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties::HasPropertyBool(const char* szName) const {
return HasGenericProperty<int>(mIntProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties::HasPropertyFloat(const char* szName) const {
return HasGenericProperty<ai_real>(mFloatProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties::HasPropertyString(const char* szName) const {
return HasGenericProperty<std::string>(mStringProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties::HasPropertyMatrix(const char* szName) const {
return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
}
#endif // !ASSIMP_BUILD_NO_EXPORT

View file

@ -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 <assimp/LogStream.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/DefaultIOSystem.h>
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

View file

@ -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 <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/fast_atof.h>
#include <assimp/ParsingUtils.h>
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
// <base>/something.lwo
// <base>/bar/something.lwo
// <base>/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

View file

@ -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 <assimp/ByteSwapper.h>
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

File diff suppressed because it is too large Load diff

View file

@ -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 <map>
#include <vector>
#include <string>
#include <assimp/matrix4x4.h>
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<KeyType, int> IntPropertyMap;
typedef std::map<KeyType, ai_real> FloatPropertyMap;
typedef std::map<KeyType, std::string> StringPropertyMap;
typedef std::map<KeyType, aiMatrix4x4> 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

View file

@ -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 <vector>
#include <assimp/BaseImporter.h>
// ------------------------------------------------------------------------------------------------
// 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<deleteList.size();++i){
delete deleteList[i];
deleteList[i]=nullptr;
}//for
}
} // namespace Assimp

View file

@ -1,229 +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 PolyTools.h, various utilities for our dealings with arbitrary polygons */
#ifndef AI_POLYTOOLS_H_INCLUDED
#define AI_POLYTOOLS_H_INCLUDED
#include <assimp/material.h>
#include <assimp/ai_assert.h>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <int ofs_x, int ofs_y, int ofs_z, typename TReal>
inline void NewellNormal (aiVector3t<TReal>& 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<TReal>(sum_yz,sum_zx,sum_xy);
}
} // ! Assimp
#endif

View file

@ -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
}
}

View file

@ -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 <assimp/RemoveComments.h>
#include <assimp/ParsingUtils.h>
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

View file

@ -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 <assimp/SGSpatialSort.h>
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<unsigned int>& 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<Entry>::const_iterator it = mPositions.begin() + index;
std::vector<Entry>::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;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -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 <assimp/ai_assert.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
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. );
}
}

View file

@ -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 <assimp/defs.h>
#include <stddef.h>
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

View file

@ -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 <assimp/ai_assert.h>
#include <assimp/scene.h>
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<ScenePrivateData*>(in->mPrivate);
}
inline
const ScenePrivateData* ScenePriv(const aiScene* in) {
ai_assert( nullptr != in );
if ( nullptr == in ) {
return nullptr;
}
return static_cast<const ScenePrivateData*>(in->mPrivate);
}
} // Namespace Assimp
#endif // AI_SCENEPRIVATE_H_INCLUDED

View file

@ -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 <assimp/scene.h>
#include <assimp/SkeletonMeshBuilder.h>
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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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;
}

View file

@ -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 <assimp/SpatialSort.h>
#include <assimp/ai_assert.h>
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<const char*> (pPositions);
const aiVector3D* vec = reinterpret_cast<const aiVector3D*> (tempPointer + a * pElementOffset);
// store position by index and distance
ai_real distance = *vec * mPlaneNormal;
mPositions.push_back( Entry( static_cast<unsigned int>(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<unsigned int>& 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<Entry>::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<BinFloat const &>(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<unsigned int>& 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<Entry>::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<unsigned int>& 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]<mPositions.size());
}
#endif
return t;
}

View file

@ -1,407 +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.cpp
/// Implementation of the SplitByBoneCount postprocessing step
// internal headers of the post-processing framework
#include "SplitByBoneCountProcess.h"
#include <assimp/postprocess.h>
#include <assimp/DefaultLogger.hpp>
#include <limits>
#include <assimp/TinyFormatter.h>
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<aiMesh*> meshes;
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
{
aiMesh* srcMesh = pScene->mMeshes[a];
std::vector<aiMesh*> 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<unsigned int>(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<unsigned int>(meshes.size()));
meshes.push_back( srcMesh);
}
}
// rebuild the scene's mesh array
pScene->mNumMeshes = static_cast<unsigned int>(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<aiMesh*>& 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<unsigned int, float> BoneWeight;
std::vector< std::vector<BoneWeight> > 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<bool> isFaceHandled( pMesh->mNumFaces, false);
while( numFacesHandled < pMesh->mNumFaces )
{
// which bones are used in the current submesh
unsigned int numBones = 0;
std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
// indices of the faces which are going to go into this submesh
std::vector<unsigned int> 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<unsigned int> 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<BoneWeight>& 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<unsigned int>(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<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::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<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::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<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex];
for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b )
{
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
if( newBoneIndex != std::numeric_limits<unsigned int>::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<BoneWeight>& 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<unsigned int>::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<unsigned int> newMeshList;
for( unsigned int a = 0; a < pNode->mNumMeshes; ++a)
{
unsigned int srcIndex = pNode->mMeshes[a];
const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex];
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
}
delete [] pNode->mMeshes;
pNode->mNumMeshes = static_cast<unsigned int>(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]);
}
}

View file

@ -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 <vector>
#include "BaseProcess.h"
#include <assimp/mesh.h>
#include <assimp/scene.h>
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<aiMesh*>& 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<unsigned int> > mSubMeshIndices;
};
} // end of namespace Assimp
#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC

View file

@ -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 <assimp/StandardShapes.h>
#include <assimp/StringComparison.h>
#include <stddef.h>
#include <assimp/Defines.h>
#include <assimp/mesh.h>
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<aiVector3D>& 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<aiVector3D>& 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<aiVector3D>&))
{
std::vector<aiVector3D> 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<aiVector3D>&, bool))
{
std::vector<aiVector3D> 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<aiVector3D>&))
{
std::vector<aiVector3D> temp;
(*GenerateFunc)(num,temp);
return MakeMesh(temp,3);
}
// ------------------------------------------------------------------------------------------------
// Build an incosahedron with points.magnitude == 1
unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& 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<aiVector3D>& 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<aiVector3D>& 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<aiVector3D>& 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<aiVector3D>& 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<aiVector3D>& 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<tess;++i)
Subdivide(positions);
}
// ------------------------------------------------------------------------------------------------
// Build a cone
void StandardShapes::MakeCone(ai_real height,ai_real radius1,
ai_real radius2,unsigned int tess,
std::vector<aiVector3D>& 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<aiVector3D>& 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

View file

@ -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 <assimp/LogStream.hpp>
#include <ostream>
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

View file

@ -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 <assimp/Subdivision.h>
#include <assimp/SceneCombiner.h>
#include <assimp/SpatialSort.h>
#include <assimp/Vertex.h>
#include <assimp/ai_assert.h>
#include "PostProcessing/ProcessHelper.h"
#include <stdio.h>
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<unsigned int> UIntVector;
typedef std::map<uint64_t,Edge> 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 id0<id1 to identify an edge - else two hashes would refer
// to the same edge.
// ---------------------------------------------------------------------------
#define MAKE_EDGE_HASH(id0,id1) (eh_tmp0__=id0,eh_tmp1__=id1,\
(eh_tmp0__<eh_tmp1__?std::swap(eh_tmp0__,eh_tmp1__):mydummy()),(uint64_t)eh_tmp0__^((uint64_t)eh_tmp1__<<32u))
#define INIT_EDGE_HASH_TEMPORARIES()\
unsigned int eh_tmp0__, eh_tmp1__;
private:
void InternSubdivide (const aiMesh* const * smesh,
size_t nmesh,aiMesh** out, unsigned int num);
};
// ------------------------------------------------------------------------------------------------
// Construct a subdivider of a specific type
Subdivider* Subdivider::Create (Algorithm algo)
{
switch (algo)
{
case CATMULL_CLARKE:
return new CatmullClarkSubdivider();
};
ai_assert(false);
return NULL; // shouldn't happen
}
// ------------------------------------------------------------------------------------------------
// Call the Catmull Clark subdivision algorithm for one mesh
void CatmullClarkSubdivider::Subdivide (
aiMesh* mesh,
aiMesh*& out,
unsigned int num,
bool discard_input
)
{
ai_assert(mesh != out);
Subdivide(&mesh,1,&out,num,discard_input);
}
// ------------------------------------------------------------------------------------------------
// Call the Catmull Clark subdivision algorithm for multiple meshes
void CatmullClarkSubdivider::Subdivide (
aiMesh** smesh,
size_t nmesh,
aiMesh** out,
unsigned int num,
bool discard_input
)
{
ai_assert( NULL != smesh );
ai_assert( NULL != out );
// course, both regions may not overlap
ai_assert(smesh<out || smesh+nmesh>out+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<aiMesh*> inmeshes;
std::vector<aiMesh*> outmeshes;
std::vector<unsigned int> 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<unsigned int>(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<unsigned int,unsigned int> IntPair;
std::vector<IntPair> 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<Vertex> 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<float>(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<unsigned int>(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<bool,Vertex> TouchedOVertex;
std::vector<TouchedOVertex > 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<float>(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<aiMesh*> tmp(nmesh);
InternSubdivide (out,nmesh,&tmp.front(),num-1);
for (size_t i = 0; i < nmesh; ++i) {
delete out[i];
out[i] = tmp[i];
}
}
}

View file

@ -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 <algorithm>
#include <assimp/ai_assert.h>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
const std::vector<aiVectorKey>* _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 <class T>
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<unsigned int>(objPos->size()-1)) ).mTime;
d1 = targetObjPos->at( std::min ( nextTargetObjPos, static_cast<unsigned int>(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<aiVectorKey>* _targetPositions)
{
ai_assert(NULL != _targetPositions);
targetPositions = _targetPositions;
}
// ------------------------------------------------------------------------------------------------
void TargetAnimationHelper::SetMainAnimationChannel (
const std::vector<aiVectorKey>* _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<aiVectorKey>* distanceTrack)
{
ai_assert(NULL != targetPositions && NULL != distanceTrack);
// TODO: in most cases we won't need the extra array
std::vector<aiVectorKey> real;
std::vector<aiVectorKey>* 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;
}
}

View file

@ -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 <assimp/anim.h>
#include <vector>
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<aiVectorKey>* _objPos,
const std::vector<aiVectorKey>* _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<aiVectorKey>* objPos,*targetObjPos;
unsigned int nextObjPos, nextTargetObjPos;
std::vector<aiVectorKey> 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<aiVectorKey>* targetPositions);
// ------------------------------------------------------------------
/** Sets the main animation channel
*
* @param objectPositions Translation channel */
void SetMainAnimationChannel ( const
std::vector<aiVectorKey>* 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<aiVectorKey>* distanceTrack );
private:
const std::vector<aiVectorKey>* targetPositions,*objectPositions;
aiVector3D fixedMain;
};
} // ! end namespace Assimp
#endif // include guard

View file

@ -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 <assimp/version.h>
#include <assimp/scene.h>
#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<Assimp::ScenePrivateData*>( mPrivate );
}

View file

@ -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 <assimp/mesh.h>
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;
}

View file

@ -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 <assimp/types.h>
#include <assimp/ai_assert.h>
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

View file

@ -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 <assimp/LogStream.hpp>
#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

View file

@ -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
(<tt>.assbin</tt>) is fast loading. Optional deflate compression helps reduce file size. The XML
flavour, <tt>.assxml</tt> or simply .xml, is just a plain-to-xml conversion of aiScene.
ASSBIN is Assimp's binary interchange format. assimp_cmd (<tt>&lt;root&gt;/tools/assimp_cmd</tt>) 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 <tt>&lt;root&gt;/doc/AssXML_Scheme.xml</tt>. 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 <tt>&lt;root&gt;/code/assbin_chunks.h</tt> header contains some magic constants
for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found
in <tt>&lt;root&gt;/tools/assimp_cmd/WriteDumb.cpp</tt> (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

View file

@ -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 <assimp/scene.h>
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;
}
}

View file

@ -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

View file

@ -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 <assimp/defs.h>
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

View file

@ -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<KeyTimeList::value_type>())) {
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<const Connection*>& 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<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(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<const Connection*>& 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<const AnimationCurve*>(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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
nodes.reserve(conns.size());
for(const Connection* con : conns) {
// link should not go to a property
if (con->PropertyName().length()) {
continue;
}
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<const AnimationCurveNode*>(ob);
if(!anim) {
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
continue;
}
if(target_prop_whitelist) {
const char* s = anim->TargetProperty().c_str();
bool ok = false;
for (size_t i = 0; i < whitelist_size; ++i) {
if (!strcmp(s, target_prop_whitelist[i])) {
ok = true;
break;
}
}
if(!ok) {
continue;
}
}
nodes.push_back(anim);
}
return nodes; // 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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
layers.reserve(conns.size());
for(const Connection* con : conns) {
// link should not go to a property
if (con->PropertyName().length()) {
continue;
}
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<const AnimationLayer*>(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

View file

@ -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 <assimp/defs.h>
#include <stdint.h>
#include <assimp/Exceptional.h>
#include <assimp/ByteSwapper.h>
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<size_t>(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<const uint64_t*>(cursor)*/;
::memcpy( &dword, cursor, sizeof( uint64_t ) );
AI_SWAP8(dword);
cursor += k_to_read;
return dword;
}
// ------------------------------------------------------------------------------------------------
uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
if(Offset(cursor, end) < sizeof( uint8_t ) ) {
TokenizeError("cannot ReadByte, out of bounds",input, cursor);
}
uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
::memcpy( &word, cursor, sizeof( uint8_t ) );
++cursor;
return word;
}
// ------------------------------------------------------------------------------------------------
unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input,
const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
const uint32_t len_len = long_length ? 4 : 1;
if(Offset(cursor, end) < len_len) {
TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
}
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
if (Offset(cursor, end) < length) {
TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
}
sbegin_out = cursor;
cursor += length;
send_out = cursor;
if(!allow_null) {
for (unsigned int i = 0; i < length; ++i) {
if(sbegin_out[i] == '\0') {
TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
}
}
}
return length;
}
// ------------------------------------------------------------------------------------------------
void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
if(Offset(cursor, end) < 1) {
TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
}
const char type = *cursor;
sbegin_out = cursor++;
switch(type)
{
// 16 bit int
case 'Y':
cursor += 2;
break;
// 1 bit bool flag (yes/no)
case 'C':
cursor += 1;
break;
// 32 bit int
case 'I':
// <- fall through
// float
case 'F':
cursor += 4;
break;
// double
case 'D':
cursor += 8;
break;
// 64 bit int
case 'L':
cursor += 8;
break;
// note: do not write cursor += ReadWord(...cursor) as this would be UB
// raw binary data
case 'R':
{
const uint32_t length = ReadWord(input, cursor, end);
cursor += length;
break;
}
case 'b':
// TODO: what is the 'b' type code? Right now we just skip over it /
// take the full range we could get
cursor = end;
break;
// array of *
case 'f':
case 'd':
case 'l':
case 'i':
case 'c': {
const uint32_t length = ReadWord(input, cursor, end);
const uint32_t encoding = ReadWord(input, cursor, end);
const uint32_t comp_len = ReadWord(input, cursor, end);
// compute length based on type and check against the stored value
if(encoding == 0) {
uint32_t stride = 0;
switch(type)
{
case 'f':
case 'i':
stride = 4;
break;
case 'd':
case 'l':
stride = 8;
break;
case 'c':
stride = 1;
break;
default:
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

View file

@ -1,86 +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 FBXCommon.h
* Some useful constants and enums for dealing with FBX files.
*/
#ifndef AI_FBXCOMMON_H_INC
#define AI_FBXCOMMON_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
namespace Assimp {
namespace FBX
{
const std::string NULL_RECORD = { // 13 null bytes
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
}; // who knows why
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit
// rotation order. We'll probably use EulerXYZ for everything
enum RotOrder {
RotOrder_EulerXYZ = 0,
RotOrder_EulerXZY,
RotOrder_EulerYZX,
RotOrder_EulerYXZ,
RotOrder_EulerZXY,
RotOrder_EulerZYX,
RotOrder_SphericXYZ,
RotOrder_MAX // end-of-enum sentinel
};
// transformation inheritance method. Most of the time RSrs
enum TransformInheritance {
TransformInheritance_RrSs = 0,
TransformInheritance_RSrs,
TransformInheritance_Rrs,
TransformInheritance_MAX // end-of-enum sentinel
};
}
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXCOMMON_H_INC

View file

@ -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 <map>
#include <set>
//
#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 <unordered_map>
# include <unordered_set>
# 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

File diff suppressed because it is too large Load diff

View file

@ -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 <assimp/anim.h>
#include <assimp/material.h>
#include <assimp/light.h>
#include <assimp/texture.h>
#include <assimp/camera.h>
#include <assimp/StringComparison.h>
#include <unordered_map>
#include <unordered_set>
struct aiScene;
struct aiNode;
struct aiMaterial;
struct morphKeyData {
std::vector<unsigned int> values;
std::vector<float> weights;
};
typedef std::map<int64_t, morphKeyData*> 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<aiNode*>& output_nodes, std::vector<aiNode*>& 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<unsigned int>
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------
std::vector<unsigned int> 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<unsigned int>
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<unsigned int>::max() */
static_cast<unsigned int>(-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<unsigned int> *outputVertStartIndices = NULL);
// lookup
static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
// ------------------------------------------------------------------------------------------------
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &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<const AnimationCurveNode*, const AnimationLayer*> LayerMap;
// XXX: better use multi_map ..
typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
// ------------------------------------------------------------------------------------------------
void ConvertAnimationStack(const AnimationStack& st);
// ------------------------------------------------------------------------------------------------
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node);
// ------------------------------------------------------------------------------------------------
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
const std::string& fixed_name,
const std::vector<const AnimationCurveNode*>& 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<const AnimationCurveNode*>& curves);
// ------------------------------------------------------------------------------------------------
aiNodeAnim* GenerateRotationNodeAnim(const std::string& name,
const Model& target,
const std::vector<const AnimationCurveNode*>& 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<const AnimationCurveNode*>& 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<const AnimationCurveNode*>& 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<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList;
typedef std::vector<KeyFrameList> KeyFrameListList;
// ------------------------------------------------------------------------------------------------
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& 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<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
int64_t start, int64_t stop,
double& maxTime,
double& minTime);
// ------------------------------------------------------------------------------------------------
void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
const LayerMap& /*layers*/,
int64_t start, int64_t stop,
double& maxTime,
double& minTime);
// ------------------------------------------------------------------------------------------------
void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& 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<aiMesh*> meshes;
std::vector<aiMaterial*> materials;
std::vector<aiAnimation*> animations;
std::vector<aiLight*> lights;
std::vector<aiCamera*> cameras;
std::vector<aiTexture*> textures;
using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
MaterialMap materials_converted;
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
VideoMap textures_converted;
using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
MeshMap meshes_converted;
// fixed node name -> which trafo chain components have animations?
using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
NodeAnimBitMap node_anim_chain_bits;
// number of nodes with the same name
using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
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<const std::string, aiBone *> 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<aiBone*>& bones);
void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode*> &node_stack );
static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
};
}
}
#endif // INCLUDED_AI_FBX_CONVERTER_H

View file

@ -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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
for(const Connection* con : conns) {
const Model* const mod = ProcessSimpleConnection<Model>(*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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
clusters.reserve(conns.size());
for(const Connection* con : conns) {
const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
blendShapeChannels.reserve(conns.size());
for (const Connection* con : conns) {
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
shapeGeometries.reserve(conns.size());
for (const Connection* con : conns) {
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
if (sg) {
shapeGeometries.push_back(sg);
continue;
}
}
}
// ------------------------------------------------------------------------------------------------
BlendShapeChannel::~BlendShapeChannel()
{
}
// ------------------------------------------------------------------------------------------------
}
}
#endif

View file

@ -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 <memory>
#include <functional>
#include <map>
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<size_t>(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<const PropertyTable> 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<const PropertyTable>()));
return;
}
std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
//double v = PropertyGet<float>( *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<const PropertyTable> props = std::make_shared<const PropertyTable>(
*Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(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<const AnimationStack*>& 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<AnimationStack>())) {
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<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const
{
std::vector<const Connection*> temp;
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
conns.equal_range(id);
temp.reserve(std::distance(range.first,range.second));
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
temp.push_back((*it).second);
}
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
return temp; // NRVO should handle this
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
const ConnectionMap& conns,
const char* const* classnames,
size_t count) const
{
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<const Connection*> temp;
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
conns.equal_range(id);
temp.reserve(std::distance(range.first,range.second));
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
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<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
obtype = nullptr;
break;
}
}
if(obtype) {
continue;
}
temp.push_back((*it).second);
}
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
return temp; // NRVO should handle this
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
{
return GetConnectionsSequenced(source, ConnectionsBySource());
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const
{
const char* arr[] = {classname};
return GetConnectionsBySourceSequenced(src, arr,1);
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
const char* const* classnames, size_t count) const
{
return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
const char* classname) const
{
const char* arr[] = {classname};
return GetConnectionsByDestinationSequenced(dest, arr,1);
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
{
return GetConnectionsSequenced(dest, ConnectionsByDestination());
}
// ------------------------------------------------------------------------------------------------
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
const char* const* classnames, size_t count) const
{
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
}
// ------------------------------------------------------------------------------------------------
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop,
const Document& doc)
: insertionOrder(insertionOrder)
, prop(prop)
, src(src)
, dest(dest)
, doc(doc)
{
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

File diff suppressed because it is too large Load diff

View file

@ -1,135 +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 FBXDocumentUtil.cpp
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
*/
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#include "FBXParser.h"
#include "FBXDocument.h"
#include "FBXUtil.h"
#include "FBXDocumentUtil.h"
#include "FBXProperties.h"
namespace Assimp {
namespace FBX {
namespace Util {
// ------------------------------------------------------------------------------------------------
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
void DOMError(const std::string& message, const Token& token)
{
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
}
// ------------------------------------------------------------------------------------------------
void DOMError(const std::string& message, const Element* element /*= NULL*/)
{
if(element) {
DOMError(message,element->KeyToken());
}
throw DeadlyImportError("FBX-DOM " + message);
}
// ------------------------------------------------------------------------------------------------
// print warning, do return
void DOMWarning(const std::string& message, const Token& token)
{
if(DefaultLogger::get()) {
ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token));
}
}
// ------------------------------------------------------------------------------------------------
void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
{
if(element) {
DOMWarning(message,element->KeyToken());
return;
}
if(DefaultLogger::get()) {
ASSIMP_LOG_WARN("FBX-DOM: " + message);
}
}
// ------------------------------------------------------------------------------------------------
// fetch a property table and the corresponding property template
std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
const std::string& templateName,
const Element &element,
const Scope& sc,
bool no_warn /*= false*/)
{
const Element* const Properties70 = sc["Properties70"];
std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
static_cast<const PropertyTable*>(NULL));
if(templateName.length()) {
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
if(it != doc.Templates().end()) {
templateProps = (*it).second;
}
}
if(!Properties70 || !Properties70->Compound()) {
if(!no_warn) {
DOMWarning("property table (Properties70) not found",&element);
}
if(templateProps) {
return templateProps;
}
else {
return std::make_shared<const PropertyTable>();
}
}
return std::make_shared<const PropertyTable>(*Properties70,templateProps);
}
} // !Util
} // !FBX
} // !Assimp
#endif

View file

@ -1,120 +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 FBXDocumentUtil.h
* @brief FBX internal utilities used by the DOM reading code
*/
#ifndef INCLUDED_AI_FBX_DOCUMENT_UTIL_H
#define INCLUDED_AI_FBX_DOCUMENT_UTIL_H
#include <assimp/defs.h>
#include <string>
#include <memory>
#include "FBXDocument.h"
struct Token;
struct Element;
namespace Assimp {
namespace FBX {
namespace Util {
/* DOM/Parse error reporting - does not return */
AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
// does return
void DOMWarning(const std::string& message, const Token& token);
void DOMWarning(const std::string& message, const Element* element = NULL);
// fetch a property table and the corresponding property template
std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
const std::string& templateName,
const Element &element,
const Scope& sc,
bool no_warn = false);
// ------------------------------------------------------------------------------------------------
template <typename T>
inline
const T* ProcessSimpleConnection(const Connection& con,
bool is_object_property_conn,
const char* name,
const Element& element,
const char** propNameOut = nullptr)
{
if (is_object_property_conn && !con.PropertyName().length()) {
DOMWarning("expected incoming " + std::string(name) +
" link to be an object-object connection, ignoring",
&element
);
return nullptr;
}
else if (!is_object_property_conn && con.PropertyName().length()) {
DOMWarning("expected incoming " + std::string(name) +
" link to be an object-property connection, ignoring",
&element
);
return nullptr;
}
if(is_object_property_conn && propNameOut) {
// note: this is ok, the return value of PropertyValue() is guaranteed to
// remain valid and unchanged as long as the document exists.
*propNameOut = con.PropertyName().c_str();
}
const Object* const ob = con.SourceObject();
if(!ob) {
DOMWarning("failed to read source object for incoming " + std::string(name) +
" link, ignoring",
&element);
return nullptr;
}
return dynamic_cast<const T*>(ob);
}
} //!Util
} //!FBX
} //!Assimp
#endif

View file

@ -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 <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <assimp/ai_assert.h>
#include <assimp/StringUtils.h> // ai_snprintf
#include <string>
#include <ostream>
#include <sstream> // ostringstream
#include <memory> // shared_ptr
namespace Assimp {
// AddP70<type> 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<Assimp::IOStream> 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<double>& 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());
// *<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<int32_t>& 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());
// *<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<double>& 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<int32_t>& 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<double>& 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<int32_t>& 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

View file

@ -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 <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
namespace Assimp {
namespace FBX {
class Node;
}
class FBX::Node {
public:
// TODO: accessors
std::string name; // node name
std::vector<FBX::FBXExportProperty> properties; // node properties
std::vector<FBX::Node> 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 <typename... More>
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 <typename T>
void AddProperty(T value) {
properties.emplace_back(value);
}
// convenience function to add multiple properties at once
template <typename T, typename... More>
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 <typename... More>
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 <typename... More>
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<Assimp::IOStream> 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 <typename T>
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<double>& 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<int32_t>& v,
Assimp::StreamWriterLE& s,
bool binary, int indent
);
private: // static helper functions
static void WritePropertyNodeAscii(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s,
int indent
);
static void WritePropertyNodeAscii(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s,
int indent
);
static void WritePropertyNodeBinary(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s
);
static void WritePropertyNodeBinary(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
);
};
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTNODE_H_INC

View file

@ -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 <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <string>
#include <vector>
#include <ostream>
#include <locale>
#include <sstream> // 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<int16_t*>(d))[0] = v;
}
FBXExportProperty::FBXExportProperty(int32_t v)
: type('I')
, data(4) {
uint8_t* d = data.data();
(reinterpret_cast<int32_t*>(d))[0] = v;
}
FBXExportProperty::FBXExportProperty(float v)
: type('F')
, data(4) {
uint8_t* d = data.data();
(reinterpret_cast<float*>(d))[0] = v;
}
FBXExportProperty::FBXExportProperty(double v)
: type('D')
, data(8) {
uint8_t* d = data.data();
(reinterpret_cast<double*>(d))[0] = v;
}
FBXExportProperty::FBXExportProperty(int64_t v)
: type('L')
, data(8) {
uint8_t* d = data.data();
(reinterpret_cast<int64_t*>(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<uint8_t>& r)
: type('R')
, data(r) {
// empty
}
FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va)
: type('i')
, data(4 * va.size() ) {
int32_t* d = reinterpret_cast<int32_t*>(data.data());
for (size_t i = 0; i < va.size(); ++i) {
d[i] = va[i];
}
}
FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va)
: type('l')
, data(8 * va.size()) {
int64_t* d = reinterpret_cast<int64_t*>(data.data());
for (size_t i = 0; i < va.size(); ++i) {
d[i] = va[i];
}
}
FBXExportProperty::FBXExportProperty(const std::vector<float>& va)
: type('f')
, data(4 * va.size()) {
float* d = reinterpret_cast<float*>(data.data());
for (size_t i = 0; i < va.size(); ++i) {
d[i] = va[i];
}
}
FBXExportProperty::FBXExportProperty(const std::vector<double>& va)
: type('d')
, data(8 * va.size()) {
double* d = reinterpret_cast<double*>(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<double*>(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<uint8_t*>(d))); return;
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(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<int32_t*>(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<int64_t*>(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<float*>(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<double*>(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<uint8_t*>(d))) { s << 'T'; }
else { s << 'F'; }
return;
case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return;
case 'I': s << *(reinterpret_cast<int32_t*>(d)); return;
case 'F': s << *(reinterpret_cast<float*>(d)); return;
case 'D': s << *(reinterpret_cast<double*>(d)); return;
case 'L': s << *(reinterpret_cast<int64_t*>(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<int32_t*>(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<int64_t*>(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<float*>(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<double*>(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

View file

@ -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 <assimp/types.h> // aiMatrix4x4
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
#include <ostream>
#include <type_traits> // 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 <bool>. 'C' seems to imply <char>,
// 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<uint8_t>& r);
explicit FBXExportProperty(const std::vector<int32_t>& va);
explicit FBXExportProperty(const std::vector<int64_t>& va);
explicit FBXExportProperty(const std::vector<double>& va);
explicit FBXExportProperty(const std::vector<float>& 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 <class T>
explicit FBXExportProperty(T v) : type('X') {
static_assert(std::is_void<T>::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<uint8_t> data;
};
} // Namespace FBX
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTPROPERTY_H_INC

File diff suppressed because it is too large Load diff

View file

@ -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 <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <vector>
#include <map>
#include <unordered_set>
#include <memory> // shared_ptr
#include <sstream> // 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<IOStream> outfile; // file to write to
std::vector<FBX::Node> connections; // connection storage
std::vector<int64_t> mesh_uids;
std::vector<int64_t> material_uids;
std::map<const aiNode*,int64_t> 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<Section> 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<const aiNode*>& limbnodes
);
void WriteModelNodes( // usually don't call this directly
StreamWriterLE& s,
const aiNode* node,
int64_t parent_uid,
const std::unordered_set<const aiNode*>& limbnodes,
std::vector<std::pair<std::string,aiVector3D>>& transform_chain
);
void WriteModelNode( // nor this
StreamWriterLE& s,
bool binary,
const aiNode* node,
int64_t node_uid,
const std::string& type,
const std::vector<std::pair<std::string,aiVector3D>>& 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<int64_t>& times,
const std::vector<float>& 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

View file

@ -1,164 +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 FBXImportSettings.h
* @brief FBX importer runtime configuration
*/
#ifndef INCLUDED_AI_FBX_IMPORTSETTINGS_H
#define INCLUDED_AI_FBX_IMPORTSETTINGS_H
namespace Assimp {
namespace FBX {
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
struct ImportSettings
{
ImportSettings()
: strictMode(true)
, readAllLayers(true)
, readAllMaterials(false)
, readMaterials(true)
, readTextures(true)
, readCameras(true)
, readLights(true)
, readAnimations(true)
, readWeights(true)
, preservePivots(true)
, optimizeEmptyAnimationCurves(true)
, useLegacyEmbeddedTextureNaming(false)
, removeEmptyBones( true )
, convertToMeters( false ) {
// empty
}
/** enable strict mode:
* - only accept fbx 2012, 2013 files
* - on the slightest error, give up.
*
* Basically, strict mode means that the fbx file will actually
* be validated. Strict mode is off by default. */
bool strictMode;
/** specifies whether all geometry layers are read and scanned for
* usable data channels. The FBX spec indicates that many readers
* will only read the first channel and that this is in some way
* the recommended way- in reality, however, it happens a lot that
* vertex data is spread among multiple layers. The default
* value for this option is true.*/
bool readAllLayers;
/** specifies whether all materials are read, or only those that
* are referenced by at least one mesh. Reading all materials
* may make FBX reading a lot slower since all objects
* need to be processed .
* This bit is ignored unless readMaterials=true*/
bool readAllMaterials;
/** import materials (true) or skip them and assign a default
* material. The default value is true.*/
bool readMaterials;
/** import embedded textures? Default value is true.*/
bool readTextures;
/** import cameras? Default value is true.*/
bool readCameras;
/** import light sources? Default value is true.*/
bool readLights;
/** import animations (i.e. animation curves, the node
* skeleton is always imported). Default value is true. */
bool readAnimations;
/** read bones (vertex weights and deform info).
* Default value is true. */
bool readWeights;
/** preserve transformation pivots and offsets. Since these can
* not directly be represented in assimp, additional dummy
* nodes will be generated. Note that settings this to false
* can make animation import a lot slower. The default value
* is true.
*
* The naming scheme for the generated nodes is:
* <OriginalName>_$AssimpFbx$_<TransformName>
*
* where <TransformName> is one of
* RotationPivot
* RotationOffset
* PreRotation
* PostRotation
* ScalingPivot
* ScalingOffset
* Translation
* Scaling
* Rotation
**/
bool preservePivots;
/** do not import animation curves that specify a constant
* values matching the corresponding node transformation.
* The default value is true. */
bool optimizeEmptyAnimationCurves;
/** use legacy naming for embedded textures eg: (*0, *1, *2)
*/
bool useLegacyEmbeddedTextureNaming;
/** Empty bones shall be removed
*/
bool removeEmptyBones;
/** Set to true to perform a conversion from cm to meter after the import
*/
bool convertToMeters;
};
} // !FBX
} // !Assimp
#endif

View file

@ -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 <assimp/MemoryIOWrapper.h>
#include <assimp/StreamReader.h>
#include <assimp/importerdesc.h>
#include <assimp/Importer.hpp>
namespace Assimp {
template <>
const char *LogFunctions<FBXImporter>::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<IOStream> 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<char> 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<Token>());
} catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
throw;
}
}
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER

View file

@ -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 <assimp/BaseImporter.h>
#include <assimp/LogAux.h>
#include "FBXImportSettings.h"
namespace Assimp {
// TinyFormatter.h
namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
// -------------------------------------------------------------------------------------------
/** Load the Autodesk FBX file format.
See http://en.wikipedia.org/wiki/FBX
*/
// -------------------------------------------------------------------------------------------
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter>
{
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

View file

@ -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 <assimp/ByteSwapper.h>
#include <algorithm> // 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<const Connection*>& 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<const Texture*>(ob);
if(!tex) {
const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
if(!layeredTexture) {
DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
continue;
}
const std::string& prop = con->PropertyName();
if (layeredTextures.find(prop) != layeredTextures.end()) {
DOMWarning("duplicate layered texture link: " + prop,&element);
}
layeredTextures[prop] = layeredTexture;
((LayeredTexture*)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<aiVector3D>(*props, "Scaling", ok);
if (ok) {
uvScaling.x = scaling.x;
uvScaling.y = scaling.y;
}
const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok);
if (ok) {
uvTrans.x = trans.x;
uvTrans.y = trans.y;
}
// resolve video links
if(doc.Settings().readTextures) {
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
for(const Connection* con : conns) {
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for texture link, ignoring",&element);
continue;
}
const Video* const video = dynamic_cast<const Video*>(ob);
if(video) {
media = video;
}
}
}
}
Texture::~Texture()
{
}
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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
for(size_t i = 0; i < conns.size();++i)
{
const Connection* con = conns.at(i);
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for texture link, ignoring",&element);
continue;
}
const Texture* const tex = dynamic_cast<const Texture*>(ob);
textures.push_back(tex);
}
}
// ------------------------------------------------------------------------------------------------
Video::Video(uint64_t id, const 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<uint64_t>(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<size_t>(token.end() - data) < 5) {
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
}
else if (*data != 'R') {
DOMWarning("video content is not raw binary data, ignoring", &element);
}
else {
// read number of elements
uint32_t len = 0;
::memcpy(&len, data + 1, sizeof(len));
AI_SWAP4(len);
contentLength = len;
content = new uint8_t[len];
::memcpy(content, data + 5, len);
}
} catch (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

View file

@ -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 <functional>
#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<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
for(const Connection* con : conns) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if(sk) {
skin = sk;
}
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) {
blendShapes.push_back(bsp);
}
}
}
// ------------------------------------------------------------------------------------------------
Geometry::~Geometry()
{
// empty
}
// ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& 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<aiVector3D> tempVerts;
ParseVectorDataArray(tempVerts,Vertices);
if(tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices");
}
std::vector<int> 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<size_t>(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<aiVector3D>& MeshGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
return m_normals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
return m_tangents;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
return m_binormals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
return m_faces;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const {
static const std::vector<aiVector2D> 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<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const {
static const std::vector<aiColor4D> 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<unsigned int>::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<int> 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 <typename T>
void ResolveVertexDataArray(std::vector<T>& 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<unsigned int>& mapping_counts,
const std::vector<unsigned int>& mapping_offsets,
const std::vector<unsigned int>& 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<T> 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<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
data_out.resize(vertex_count);
std::vector<int> 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<size_t>(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<T> 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<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
data_out.resize(vertex_count);
std::vector<int> 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<size_t>(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<aiVector3D>& 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<aiVector2D>& 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<aiColor4D>& 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<aiVector3D>& 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<aiVector3D>& 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<int>& 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<aiVector3D>& ShapeGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const {
return m_normals;
}
// ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& 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<aiVector3D>& LineGeometry::GetVertices() const {
return m_vertices;
}
// ------------------------------------------------------------------------------------------------
const std::vector<int>& LineGeometry::GetIndices() const {
return m_indices;
}
} // !FBX
} // !Assimp
#endif

View file

@ -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<const BlendShape*>& GetBlendShapes() const;
private:
const Skin* skin;
std::vector<const BlendShape*> blendShapes;
};
typedef std::vector<int> 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<aiVector3D>& GetVertices() const;
/** Get a list of all vertex normals or an empty array if
* no normals are specified. */
const std::vector<aiVector3D>& GetNormals() const;
/** Get a list of all vertex tangents or an empty array
* if no tangents are specified */
const std::vector<aiVector3D>& GetTangents() const;
/** Get a list of all vertex bi-normals or an empty array
* if no bi-normals are specified */
const std::vector<aiVector3D>& 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<unsigned int>& GetFaceIndexCounts() const;
/** Get a UV coordinate slot, returns an empty array if
* the requested slot does not exist. */
const std::vector<aiVector2D>& 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<aiColor4D>& 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<aiVector2D>& uv_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType );
void ReadVertexDataNormals( std::vector<aiVector3D>& normals_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType );
void ReadVertexDataColors( std::vector<aiColor4D>& colors_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType );
void ReadVertexDataTangents( std::vector<aiVector3D>& tangents_out, const Scope& source,
const std::string& MappingInformationType,
const std::string& ReferenceInformationType );
void ReadVertexDataBinormals( std::vector<aiVector3D>& 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<aiVector3D> m_vertices;
std::vector<unsigned int> m_faces;
mutable std::vector<unsigned int> m_facesVertexStartIndices;
std::vector<aiVector3D> m_tangents;
std::vector<aiVector3D> m_binormals;
std::vector<aiVector3D> m_normals;
std::string m_uvNames[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
std::vector<aiVector2D> m_uvs[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
std::vector<aiColor4D> m_colors[ AI_MAX_NUMBER_OF_COLOR_SETS ];
std::vector<unsigned int> m_mapping_counts;
std::vector<unsigned int> m_mapping_offsets;
std::vector<unsigned int> 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<aiVector3D>& GetVertices() const;
/** Get a list of all vertex normals or an empty array if
* no normals are specified. */
const std::vector<aiVector3D>& GetNormals() const;
/** Return list of vertex indices. */
const std::vector<unsigned int>& GetIndices() const;
private:
std::vector<aiVector3D> m_vertices;
std::vector<aiVector3D> m_normals;
std::vector<unsigned int> m_indices;
};
/**
* DOM class for FBX geometry of type "Line"
*/
class LineGeometry : public Geometry
{
public:
/** The class constructor */
LineGeometry(uint64_t id, const 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<aiVector3D>& GetVertices() const;
/** Return list of vertex indices. */
const std::vector<int>& GetIndices() const;
private:
std::vector<aiVector3D> m_vertices;
std::vector<int> m_indices;
};
}
}
#endif // INCLUDED_AI_FBX_MESHGEOMETRY_H

View file

@ -1,153 +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 FBXModel.cpp
* @brief Assimp::FBX::Model implementation
*/
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#include "FBXParser.h"
#include "FBXMeshGeometry.h"
#include "FBXDocument.h"
#include "FBXImporter.h"
#include "FBXDocumentUtil.h"
namespace Assimp {
namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: Object(id,element,name)
, shading("Y")
{
const Scope& sc = GetRequiredScope(element);
const Element* const Shading = sc["Shading"];
const Element* const Culling = sc["Culling"];
if(Shading) {
shading = GetRequiredToken(*Shading,0).StringContents();
}
if (Culling) {
culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
}
props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
ResolveLinks(element,doc);
}
// ------------------------------------------------------------------------------------------------
Model::~Model()
{
}
// ------------------------------------------------------------------------------------------------
void Model::ResolveLinks(const Element& element, const Document& doc)
{
const char* const arr[] = {"Geometry","Material","NodeAttribute"};
// resolve material
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
materials.reserve(conns.size());
geometry.reserve(conns.size());
attributes.reserve(conns.size());
for(const Connection* con : conns) {
// material and geometry links should be Object-Object connections
if (con->PropertyName().length()) {
continue;
}
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
continue;
}
const Material* const mat = dynamic_cast<const Material*>(ob);
if(mat) {
materials.push_back(mat);
continue;
}
const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
if(geo) {
geometry.push_back(geo);
continue;
}
const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
if(att) {
attributes.push_back(att);
continue;
}
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
continue;
}
}
// ------------------------------------------------------------------------------------------------
bool Model::IsNull() const
{
const std::vector<const NodeAttribute*>& attrs = GetAttributes();
for(const NodeAttribute* att : attrs) {
const Null* null_tag = dynamic_cast<const Null*>(att);
if(null_tag) {
return true;
}
}
return false;
}
} //!FBX
} //!Assimp
#endif

View file

@ -1,170 +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 "FBXImporter.h"
#include "FBXDocumentUtil.h"
namespace Assimp {
namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: Object(id,element,name)
, props()
{
const Scope& sc = GetRequiredScope(element);
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
// hack on the deriving type but Null/LimbNode attributes are the only case in which
// the property table is by design absent and no warning should be generated
// for it.
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
}
// ------------------------------------------------------------------------------------------------
NodeAttribute::~NodeAttribute()
{
// empty
}
// ------------------------------------------------------------------------------------------------
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
const Scope& sc = GetRequiredScope(element);
const Element* const CameraId = sc["CameraId"];
const Element* const CameraName = sc["CameraName"];
const Element* const CameraIndexName = sc["CameraIndexName"];
if(CameraId) {
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
}
if(CameraName) {
cameraName = GetRequiredToken(*CameraName,0).StringContents();
}
if(CameraIndexName && CameraIndexName->Tokens().size()) {
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
}
}
// ------------------------------------------------------------------------------------------------
CameraSwitcher::~CameraSwitcher()
{
// empty
}
// ------------------------------------------------------------------------------------------------
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
// empty
}
// ------------------------------------------------------------------------------------------------
Camera::~Camera()
{
// empty
}
// ------------------------------------------------------------------------------------------------
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
// empty
}
// ------------------------------------------------------------------------------------------------
Light::~Light()
{
}
// ------------------------------------------------------------------------------------------------
Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
Null::~Null()
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::~LimbNode()
{
}
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -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 <stdint.h>
#include <map>
#include <memory>
#include <assimp/LogAux.h>
#include <assimp/fast_atof.h>
#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<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
# define new_Scope new Scope
# define new_Element new Element
/** FBX data entity that consists of a key:value tuple.
*
* Example:
* @verbatim
* AnimationCurve: 23, "AnimCurve::", "" {
* [..]
* }
* @endverbatim
*
* As can be seen in this sample, elements can contain nested #Scope
* as their trailing member. **/
class Element
{
public:
Element(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<Scope> 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<Scope> 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<aiVector3D>& out, const Element& el);
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
void ParseVectorDataArray(std::vector<int>& out, const Element& el);
void ParseVectorDataArray(std::vector<float>& out, const Element& el);
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
void ParseVectorDataArray(std::vector<int64_t>& 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

View file

@ -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<std::string>(ParseTokenAsString(*tok[4]));
}
else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
}
else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
}
else if (!strcmp(cs, "ULongLong")) {
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
}
else if (!strcmp(cs, "KTime")) {
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
}
else if (!strcmp(cs,"Vector3D") ||
!strcmp(cs,"ColorRGB") ||
!strcmp(cs,"Vector") ||
!strcmp(cs,"Color") ||
!strcmp(cs,"Lcl Translation") ||
!strcmp(cs,"Lcl Rotation") ||
!strcmp(cs,"Lcl Scaling")
) {
return new TypedProperty<aiVector3D>(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<float>(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<const PropertyTable> 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<Property> prop = std::shared_ptr<Property>(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

View file

@ -1,185 +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.h
* @brief FBX dynamic properties
*/
#ifndef INCLUDED_AI_FBX_PROPERTIES_H
#define INCLUDED_AI_FBX_PROPERTIES_H
#include "FBXCompileConfig.h"
#include <memory>
#include <string>
namespace Assimp {
namespace FBX {
// Forward declarations
class Element;
/** Represents a dynamic property. Type info added by deriving classes,
* see #TypedProperty.
Example:
@verbatim
P: "ShininessExponent", "double", "Number", "",0.5
@endvebatim
*/
class Property {
protected:
Property();
public:
virtual ~Property();
public:
template <typename T>
const T* As() const {
return dynamic_cast<const T*>(this);
}
};
template<typename T>
class TypedProperty : public Property {
public:
explicit TypedProperty(const T& value)
: value(value) {
// empty
}
const T& Value() const {
return value;
}
private:
T value;
};
typedef std::fbx_unordered_map<std::string,std::shared_ptr<Property> > DirectPropertyMap;
typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap;
typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap;
/**
* Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
*/
class PropertyTable {
public:
// in-memory property table with no source element
PropertyTable();
PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps);
~PropertyTable();
const Property* Get(const std::string& name) const;
// PropertyTable's need not be coupled with FBX elements so this can be NULL
const Element* GetElement() const {
return element;
}
const PropertyTable* TemplateProps() const {
return templateProps.get();
}
DirectPropertyMap GetUnparsedProperties() const;
private:
LazyPropertyMap lazyProps;
mutable PropertyMap props;
const std::shared_ptr<const PropertyTable> templateProps;
const Element* const element;
};
// ------------------------------------------------------------------------------------------------
template <typename T>
inline
T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
const Property* const prop = in.Get(name);
if( nullptr == prop) {
return defaultValue;
}
// strong typing, no need to be lenient
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
if( nullptr == tprop) {
return defaultValue;
}
return tprop->Value();
}
// ------------------------------------------------------------------------------------------------
template <typename T>
inline
T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
const Property* prop = in.Get(name);
if( nullptr == prop) {
if ( ! useTemplate ) {
result = false;
return T();
}
const PropertyTable* templ = in.TemplateProps();
if ( nullptr == templ ) {
result = false;
return T();
}
prop = templ->Get(name);
if ( nullptr == prop ) {
result = false;
return T();
}
}
// strong typing, no need to be lenient
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
if( nullptr == tprop) {
result = false;
return T();
}
result = true;
return tprop->Value();
}
} //! FBX
} //! Assimp
#endif // INCLUDED_AI_FBX_PROPERTIES_H

View file

@ -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 <assimp/ParsingUtils.h>
#include "FBXTokenizer.h"
#include "FBXUtil.h"
#include <assimp/Exceptional.h>
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<size_t>(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<size_t>(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

View file

@ -1,187 +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.h
* @brief FBX lexer
*/
#ifndef INCLUDED_AI_FBX_TOKENIZER_H
#define INCLUDED_AI_FBX_TOKENIZER_H
#include "FBXCompileConfig.h"
#include <assimp/ai_assert.h>
#include <vector>
#include <string>
namespace Assimp {
namespace FBX {
/** Rough classification for text FBX tokens used for constructing the
* basic scope hierarchy. */
enum TokenType
{
// {
TokenType_OPEN_BRACKET = 0,
// }
TokenType_CLOSE_BRACKET,
// '"blablubb"', '2', '*14' - very general token class,
// further processing happens at a later stage.
TokenType_DATA,
//
TokenType_BINARY_DATA,
// ,
TokenType_COMMA,
// blubb:
TokenType_KEY
};
/** Represents a single token in a FBX file. Tokens are
* classified by the #TokenType enumerated types.
*
* Offers iterator protocol. Tokens are immutable. */
class Token
{
private:
static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
public:
/** construct a textual token */
Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column);
/** construct a binary token */
Token(const char* sbegin, const char* send, TokenType type, size_t offset);
~Token();
public:
std::string StringContents() const {
return std::string(begin(),end());
}
bool IsBinary() const {
return column == BINARY_MARKER;
}
const char* begin() const {
return sbegin;
}
const char* end() const {
return send;
}
TokenType Type() const {
return type;
}
size_t Offset() const {
ai_assert(IsBinary());
return offset;
}
unsigned int Line() const {
ai_assert(!IsBinary());
return static_cast<unsigned int>(line);
}
unsigned int Column() const {
ai_assert(!IsBinary());
return column;
}
private:
#ifdef DEBUG
// full string copy for the sole purpose that it nicely appears
// in msvc's debugger window.
const std::string contents;
#endif
const char* const sbegin;
const char* const send;
const TokenType type;
union {
size_t line;
size_t offset;
};
const unsigned int column;
};
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef const Token* TokenPtr;
typedef std::vector< TokenPtr > TokenList;
#define new_Token new Token
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
*
* Skips over comments and generates line and column numbers.
*
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated.
* @throw DeadlyImportError if something goes wrong */
void Tokenize(TokenList& output_tokens, const char* input);
/** Tokenizer function for binary FBX files.
*
* Emits a token list suitable for direct parsing.
*
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal.
* @throw DeadlyImportError if something goes wrong */
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
} // ! FBX
} // ! Assimp
#endif // ! INCLUDED_AI_FBX_PARSER_H

View file

@ -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 <assimp/TinyFormatter.h>
#include <string>
#include <cstring>
#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<std::string>( (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<std::string>( (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<std::string>( (Formatter::format() << prefix <<
" (" << TokenTypeString(tok->Type()) <<
", offset 0x" << std::hex << tok->Offset() << ") " <<
text) );
}
return static_cast<std::string>( (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<uint8_t>(ch);
if (idx > 127)
return 255;
return base64DecodeTable[idx];
}
size_t ComputeDecodedSizeBase64(const char* in, size_t inLength)
{
if (inLength < 2)
{
return 0;
}
const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
const size_t full_length = (inLength * 3) >> 2; // div by 4
if (full_length < equals)
{
return 0;
}
return full_length - equals;
}
size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength)
{
if (maxOutLength == 0 || inLength < 2) {
return 0;
}
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
size_t dst_offset = 0;
int val = 0, valb = -8;
for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
{
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
if (table_value == 255)
{
return 0;
}
val = (val << 6) + table_value;
valb += 6;
if (valb >= 0)
{
out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
valb -= 8;
val &= 0xFFF;
}
}
return dst_offset;
}
static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char EncodeBase64(char byte)
{
return to_base64_string[(size_t)byte];
}
/** Encodes a block of 4 bytes to base64 encoding
*
* @param bytes Bytes to encode.
* @param out_string String to write encoded values to.
* @param string_pos Position in out_string.*/
void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos)
{
char b0 = (bytes[0] & 0xFC) >> 2;
char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
char b3 = (bytes[2] & 0x3F);
out_string[string_pos + 0] = EncodeBase64(b0);
out_string[string_pos + 1] = EncodeBase64(b1);
out_string[string_pos + 2] = EncodeBase64(b2);
out_string[string_pos + 3] = EncodeBase64(b3);
}
std::string EncodeBase64(const char* data, size_t length)
{
// calculate extra bytes needed to get a multiple of 3
size_t extraBytes = 3 - length % 3;
// number of base64 bytes
size_t encodedBytes = 4 * (length + extraBytes) / 3;
std::string encoded_string(encodedBytes, '=');
// read blocks of 3 bytes
for (size_t ib3 = 0; ib3 < length / 3; ib3++)
{
const size_t iByte = ib3 * 3;
const size_t iEncodedByte = ib3 * 4;
const char* currData = &data[iByte];
EncodeByteBlock(currData, encoded_string, iEncodedByte);
}
// if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
if (extraBytes > 0)
{
char finalBytes[4] = { 0,0,0,0 };
memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
const size_t iEncodedByte = encodedBytes - 4;
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
// add '=' at the end
for (size_t i = 0; i < 4 * extraBytes / 3; i++)
encoded_string[encodedBytes - i - 1] = '=';
}
return encoded_string;
}
} // !Util
} // !FBX
} // !Assimp
#endif

View file

@ -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 FBXUtil.h
* @brief FBX utility functions for internal use
*/
#ifndef INCLUDED_AI_FBX_UTIL_H
#define INCLUDED_AI_FBX_UTIL_H
#include "FBXCompileConfig.h"
#include "FBXTokenizer.h"
#include <stdint.h>
namespace Assimp {
namespace FBX {
namespace Util {
/** helper for std::for_each to delete all heap-allocated items in a container */
template<typename T>
struct delete_fun
{
void operator()(const volatile T* del) {
delete del;
}
};
/** Get a string representation for a #TokenType. */
const char* TokenTypeString(TokenType t);
/** Format log/error messages using a given offset in the source binary file
*
* @param prefix Message prefix to be preprended to the location info.
* @param text Message text
* @param line Line index, 1-based
* @param column Column index, 1-based
* @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
/** Format log/error messages using a given line location in the source file.
*
* @param prefix Message prefix to be preprended to the location info.
* @param text Message text
* @param line Line index, 1-based
* @param column Column index, 1-based
* @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/
std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column);
/** Format log/error messages using a given cursor token.
*
* @param prefix Message prefix to be preprended to the location info.
* @param text Message text
* @param tok Token where parsing/processing stopped
* @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/
std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok);
/** Decode a single Base64-encoded character.
*
* @param ch Character to decode (from base64 to binary).
* @return decoded byte value*/
uint8_t DecodeBase64(char ch);
/** Compute decoded size of a Base64-encoded string
*
* @param in Characters to decode.
* @param inLength Number of characters to decode.
* @return size of the decoded data (number of bytes)*/
size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
/** Decode a Base64-encoded string
*
* @param in Characters to decode.
* @param inLength Number of characters to decode.
* @param out Pointer where we will store the decoded data.
* @param maxOutLength Size of output buffer.
* @return size of the decoded data (number of bytes)*/
size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength);
char EncodeBase64(char byte);
/** Encode bytes in base64-encoding
*
* @param data Binary data to encode.
* @param inLength Number of bytes to encode.
* @return base64-encoded string*/
std::string EncodeBase64(const char* data, size_t length);
}
}
}
#endif // ! INCLUDED_AI_FBX_UTIL_H

View file

@ -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 <assimp/Hash.h>
#include <assimp/fast_atof.h>
#include <assimp/ParsingUtils.h>
#include "MaterialSystem.h"
#include <assimp/types.h>
#include <assimp/material.h>
#include <assimp/DefaultLogger.hpp>
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<ai_real> ( reinterpret_cast<float*>(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<ai_real> ( reinterpret_cast<double*>(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<ai_real> ( reinterpret_cast<int32_t*>(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<ai_real>(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<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
if (pMax) {
iWrite = std::min(*pMax,iWrite);
}
if (1 == prop->mDataLength) {
// bool type, 1 byte
*pOut = static_cast<int>(*prop->mData);
}
else {
for (unsigned int a = 0; a < iWrite;++a) {
pOut[a] = static_cast<int>(reinterpret_cast<int32_t*>(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<int>(reinterpret_cast<float*>(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<unsigned int>(*reinterpret_cast<uint32_t*>(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<int>(aiTextureMapping_UV);
aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_);
aiTextureMapping mapping = static_cast<aiTextureMapping>(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<unsigned int>(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);
}
}

View file

@ -1,72 +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.h
* Now that #MaterialHelper is gone, this file only contains some
* internal material utility functions.
*/
#ifndef AI_MATERIALSYSTEM_H_INC
#define AI_MATERIALSYSTEM_H_INC
#include <stdint.h>
struct aiMaterial;
namespace Assimp {
// ------------------------------------------------------------------------------
/** Computes a hash (hopefully unique) from all material properties
* The hash value reflects the current property state, so if you add any
* property and call this method again, the resulting hash value will be
* different. The hash is not persistent across different builds and platforms.
*
* @param includeMatName Set to 'true' to take all properties with
* '?' as initial character in their name into account.
* Currently #AI_MATKEY_NAME is the only example.
* @return 32 Bit jash value for the material
*/
uint32_t ComputeMaterialHash(const aiMaterial* mat, bool includeMatName = false);
} // ! namespace Assimp
#endif //!! AI_MATERIALSYSTEM_H_INC

View file

@ -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 <assimp/BaseImporter.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <iostream>
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<aiBone *> bones;
std::vector<aiNode *> nodes;
std::map<aiBone *, aiNode *> 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<aiBone *, aiNode *> 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<aiBone *> &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<aiNode *> &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<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode *> &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<aiBone *, aiNode *>(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<aiBone *> &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<aiBone *> &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<aiNode *> &nodes) {
std::vector<aiNode *>::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

View file

@ -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 <assimp/BaseImporter.h>
#include <vector>
#include <map>
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 <gordon@gordonite.tech>
* 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<aiBone *> &bone_list);
static bool IsBoneNode(const aiString &bone_name,
std::vector<aiBone *> &bones);
static aiNode *GetNodeFromStack(const aiString &node_name,
std::vector<aiNode *> &nodes);
static void BuildNodeList(const aiNode *current_node,
std::vector<aiNode *> &nodes);
static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
const aiScene *scene,
std::vector<aiBone *> &bones);
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
const aiScene *scene,
const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode *> &node_stack);
};
} // Namespace Assimp
#endif // SCALE_PROCESS_H_

View file

@ -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 <assimp/TinyFormatter.h>
#include <assimp/qnan.h>
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<bool> 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<std::pair<SpatialSort,float> >* avf;
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
if (avf)
{
std::pair<SpatialSort,float>& 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<unsigned int> verticesFound;
const float fLimit = std::cos(configMaxAngle);
std::vector<unsigned int> 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;
}

View file

@ -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

View file

@ -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 <assimp/Exceptional.h>
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<MappingInfo> 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<MappingInfo>::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");
}

View file

@ -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 <assimp/mesh.h>
#include <assimp/material.h>
#include <assimp/types.h>
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

View file

@ -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 <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/DefaultLogger.hpp>
using namespace Assimp;
#ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
namespace {
template <typename aiMeshType>
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

View file

@ -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 <assimp/types.h>
#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

Some files were not shown because too many files have changed in this diff Show more