mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 06:33:16 +00:00
Merge pull request #42941 from RevoluPowered/fbx-3-2-2020
[3.2] FBX importer rewrite
This commit is contained in:
commit
4f908fb671
@ -55,6 +55,13 @@ Comment: Godot Engine logo
|
||||
Copyright: 2017, Andrea Calabró
|
||||
License: CC-BY-3.0
|
||||
|
||||
Files: ./modules/fbx/fbx_parser/
|
||||
Comment: Open Asset Import Library (assimp)
|
||||
Copyright: 2006-2016, assimp team
|
||||
2007-2020, Juan Linietsky, Ariel Manzur.
|
||||
2014-2020, Godot Engine contributors.
|
||||
License: BSD-3-clause and Expat
|
||||
|
||||
Files: ./platform/android/java/aidl/com/android/vending/billing/IInAppBillingService.aidl
|
||||
./platform/android/java/res/layout/status_bar_ongoing_event_progress_bar.xml
|
||||
./platform/android/java/src/com/google/android/vending/expansion/downloader/*
|
||||
@ -110,11 +117,6 @@ Copyright: 2007, Starbreeze Studios
|
||||
2014-2020, Godot Engine contributors.
|
||||
License: Expat and Zlib
|
||||
|
||||
Files: ./thirdparty/assimp/
|
||||
Comment: Open Asset Import Library (assimp)
|
||||
Copyright: 2006-2016, assimp team
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: ./thirdparty/bullet/
|
||||
Comment: Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright: 2003-2013, Erwin Coumans
|
||||
|
@ -1,94 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_assimp = env_modules.Clone()
|
||||
|
||||
# Force bundled version for now, there's no released version of Assimp with
|
||||
# support for ArmaturePopulate which we use from their master branch.
|
||||
if True: # env['builtin_assimp']:
|
||||
thirdparty_dir = "#thirdparty/assimp"
|
||||
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp"])
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/code"])
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/include"])
|
||||
|
||||
# env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_SINGLETHREADED"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_BOOST_WORKAROUND"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OWN_ZLIB"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_EXPORT"])
|
||||
|
||||
# Importers we don't need
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3DS_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3MF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AMF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASE_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASSBIN_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_B3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BLEND_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BVH_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_C4D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COB_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COLLADA_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_CSM_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_DXF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF2_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_HMP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IFC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRR_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRRMESH_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWO_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWS_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_M3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD2_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD3_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MMD_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MS3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NDO_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NFF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OBJ_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OFF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OGRE_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OPENGEX_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_PLY_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3BSP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_RAW_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SIB_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SMD_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STEP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_TERRAGEN_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_XGL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X_IMPORTER"])
|
||||
|
||||
if env["platform"] == "windows":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_WINDOWS"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "WINDOWS")])
|
||||
elif env["platform"] == "x11":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_LINUX"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "LINUX")])
|
||||
elif env["platform"] == "osx":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_DARWIN"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "DARWIN")])
|
||||
|
||||
env_thirdparty = env_assimp.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
|
||||
env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp"))
|
||||
env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
|
||||
env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp"))
|
||||
env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
|
||||
|
||||
# Godot's own source files
|
||||
env_assimp.add_source_files(env.modules_sources, "*.cpp")
|
File diff suppressed because it is too large
Load Diff
@ -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*
|
||||
|
@ -1,447 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_UTILS_IMPORTER_ASSIMP_H
|
||||
#define IMPORT_UTILS_IMPORTER_ASSIMP_H
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
#include "import_state.h"
|
||||
|
||||
#include <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, PoolColorArray::Write &w) {
|
||||
const aiVector3D normals = ai_mesh->mAnimMeshes[i]->mNormals[tri_index];
|
||||
const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
|
||||
const aiVector3D tangent = ai_mesh->mAnimMeshes[i]->mTangents[tri_index];
|
||||
const Vector3 godot_tangent = Vector3(tangent.x, tangent.y, tangent.z);
|
||||
const aiVector3D bitangent = ai_mesh->mAnimMeshes[i]->mBitangents[tri_index];
|
||||
const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
|
||||
float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
|
||||
Color plane_tangent = Color(tangent.x, tangent.y, tangent.z, d);
|
||||
w[index] = plane_tangent;
|
||||
}
|
||||
|
||||
struct AssetImportFbx {
|
||||
enum ETimeMode {
|
||||
TIME_MODE_DEFAULT = 0,
|
||||
TIME_MODE_120 = 1,
|
||||
TIME_MODE_100 = 2,
|
||||
TIME_MODE_60 = 3,
|
||||
TIME_MODE_50 = 4,
|
||||
TIME_MODE_48 = 5,
|
||||
TIME_MODE_30 = 6,
|
||||
TIME_MODE_30_DROP = 7,
|
||||
TIME_MODE_NTSC_DROP_FRAME = 8,
|
||||
TIME_MODE_NTSC_FULL_FRAME = 9,
|
||||
TIME_MODE_PAL = 10,
|
||||
TIME_MODE_CINEMA = 11,
|
||||
TIME_MODE_1000 = 12,
|
||||
TIME_MODE_CINEMA_ND = 13,
|
||||
TIME_MODE_CUSTOM = 14,
|
||||
TIME_MODE_TIME_MODE_COUNT = 15
|
||||
};
|
||||
enum UpAxis {
|
||||
UP_VECTOR_AXIS_X = 1,
|
||||
UP_VECTOR_AXIS_Y = 2,
|
||||
UP_VECTOR_AXIS_Z = 3
|
||||
};
|
||||
enum FrontAxis {
|
||||
FRONT_PARITY_EVEN = 1,
|
||||
FRONT_PARITY_ODD = 2,
|
||||
};
|
||||
|
||||
enum CoordAxis {
|
||||
COORD_RIGHT = 0,
|
||||
COORD_LEFT = 1
|
||||
};
|
||||
};
|
||||
|
||||
/** Get assimp string
|
||||
* automatically filters the string data
|
||||
*/
|
||||
static String get_assimp_string(const aiString &p_string) {
|
||||
//convert an assimp String to a Godot String
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
if (name.find(":") != -1) {
|
||||
String replaced_name = name.split(":")[1];
|
||||
print_verbose("Replacing " + name + " containing : with " + replaced_name);
|
||||
name = replaced_name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static String get_anim_string_from_assimp(const aiString &p_string) {
|
||||
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
if (name.find(":") != -1) {
|
||||
String replaced_name = name.split(":")[1];
|
||||
print_verbose("Replacing " + name + " containing : with " + replaced_name);
|
||||
name = replaced_name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* No filter logic get_raw_string_from_assimp
|
||||
* This just convers the aiString to a parsed utf8 string
|
||||
* Without removing special chars etc
|
||||
*/
|
||||
static String get_raw_string_from_assimp(const aiString &p_string) {
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
return name;
|
||||
}
|
||||
|
||||
static Ref<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 != NULL) {
|
||||
xform = assimp_matrix_transform(current_node->mTransformation) * xform;
|
||||
current_node = current_node->mParent;
|
||||
}
|
||||
return xform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find hardcoded textures from assimp which could be in many different directories
|
||||
*/
|
||||
static void find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension) {
|
||||
Vector<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 == NULL);
|
||||
aiTextureMapMode tex_mode = map_mode[0];
|
||||
|
||||
int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
if (tex_mode == aiTextureMapMode_Wrap) {
|
||||
//Default
|
||||
} else if (tex_mode == aiTextureMapMode_Clamp) {
|
||||
flags = flags & ~Texture::FLAG_REPEAT;
|
||||
} else if (tex_mode == aiTextureMapMode_Mirror) {
|
||||
flags = flags | Texture::FLAG_MIRRORED_REPEAT;
|
||||
}
|
||||
texture->set_flags(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load or load from cache image :)
|
||||
*/
|
||||
static Ref<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 == NULL, 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 == NULL, 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();
|
||||
PoolByteArray arr;
|
||||
uint32_t size = tex->mWidth * tex->mHeight;
|
||||
arr.resize(size);
|
||||
memcpy(arr.write().ptr(), tex->pcData, size);
|
||||
ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
|
||||
//ARGB8888 to RGBA8888
|
||||
for (int32_t i = 0; i < arr.size() / 4; i++) {
|
||||
arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
|
||||
arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
|
||||
arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
|
||||
arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
|
||||
}
|
||||
img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
|
||||
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, img);
|
||||
return img;
|
||||
}
|
||||
return Ref<Image>();
|
||||
} else {
|
||||
Ref<Texture> texture = ResourceLoader::load(p_path);
|
||||
ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
|
||||
Ref<Image> image = texture->get_data();
|
||||
ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
return Ref<Image>();
|
||||
}
|
||||
|
||||
/* create texture from assimp data, if found in path */
|
||||
static bool CreateAssimpTexture(
|
||||
AssimpImporter::ImportState &state,
|
||||
aiString texture_path,
|
||||
String &filename,
|
||||
String &path,
|
||||
AssimpImageData &image_state) {
|
||||
filename = get_raw_string_from_assimp(texture_path);
|
||||
path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
|
||||
bool found = false;
|
||||
find_texture_path(state.path, path, found);
|
||||
if (found) {
|
||||
image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
|
||||
if (image_state.raw_image.is_valid()) {
|
||||
image_state.texture.instance();
|
||||
image_state.texture->create_from_image(image_state.raw_image);
|
||||
image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/** GetAssimpTexture
|
||||
* Designed to retrieve textures for you
|
||||
*/
|
||||
static bool GetAssimpTexture(
|
||||
AssimpImporter::ImportState &state,
|
||||
aiMaterial *ai_material,
|
||||
aiTextureType texture_type,
|
||||
String &filename,
|
||||
String &path,
|
||||
AssimpImageData &image_state) {
|
||||
aiString ai_filename = aiString();
|
||||
if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
|
||||
return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IMPORT_UTILS_IMPORTER_ASSIMP_H
|
15
modules/fbx/SCsub
Normal file
15
modules/fbx/SCsub
Normal file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_fbx = env_modules.Clone()
|
||||
|
||||
# Make includes relative to the folder path specified here so our includes are clean
|
||||
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
|
||||
|
||||
# Godot's own source files
|
||||
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "fbx_parser/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "*.cpp")
|
46
modules/fbx/data/fbx_anim_container.h
Normal file
46
modules/fbx/data/fbx_anim_container.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_anim_container.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_ANIM_CONTAINER_H
|
||||
#define FBX_ANIM_CONTAINER_H
|
||||
|
||||
#include "core/vector.h"
|
||||
|
||||
// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks
|
||||
// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp
|
||||
// to avoid having to rewrite the entire logic I refactored this into the code instead.
|
||||
// once it works I can rewrite so we can add the fun misc features / small features
|
||||
struct FBXTrack {
|
||||
bool has_default = false;
|
||||
Vector3 default_value;
|
||||
std::map<int64_t, Vector3> keyframes;
|
||||
};
|
||||
|
||||
#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H
|
93
modules/fbx/data/fbx_bone.cpp
Normal file
93
modules/fbx/data/fbx_bone.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_bone.h"
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
Ref<FBXNode> FBXBone::get_link(const ImportState &state) const {
|
||||
print_verbose("bone name: " + bone_name);
|
||||
ERR_FAIL_COND_V_MSG(cluster == nullptr, nullptr, "bone has invalid cluster");
|
||||
ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node");
|
||||
|
||||
Ref<FBXNode> link_node;
|
||||
uint64_t id = cluster->TargetNode()->ID();
|
||||
if (state.fbx_target_map.has(id)) {
|
||||
link_node = state.fbx_target_map[id];
|
||||
} else {
|
||||
print_error("link node not found for " + itos(id));
|
||||
}
|
||||
|
||||
// the node in space this is for, like if it's FOR a target.
|
||||
return link_node;
|
||||
}
|
||||
|
||||
/* right now we just get single skin working and we can patch in the multiple tomorrow - per skin not per bone. */
|
||||
// this will work for multiple meshes :) awesomeness.
|
||||
// okay so these formula's are complex and need proper understanding of
|
||||
// shear, pivots, geometric pivots, pre rotation and post rotation
|
||||
// additionally DO NOT EDIT THIS if your blender file isn't working.
|
||||
// Contact RevoluPowered Gordon MacPherson if you are contemplating making edits to this.
|
||||
Transform FBXBone::get_vertex_skin_xform(const ImportState &state, Transform mesh_global_position, bool &r_valid_pose) {
|
||||
r_valid_pose = false;
|
||||
print_verbose("get_vertex_skin_xform: " + bone_name);
|
||||
ERR_FAIL_COND_V_MSG(cluster == nullptr, Transform(), "[serious] unable to resolve the fbx cluster for this bone " + bone_name);
|
||||
// these methods will ONLY work for Maya.
|
||||
if (cluster->TransformAssociateModelValid()) {
|
||||
//print_error("additive skinning in use");
|
||||
Transform associate_global_init_position = cluster->TransformAssociateModel();
|
||||
Transform associate_global_current_position = Transform();
|
||||
Transform reference_global_init_position = cluster->GetTransform();
|
||||
Transform cluster_global_init_position = cluster->TransformLink();
|
||||
Ref<FBXNode> link_node = get_link(state);
|
||||
ERR_FAIL_COND_V_MSG(link_node.is_null(), Transform(), "invalid link corrupt file detected");
|
||||
r_valid_pose = true;
|
||||
Transform cluster_global_current_position = link_node.is_valid() && link_node->pivot_transform.is_valid() ? link_node->pivot_transform->GlobalTransform : Transform();
|
||||
|
||||
vertex_transform_matrix = reference_global_init_position.affine_inverse() * associate_global_init_position * associate_global_current_position.affine_inverse() *
|
||||
cluster_global_current_position * cluster_global_init_position.affine_inverse() * reference_global_init_position;
|
||||
} else {
|
||||
//print_error("non additive skinning is in use");
|
||||
Transform reference_global_position = cluster->GetTransform();
|
||||
Transform reference_global_current_position = mesh_global_position;
|
||||
//Transform geometric_pivot = Transform(); // we do not use this - 3ds max only
|
||||
Transform global_init_position = cluster->TransformLink();
|
||||
if (global_init_position.basis.determinant() == 0) {
|
||||
global_init_position = Transform(Basis(), global_init_position.origin);
|
||||
}
|
||||
Transform cluster_relative_init_position = global_init_position.affine_inverse() * reference_global_position;
|
||||
Transform cluster_relative_position_inverse = reference_global_current_position.affine_inverse() * global_init_position;
|
||||
vertex_transform_matrix = cluster_relative_position_inverse * cluster_relative_init_position;
|
||||
r_valid_pose = true;
|
||||
}
|
||||
|
||||
return vertex_transform_matrix;
|
||||
}
|
95
modules/fbx/data/fbx_bone.h
Normal file
95
modules/fbx/data/fbx_bone.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_BONE_H
|
||||
#define FBX_BONE_H
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXBone : public Reference {
|
||||
uint64_t parent_bone_id = 0;
|
||||
uint64_t bone_id = 0;
|
||||
|
||||
bool valid_parent = false; // if the parent bone id is set up.
|
||||
String bone_name = String(); // bone name
|
||||
|
||||
bool is_root_bone() const {
|
||||
return !valid_parent;
|
||||
}
|
||||
|
||||
uint64_t target_node_id; // the node target id for the skeleton element
|
||||
bool valid_target = false; // only applies to bones with a mesh / in the skin.
|
||||
|
||||
// Godot specific data
|
||||
int godot_bone_id = -2; // godot internal bone id assigned after import
|
||||
|
||||
// if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton.
|
||||
// this is to support joints by themselves in scenes
|
||||
bool valid_armature_id = false;
|
||||
uint64_t armature_id = 0;
|
||||
|
||||
// Vertex Weight information
|
||||
Transform transform_link; // todo remove
|
||||
Transform transform_matrix; // todo remove
|
||||
|
||||
/* get associate model - the model can be invalid sometimes */
|
||||
Ref<FBXBone> get_associate_model() const {
|
||||
return parent_bone;
|
||||
}
|
||||
|
||||
/* link node is the parent bone */
|
||||
Ref<FBXNode> get_link(const ImportState &state) const;
|
||||
Transform get_vertex_skin_xform(const ImportState &state, Transform mesh_global_position, bool &valid);
|
||||
Transform vertex_transform_matrix;
|
||||
Transform local_cluster_matrix; // set_bone_pose
|
||||
|
||||
mutable const FBXDocParser::Deformer *skin = nullptr;
|
||||
mutable const FBXDocParser::Cluster *cluster = nullptr;
|
||||
mutable const FBXDocParser::Geometry *geometry = nullptr;
|
||||
mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr;
|
||||
|
||||
void set_pivot_xform(Ref<PivotTransform> p_pivot_xform) {
|
||||
pivot_xform = p_pivot_xform;
|
||||
}
|
||||
|
||||
// pose node / if assigned
|
||||
Transform pose_node = Transform();
|
||||
bool assigned_pose_node = false;
|
||||
Ref<FBXBone> parent_bone = Ref<FBXBone>();
|
||||
Ref<PivotTransform> pivot_xform = Ref<PivotTransform>();
|
||||
Ref<FBXSkeleton> fbx_skeleton = Ref<FBXSkeleton>();
|
||||
};
|
||||
|
||||
#endif // FBX_BONE_H
|
487
modules/fbx/data/fbx_material.cpp
Normal file
487
modules/fbx/data/fbx_material.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_material.h"
|
||||
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
String FBXMaterial::get_material_name() const {
|
||||
return material_name;
|
||||
}
|
||||
|
||||
void FBXMaterial::set_imported_material(const FBXDocParser::Material *p_material) {
|
||||
material = p_material;
|
||||
}
|
||||
|
||||
void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) {
|
||||
if (search_directory.empty()) {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename));
|
||||
} else {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename));
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename));
|
||||
}
|
||||
}
|
||||
|
||||
String find_file(const String &p_base, const String &p_file_to_find) {
|
||||
_Directory dir;
|
||||
dir.open(p_base);
|
||||
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (n != String()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(p_base + "/" + n, p_file_to_find);
|
||||
if (f != "") {
|
||||
return f;
|
||||
}
|
||||
} else if (n == p_file_to_find) {
|
||||
return p_base + "/" + n;
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
// fbx will not give us good path information and let's not regex them to fix them
|
||||
// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK.
|
||||
String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) {
|
||||
_Directory dir;
|
||||
Vector<String> paths;
|
||||
add_search_string(p_filename, p_current_directory, "", paths);
|
||||
add_search_string(p_filename, p_current_directory, "texture", paths);
|
||||
add_search_string(p_filename, p_current_directory, "textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "Textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "materials", paths);
|
||||
add_search_string(p_filename, p_current_directory, "mats", paths);
|
||||
add_search_string(p_filename, p_current_directory, "pictures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "images", paths);
|
||||
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
if (dir.file_exists(paths[i])) {
|
||||
return paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
// We were not able to find the texture in the common locations,
|
||||
// try to find it into the project globally.
|
||||
// The common textures can be stored into one of those folders:
|
||||
// res://asset
|
||||
// res://texture
|
||||
// res://material
|
||||
// res://mat
|
||||
// res://image
|
||||
// res://picture
|
||||
//
|
||||
// Note the folders can also be called with custom names, like:
|
||||
// res://my_assets
|
||||
// since the keyword `asset` is into the directory name the textures will be
|
||||
// searched there too.
|
||||
|
||||
dir.open("res://");
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (n != String()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
const String lower_n = n.to_lower();
|
||||
if (
|
||||
// Don't need to use plural.
|
||||
lower_n.find("asset") >= 0 ||
|
||||
lower_n.find("texture") >= 0 ||
|
||||
lower_n.find("material") >= 0 ||
|
||||
lower_n.find("mat") >= 0 ||
|
||||
lower_n.find("image") >= 0 ||
|
||||
lower_n.find("picture") >= 0) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(String("res://") + n, p_filename);
|
||||
if (f != "") {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
FBXMaterial::MaterialInfo FBXMaterial::extract_material_info(const FBXDocParser::Material *material) const {
|
||||
MaterialInfo mat_info;
|
||||
|
||||
// TODO Layered textures are a collection on textures stored into an array.
|
||||
// Extract layered textures is not yet supported. Per each texture in the
|
||||
// layered texture array you want to use the below method to extract those.
|
||||
|
||||
for (std::pair<std::string, const FBXDocParser::Texture *> texture : material->Textures()) {
|
||||
const std::string &fbx_mapping_name = texture.first;
|
||||
|
||||
if (fbx_feature_mapping_desc.count(fbx_mapping_name) > 0) {
|
||||
// This is a feature not a normal texture.
|
||||
mat_info.features.push_back(fbx_feature_mapping_desc.at(fbx_mapping_name));
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(fbx_texture_mapping_desc.count(fbx_mapping_name) <= 0, "This FBX has a material with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider open an issue so we can support it.");
|
||||
|
||||
const String absoulte_fbx_file_path = texture.second->FileName().c_str();
|
||||
const String file_extension = absoulte_fbx_file_path.get_extension().to_upper();
|
||||
|
||||
const String file_extension_uppercase = file_extension.to_upper();
|
||||
|
||||
// TODO: we don't support EMBED for DDS and TGA.
|
||||
ERR_CONTINUE_MSG(
|
||||
file_extension_uppercase != "PNG" &&
|
||||
file_extension_uppercase != "JPEG" &&
|
||||
file_extension_uppercase != "JPG" &&
|
||||
file_extension_uppercase != "TGA" &&
|
||||
file_extension_uppercase != "WEBP" &&
|
||||
file_extension_uppercase != "DDS",
|
||||
"The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase);
|
||||
|
||||
const String texture_name = absoulte_fbx_file_path.get_file();
|
||||
const SpatialMaterial::TextureParam mapping_mode = fbx_texture_mapping_desc.at(fbx_mapping_name);
|
||||
|
||||
TextureFileMapping file_mapping;
|
||||
file_mapping.map_mode = mapping_mode;
|
||||
file_mapping.name = texture_name;
|
||||
file_mapping.texture = texture.second;
|
||||
mat_info.textures.push_back(file_mapping);
|
||||
|
||||
// Make sure to active the various features.
|
||||
switch (mapping_mode) {
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ALBEDO:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_METALLIC:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_FLOWMAP:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_REFRACTION:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_MAX:
|
||||
// No features required.
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_EMISSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_NORMAL:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_RIM:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_RIM);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_CLEARCOAT:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_AMBIENT_OCCLUSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DEPTH:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_DEPTH_MAPPING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_SUBSURFACE_SCATTERING:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_SUBSURACE_SCATTERING);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_TRANSMISSION:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_TRANSMISSION);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_ALBEDO:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_MASK:
|
||||
case SpatialMaterial::TextureParam::TEXTURE_DETAIL_NORMAL:
|
||||
mat_info.features.push_back(SpatialMaterial::Feature::FEATURE_DETAIL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mat_info;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) {
|
||||
ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor");
|
||||
const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type);
|
||||
// Make sure to not lost any eventual opacity.
|
||||
return val->Value();
|
||||
}
|
||||
|
||||
Ref<SpatialMaterial> FBXMaterial::import_material(ImportState &state) {
|
||||
|
||||
ERR_FAIL_COND_V(material == nullptr, nullptr);
|
||||
|
||||
const String p_fbx_current_directory = state.path;
|
||||
|
||||
Ref<SpatialMaterial> spatial_material;
|
||||
|
||||
// read the material file
|
||||
// is material two sided
|
||||
// read material name
|
||||
print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name()));
|
||||
material_name = ImportUtils::FBXNodeToName(material->Name());
|
||||
|
||||
// Extract info.
|
||||
MaterialInfo material_info = extract_material_info(material);
|
||||
|
||||
// Extract other parameters info.
|
||||
for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) {
|
||||
const std::string name = iter.first;
|
||||
//const Assimp::FBX::ElementPtr element = iter.second;
|
||||
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyDesc desc = PROPERTY_DESC_NOT_FOUND;
|
||||
if (fbx_properties_desc.count(name) > 0) {
|
||||
desc = fbx_properties_desc.at(name);
|
||||
}
|
||||
|
||||
if (desc == PROPERTY_DESC_IGNORE) {
|
||||
print_verbose("The FBX material parameter: `" + String(name.c_str()) + "` is ignored.");
|
||||
continue;
|
||||
} else {
|
||||
print_verbose("FBX Material parameter: " + String(name.c_str()));
|
||||
}
|
||||
|
||||
if (desc == PROPERTY_DESC_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
|
||||
|
||||
FBXDocParser::PropertyPtr prop = material->Props()->Get(name);
|
||||
|
||||
//Assimp::FBX::PropertyPtr prop = prop.second.
|
||||
|
||||
if (prop == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
|
||||
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no data no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
|
||||
switch (desc) {
|
||||
case PROPERTY_DESC_ALBEDO_COLOR: {
|
||||
const Vector3 color = extract_from_prop(prop, Vector3(0, 0, 0), name, "Vector3");
|
||||
// Make sure to not lost any eventual opacity.
|
||||
Color c = spatial_material->get_albedo();
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_albedo(c);
|
||||
} break;
|
||||
case PROPERTY_DESC_TRANSPARENT: {
|
||||
const real_t opacity = extract_from_prop(prop, 1.0f, name, "float");
|
||||
if (opacity < (1.0 - CMP_EPSILON)) {
|
||||
Color c = spatial_material->get_albedo();
|
||||
c[3] = opacity;
|
||||
spatial_material->set_albedo(c);
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_TRANSPARENT);
|
||||
spatial_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_METALLIC: {
|
||||
spatial_material->set_metallic(std::min(1.0f, extract_from_prop(prop, 1.0f, name, "float")));
|
||||
} break;
|
||||
case PROPERTY_DESC_ROUGHNESS: {
|
||||
spatial_material->set_roughness(std::min(1.0f, extract_from_prop(prop, 1.0f, name, "float")));
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT: {
|
||||
spatial_material->set_clearcoat(extract_from_prop(prop, 1.0f, name, "float"));
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT_ROUGHNESS: {
|
||||
spatial_material->set_clearcoat_gloss(1.0 - extract_from_prop(prop, 0.5f, name, "float"));
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_CLEARCOAT);
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE: {
|
||||
const real_t emissive = extract_from_prop(prop, 0.0f, name, "float");
|
||||
if (emissive > CMP_EPSILON) {
|
||||
spatial_material->set_emission_energy(emissive);
|
||||
material_info.features.push_back(SpatialMaterial::Feature::FEATURE_EMISSION);
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE_COLOR: {
|
||||
const Vector3 color = extract_from_prop(prop, Vector3(0, 0, 0), name, "Vector3");
|
||||
Color c;
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_emission(c);
|
||||
} break;
|
||||
case PROPERTY_DESC_NOT_FOUND:
|
||||
case PROPERTY_DESC_IGNORE:
|
||||
// Already checked, can't happen.
|
||||
CRASH_NOW();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the material features.
|
||||
for (int x = 0; x < material_info.features.size(); x++) {
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no textures no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
spatial_material->set_feature(material_info.features[x], true);
|
||||
}
|
||||
|
||||
// Set the textures.
|
||||
for (int x = 0; x < material_info.textures.size(); x++) {
|
||||
TextureFileMapping mapping = material_info.textures[x];
|
||||
Ref<Texture> texture;
|
||||
print_verbose("texture mapping name: " + mapping.name);
|
||||
|
||||
if (state.cached_image_searches.has(mapping.name)) {
|
||||
texture = state.cached_image_searches[mapping.name];
|
||||
} else {
|
||||
String path = find_texture_path_by_filename(mapping.name, p_fbx_current_directory);
|
||||
if (!path.empty()) {
|
||||
Error err;
|
||||
Ref<Texture> image_texture = ResourceLoader::load(path, "Texture", false, &err);
|
||||
|
||||
ERR_CONTINUE_MSG(err != OK, "unable to import image file not loaded yet: " + path);
|
||||
ERR_CONTINUE(image_texture == NULL || image_texture.is_null());
|
||||
|
||||
texture = image_texture;
|
||||
state.cached_image_searches.insert(mapping.name, texture);
|
||||
print_verbose("Created texture from loaded image file.");
|
||||
|
||||
} else if (mapping.texture != nullptr && mapping.texture->Media() != nullptr) {
|
||||
// This is an embedded texture. Extract it.
|
||||
Ref<Image> image;
|
||||
image.instance();
|
||||
|
||||
const String extension = mapping.name.get_extension().to_upper();
|
||||
if (extension == "PNG") {
|
||||
|
||||
// The stored file is a PNG.
|
||||
image = Image::_png_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail.");
|
||||
|
||||
} else if (
|
||||
extension == "JPEG" ||
|
||||
extension == "JPG") {
|
||||
|
||||
// The stored file is a JPEG.
|
||||
image = Image::_jpg_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail.");
|
||||
|
||||
} else if (extension == "TGA") {
|
||||
|
||||
// The stored file is a TGA.
|
||||
//image = Image::_tga_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
//ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail.");
|
||||
|
||||
} else if (extension == "WEBP") {
|
||||
|
||||
// The stored file is a WEBP.
|
||||
image = Image::_webp_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail.");
|
||||
|
||||
// } else if (extension == "DDS") {
|
||||
// // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load().
|
||||
// // The stored file is a DDS.
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please.");
|
||||
}
|
||||
|
||||
Ref<ImageTexture> image_texture;
|
||||
image_texture.instance();
|
||||
image_texture->create_from_image(image);
|
||||
|
||||
const int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
image_texture->set_flags(flags);
|
||||
|
||||
texture = image_texture;
|
||||
state.cached_image_searches[mapping.name] = texture;
|
||||
print_verbose("Created texture from embedded image.");
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + mapping.name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport.");
|
||||
}
|
||||
}
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no textures no material is created.
|
||||
spatial_material.instance();
|
||||
}
|
||||
|
||||
switch (mapping.map_mode) {
|
||||
case SpatialMaterial::TextureParam::TEXTURE_METALLIC:
|
||||
if (mapping.name.to_lower().find("ser") >= 0) {
|
||||
// SER shader.
|
||||
spatial_material->set_metallic_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_RED);
|
||||
} else {
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_metallic_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
}
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS:
|
||||
if (mapping.name.to_lower().find("ser") >= 0) {
|
||||
// SER shader.
|
||||
spatial_material->set_roughness_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_BLUE);
|
||||
} else {
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_roughness_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
}
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION:
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_ao_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
break;
|
||||
case SpatialMaterial::TextureParam::TEXTURE_REFRACTION:
|
||||
// Use grayscale as default.
|
||||
spatial_material->set_refraction_texture_channel(SpatialMaterial::TextureChannel::TEXTURE_CHANNEL_GRAYSCALE);
|
||||
break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
|
||||
spatial_material->set_texture(mapping.map_mode, texture);
|
||||
}
|
||||
|
||||
if (spatial_material.is_valid()) {
|
||||
spatial_material->set_name(material_name);
|
||||
}
|
||||
|
||||
return spatial_material;
|
||||
}
|
233
modules/fbx/data/fbx_material.h
Normal file
233
modules/fbx/data/fbx_material.h
Normal file
@ -0,0 +1,233 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MATERIAL_H
|
||||
#define FBX_MATERIAL_H
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
struct FBXMaterial : public Reference {
|
||||
String material_name = String();
|
||||
mutable const FBXDocParser::Material *material = nullptr;
|
||||
|
||||
/* Godot materials
|
||||
*** Texture Maps:
|
||||
* Albedo - color, texture
|
||||
* Metallic - specular, metallic, texture
|
||||
* Roughness - roughness, texture
|
||||
* Emission - color, texture
|
||||
* Normal Map - scale, texture
|
||||
* Ambient Occlusion - texture
|
||||
* Refraction - scale, texture
|
||||
*** Has Settings for:
|
||||
* UV1 - SCALE, OFFSET
|
||||
* UV2 - SCALE, OFFSET
|
||||
*** Flags for
|
||||
* Transparent
|
||||
* Cull Mode
|
||||
*/
|
||||
|
||||
enum class MapMode {
|
||||
AlbedoM = 0,
|
||||
MetallicM,
|
||||
SpecularM,
|
||||
EmissionM,
|
||||
RoughnessM,
|
||||
NormalM,
|
||||
AmbientOcclusionM,
|
||||
RefractionM,
|
||||
ReflectionM,
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, SpatialMaterial::Feature> fbx_feature_mapping_desc = {
|
||||
/* Transparent */
|
||||
{ "TransparentColor", SpatialMaterial::Feature::FEATURE_TRANSPARENT },
|
||||
{ "Maya|opacity", SpatialMaterial::Feature::FEATURE_TRANSPARENT }
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, SpatialMaterial::TextureParam> fbx_texture_mapping_desc = {
|
||||
/* Diffuse */
|
||||
{ "Maya|base", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "DiffuseColor", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|DiffuseTexture", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor|file", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "3dsMax|Parameters|base_color_map", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map|file", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map", SpatialMaterial::TextureParam::TEXTURE_ALBEDO },
|
||||
/* Emission */
|
||||
{ "EmissiveColor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "EmissiveFactor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor|file", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "3dsMax|Parameters|emission_map", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map|file", SpatialMaterial::TextureParam::TEXTURE_EMISSION },
|
||||
/* Metallic */
|
||||
{ "Maya|metalness", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|metalness|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "3dsMax|Parameters|metalness_map", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "SpecularColor", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|specularColor", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|SpecularTexture", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|SpecularTexture|file", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
{ "ShininessExponent", SpatialMaterial::TextureParam::TEXTURE_METALLIC },
|
||||
/* Roughness */
|
||||
{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "3dsMax|Parameters|roughness_map", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map|file", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "ReflectionFactor", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|specularRoughness", SpatialMaterial::TextureParam::TEXTURE_ROUGHNESS },
|
||||
/* Normal */
|
||||
{ "NormalMap", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Bump", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "3dsMax|Parameters|bump_map", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|NormalTexture", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|normalCamera", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|normalCamera|file", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map|file", SpatialMaterial::TextureParam::TEXTURE_NORMAL },
|
||||
/* AO */
|
||||
{ "Maya|TEX_ao_map", SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
{ "Maya|TEX_ao_map|file", SpatialMaterial::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
// {"TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA },
|
||||
// {"TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
enum PropertyDesc {
|
||||
PROPERTY_DESC_NOT_FOUND,
|
||||
PROPERTY_DESC_ALBEDO_COLOR,
|
||||
PROPERTY_DESC_TRANSPARENT,
|
||||
PROPERTY_DESC_METALLIC,
|
||||
PROPERTY_DESC_ROUGHNESS,
|
||||
PROPERTY_DESC_COAT,
|
||||
PROPERTY_DESC_COAT_ROUGHNESS,
|
||||
PROPERTY_DESC_EMISSIVE,
|
||||
PROPERTY_DESC_EMISSIVE_COLOR,
|
||||
PROPERTY_DESC_IGNORE
|
||||
};
|
||||
|
||||
const std::map<std::string, PropertyDesc> fbx_properties_desc = {
|
||||
/* Albedo */
|
||||
{ "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
{ "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
|
||||
/* Transparent */
|
||||
{ "Opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "TransparencyFactor", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "Maya|opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
|
||||
/* Metallic */
|
||||
{ "Shininess", PROPERTY_DESC_METALLIC },
|
||||
{ "Reflectivity", PROPERTY_DESC_METALLIC },
|
||||
{ "Maya|metalness", PROPERTY_DESC_METALLIC },
|
||||
|
||||
/* Roughness */
|
||||
{ "Maya|diffuseRoughness", PROPERTY_DESC_ROUGHNESS },
|
||||
|
||||
/* Coat */
|
||||
{ "Maya|coat", PROPERTY_DESC_COAT },
|
||||
|
||||
/* Coat roughness */
|
||||
{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS },
|
||||
|
||||
/* Emissive */
|
||||
{ "Maya|emission", PROPERTY_DESC_EMISSIVE },
|
||||
|
||||
/* Emissive color */
|
||||
{ "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
{ "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
|
||||
/* Ignore */
|
||||
{ "Maya", PROPERTY_DESC_IGNORE },
|
||||
{ "Diffuse", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|TypeId", PROPERTY_DESC_IGNORE },
|
||||
{ "Ambient", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientColor", PROPERTY_DESC_IGNORE },
|
||||
{ "ShininessExponent", PROPERTY_DESC_IGNORE },
|
||||
{ "Specular", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularColor", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularFactor", PROPERTY_DESC_IGNORE },
|
||||
//{ "BumpFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|exitToBackground", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectSpecular", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|internalReflections", PROPERTY_DESC_IGNORE },
|
||||
{ "DiffuseFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "ReflectionColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Emissive", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatNormal", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatIOR", PROPERTY_DESC_IGNORE },
|
||||
};
|
||||
|
||||
struct TextureFileMapping {
|
||||
SpatialMaterial::TextureParam map_mode = SpatialMaterial::TEXTURE_ALBEDO;
|
||||
String name = String();
|
||||
const FBXDocParser::Texture *texture = nullptr;
|
||||
};
|
||||
|
||||
/* storing the texture properties like color */
|
||||
template <class T>
|
||||
struct TexturePropertyMapping : Reference {
|
||||
SpatialMaterial::TextureParam map_mode = SpatialMaterial::TextureParam::TEXTURE_ALBEDO;
|
||||
const T property = T();
|
||||
};
|
||||
|
||||
static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths);
|
||||
|
||||
static String find_texture_path_by_filename(const String p_filename, const String p_current_directory);
|
||||
|
||||
String get_material_name() const;
|
||||
|
||||
void set_imported_material(const FBXDocParser::Material *p_material);
|
||||
|
||||
struct MaterialInfo {
|
||||
Vector<TextureFileMapping> textures;
|
||||
Vector<SpatialMaterial::Feature> features;
|
||||
};
|
||||
/// Extracts the material information.
|
||||
MaterialInfo extract_material_info(const FBXDocParser::Material *material) const;
|
||||
|
||||
Ref<SpatialMaterial> import_material(ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_MATERIAL_H
|
1366
modules/fbx/data/fbx_mesh_data.cpp
Normal file
1366
modules/fbx/data/fbx_mesh_data.cpp
Normal file
File diff suppressed because it is too large
Load Diff
175
modules/fbx/data/fbx_mesh_data.h
Normal file
175
modules/fbx/data/fbx_mesh_data.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_mesh_data.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MESH_DATA_H
|
||||
#define FBX_MESH_DATA_H
|
||||
|
||||
#include "core/hash_map.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
struct FBXMeshData;
|
||||
struct FBXBone;
|
||||
struct ImportState;
|
||||
|
||||
struct VertexWeightMapping {
|
||||
Vector<real_t> weights;
|
||||
Vector<int> bones;
|
||||
// This extra vector is used because the bone id is computed in a second step.
|
||||
// TODO Get rid of this extra step is a good idea.
|
||||
Vector<Ref<FBXBone> > bones_ref;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VertexData {
|
||||
int polygon_index;
|
||||
T data;
|
||||
};
|
||||
|
||||
// Caches mesh information and instantiates meshes for you using helper functions.
|
||||
struct FBXMeshData : Reference {
|
||||
struct MorphVertexData {
|
||||
// TODO we have only these??
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> vertices;
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> normals;
|
||||
};
|
||||
|
||||
/// vertex id, Weight Info
|
||||
/// later: perf we can use array here
|
||||
HashMap<int, VertexWeightMapping> vertex_weights;
|
||||
|
||||
// translate fbx mesh data from document context to FBX Mesh Geometry Context
|
||||
bool valid_weight_indexes = false;
|
||||
|
||||
MeshInstance *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *mesh_geometry, const FBXDocParser::Model *model);
|
||||
|
||||
void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
|
||||
|
||||
/* mesh maximum weight count */
|
||||
bool valid_weight_count = false;
|
||||
int max_weight_count = 0;
|
||||
uint64_t armature_id = 0;
|
||||
bool valid_armature_id = false;
|
||||
MeshInstance *godot_mesh_instance = nullptr;
|
||||
|
||||
private:
|
||||
void sanitize_vertex_weights();
|
||||
|
||||
/// Make sure to reorganize the vertices so that the correct UV is taken.
|
||||
/// This step is needed because differently from the normal, that can be
|
||||
/// combined, the UV may need its own triangle because sometimes they have
|
||||
/// really different UV for the same vertex but different polygon.
|
||||
/// This function make sure to add another vertex for those UVS.
|
||||
void reorganize_vertices(
|
||||
std::vector<int> &r_polygon_indices,
|
||||
std::vector<Vector3> &r_vertices,
|
||||
HashMap<int, Vector3> &r_normals,
|
||||
HashMap<int, Vector2> &r_uv_1,
|
||||
HashMap<int, Vector2> &r_uv_2,
|
||||
HashMap<int, Color> &r_color,
|
||||
HashMap<String, MorphVertexData> &r_morphs,
|
||||
HashMap<int, HashMap<int, Vector3> > &r_normals_raw,
|
||||
HashMap<int, HashMap<int, Vector2> > &r_uv_1_raw,
|
||||
HashMap<int, HashMap<int, Vector2> > &r_uv_2_raw);
|
||||
|
||||
void add_vertex(
|
||||
Ref<SurfaceTool> p_surface_tool,
|
||||
real_t p_scale,
|
||||
int p_vertex,
|
||||
const std::vector<Vector3> &p_vertices_position,
|
||||
const HashMap<int, Vector3> &p_normals,
|
||||
const HashMap<int, Vector2> &p_uvs_0,
|
||||
const HashMap<int, Vector2> &p_uvs_1,
|
||||
const HashMap<int, Color> &p_colors,
|
||||
const Vector3 &p_morph_value = Vector3(),
|
||||
const Vector3 &p_morph_normal = Vector3());
|
||||
|
||||
void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const;
|
||||
|
||||
/// This function is responsible to convert the FBX polygon vertex to
|
||||
/// vertex index.
|
||||
/// The polygon vertices are stored in an array with some negative
|
||||
/// values. The negative values define the last face index.
|
||||
/// For example the following `face_array` contains two faces, the former
|
||||
/// with 3 vertices and the latter with a line:
|
||||
/// [0,2,-2,3,-5]
|
||||
/// Parsed as:
|
||||
/// [0, 2, 1, 3, 4]
|
||||
/// The negative values are computed using this formula: `(-value) - 1`
|
||||
///
|
||||
/// Returns the vertex index from the poligon vertex.
|
||||
/// Returns -1 if `p_index` is invalid.
|
||||
int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Retuns true if this polygon_vertex_index is the end of a new polygon.
|
||||
bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Retuns true if this polygon_vertex_index is the begin of a new polygon.
|
||||
bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns the number of polygons.
|
||||
int count_polygons(const std::vector<int> &p_face_indices) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` alligned with vertex.
|
||||
/// Useful to extract normal/uvs/colors/tangets/etc...
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class R, class T>
|
||||
HashMap<int, R> extract_per_vertex_data(
|
||||
int p_vertex_count,
|
||||
const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges,
|
||||
const std::vector<int> &p_mesh_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data,
|
||||
R (*collector_function)(const Vector<VertexData<T> > *p_vertex_data, R p_fall_back),
|
||||
R p_fall_back) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` organized per polygon.
|
||||
/// Useful to extract the materila
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class T>
|
||||
HashMap<int, T> extract_per_polygon(
|
||||
int p_vertex_count,
|
||||
const std::vector<int> &p_face_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data,
|
||||
T p_fallback_value) const;
|
||||
|
||||
/// Extracts the morph data and organizes it per vertices.
|
||||
/// The returned `MorphVertexData` arrays are never something different
|
||||
/// then the `vertex_count`.
|
||||
void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data);
|
||||
};
|
||||
|
||||
#endif // FBX_MESH_DATA_H
|
63
modules/fbx/data/fbx_node.h
Normal file
63
modules/fbx/data/fbx_node.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_node.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_NODE_H
|
||||
#define FBX_NODE_H
|
||||
|
||||
#include "fbx_skeleton.h"
|
||||
#include "model_abstraction.h"
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
class Spatial;
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXNode : Reference, ModelAbstraction {
|
||||
uint64_t current_node_id = 0;
|
||||
String node_name = String();
|
||||
Spatial *godot_node = nullptr;
|
||||
|
||||
// used to parent the skeleton once the tree is built.
|
||||
Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>();
|
||||
|
||||
void set_parent(Ref<FBXNode> p_parent) {
|
||||
fbx_parent = p_parent;
|
||||
}
|
||||
|
||||
void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) {
|
||||
pivot_transform = p_pivot_transform;
|
||||
}
|
||||
|
||||
Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data
|
||||
Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node
|
||||
};
|
||||
|
||||
#endif // FBX_NODE_H
|
124
modules/fbx/data/fbx_skeleton.cpp
Normal file
124
modules/fbx/data/fbx_skeleton.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_skeleton.h"
|
||||
|
||||
#include "import_state.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void FBXSkeleton::init_skeleton(const ImportState &state) {
|
||||
int skeleton_bone_count = skeleton_bones.size();
|
||||
|
||||
if (skeleton == nullptr && skeleton_bone_count > 0) {
|
||||
skeleton = memnew(Skeleton);
|
||||
|
||||
Ref<FBXNode> skeleton_parent_node;
|
||||
if (fbx_node.is_valid()) {
|
||||
// cache skeleton attachment for later during node creation
|
||||
// can't be done until after node hierarchy is built
|
||||
if (fbx_node->godot_node != state.root) {
|
||||
fbx_node->skeleton_node = Ref<FBXSkeleton>(this);
|
||||
print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name);
|
||||
} else {
|
||||
// root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton)
|
||||
fbx_node->godot_node->add_child(skeleton);
|
||||
skeleton->set_owner(state.root_owner);
|
||||
skeleton->set_name("Skeleton");
|
||||
print_verbose("created armature skeleton for root");
|
||||
}
|
||||
} else {
|
||||
memfree(skeleton);
|
||||
skeleton = nullptr;
|
||||
print_error("[doc] skeleton has no valid node to parent nodes to - erasing");
|
||||
skeleton_bones.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the bone name uniques.
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
// Make sure the bone name is unique.
|
||||
const String bone_name = bone->bone_name;
|
||||
int same_name_count = 0;
|
||||
for (int y = x; y < skeleton_bone_count; y++) {
|
||||
Ref<FBXBone> other_bone = skeleton_bones[y];
|
||||
if (other_bone.is_valid()) {
|
||||
if (other_bone->bone_name == bone_name) {
|
||||
same_name_count += 1;
|
||||
other_bone->bone_name += "_" + itos(same_name_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<int, Ref<FBXBone> > bone_map;
|
||||
// implement fbx cluster skin logic here this is where it goes
|
||||
int bone_count = 0;
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
skeleton->add_bone(bone->bone_name);
|
||||
bone->godot_bone_id = bone_count;
|
||||
bone->fbx_skeleton = Ref<FBXSkeleton>(this);
|
||||
bone_map.insert(bone_count, bone);
|
||||
print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name);
|
||||
bone_count++;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?");
|
||||
|
||||
for (Map<int, Ref<FBXBone> >::Element *bone_element = bone_map.front(); bone_element; bone_element = bone_element->next()) {
|
||||
Ref<FBXBone> bone = bone_element->value();
|
||||
int bone_index = bone_element->key();
|
||||
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
|
||||
|
||||
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->pivot_xform->LocalTransform, state.scale));
|
||||
|
||||
// lookup parent ID
|
||||
if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
|
||||
Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id];
|
||||
int bone_id = skeleton->find_bone(parent_bone->bone_name);
|
||||
if (bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, bone_id);
|
||||
} else {
|
||||
print_error("invalid bone parent: " + parent_bone->bone_name);
|
||||
}
|
||||
} else {
|
||||
if (bone->godot_bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, -1); // no parent for this bone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
modules/fbx/data/fbx_skeleton.h
Normal file
53
modules/fbx/data/fbx_skeleton.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_SKELETON_H
|
||||
#define FBX_SKELETON_H
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_node.h"
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "scene/3d/skeleton.h"
|
||||
|
||||
struct FBXNode;
|
||||
struct ImportState;
|
||||
struct FBXBone;
|
||||
|
||||
struct FBXSkeleton : Reference, ModelAbstraction {
|
||||
Ref<FBXNode> fbx_node = Ref<FBXNode>();
|
||||
Vector<Ref<FBXBone> > skeleton_bones = Vector<Ref<FBXBone> >();
|
||||
Skeleton *skeleton = nullptr;
|
||||
|
||||
void init_skeleton(const ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_SKELETON_H
|
@ -28,8 +28,12 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORT_STATE_H
|
||||
#define EDITOR_SCENE_IMPORT_STATE_H
|
||||
#ifndef IMPORT_STATE_H
|
||||
#define IMPORT_STATE_H
|
||||
|
||||
#include "fbx_mesh_data.h"
|
||||
#include "modules/fbx/tools/import_utils.h"
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "core/bind/core_bind.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
@ -43,91 +47,64 @@
|
||||
#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 "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
#include "modules/fbx/fbx_parser/FBXImportSettings.h"
|
||||
#include "modules/fbx/fbx_parser/FBXMeshGeometry.h"
|
||||
#include "modules/fbx/fbx_parser/FBXParser.h"
|
||||
#include "modules/fbx/fbx_parser/FBXTokenizer.h"
|
||||
#include "modules/fbx/fbx_parser/FBXUtil.h"
|
||||
|
||||
struct FBXBone;
|
||||
struct FBXMeshData;
|
||||
struct FBXNode;
|
||||
struct FBXSkeleton;
|
||||
|
||||
namespace AssimpImporter {
|
||||
/** Import state is for global scene import data
|
||||
* This makes the code simpler and contains useful lookups.
|
||||
*/
|
||||
struct ImportState {
|
||||
bool enable_material_import = true;
|
||||
bool enable_animation_import = true;
|
||||
|
||||
String path;
|
||||
Spatial *root;
|
||||
const aiScene *assimp_scene;
|
||||
uint32_t max_bone_weights;
|
||||
Map<StringName, Ref<Texture> > cached_image_searches;
|
||||
Map<uint64_t, Ref<SpatialMaterial> > cached_materials;
|
||||
|
||||
Map<String, Ref<Mesh> > mesh_cache;
|
||||
Map<int, Ref<Material> > material_cache;
|
||||
Map<String, int> light_cache;
|
||||
Map<String, int> camera_cache;
|
||||
String path = String();
|
||||
Spatial *root_owner = nullptr;
|
||||
Spatial *root = nullptr;
|
||||
real_t scale = 0.01;
|
||||
Ref<FBXNode> fbx_root_node = Ref<FBXNode>();
|
||||
// skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically.
|
||||
Map<uint64_t, Ref<FBXSkeleton> > skeleton_map = Map<uint64_t, Ref<FBXSkeleton> >();
|
||||
|
||||
// very useful for when you need to ask assimp for the bone mesh
|
||||
// nodes on the same level get merged automatically.
|
||||
//Map<uint64_t, Skeleton *> armature_map;
|
||||
AnimationPlayer *animation_player = nullptr;
|
||||
|
||||
Map<const aiNode *, Node *> assimp_node_map;
|
||||
Map<String, Ref<Image> > path_to_image_cache;
|
||||
// Generation 4 - Raw document accessing for bone/skin/joint/kLocators
|
||||
// joints are not necessarily bones but must be merged into the skeleton
|
||||
// (bone id), bone
|
||||
Map<uint64_t, Ref<FBXBone> > fbx_bone_map = Map<uint64_t, Ref<FBXBone> >(); // this is the bone name and setup information required for joints
|
||||
// this will never contain joints only bones attached to a mesh.
|
||||
|
||||
// Generation 3 - determinisitic iteration
|
||||
// to lower potential recursion errors
|
||||
List<const aiNode *> nodes;
|
||||
Map<const aiNode *, Spatial *> flat_node_map;
|
||||
AnimationPlayer *animation_player;
|
||||
// Generation 4 - Raw document for creating the nodes transforms in the scene
|
||||
// this is a list of the nodes in the scene
|
||||
// (id, node)
|
||||
List<Ref<FBXNode> > fbx_node_list = List<Ref<FBXNode> >();
|
||||
|
||||
// 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 *, Skeleton *> armature_skeletons;
|
||||
Map<aiBone *, Skeleton *> 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;
|
||||
// All nodes which have been created in the scene
|
||||
// this will not contain the root node of the scene
|
||||
Map<uint64_t, Ref<FBXNode> > fbx_target_map = Map<uint64_t, Ref<FBXNode> >();
|
||||
|
||||
// EditorSceneImporter::ImportFlags
|
||||
uint32_t import_flags;
|
||||
// mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins
|
||||
Map<uint64_t, Ref<FBXNode> > MeshNodes = Map<uint64_t, Ref<FBXNode> >();
|
||||
// mesh skin map
|
||||
Map<uint64_t, Ref<Skin> > MeshSkins = Map<uint64_t, Ref<Skin> >();
|
||||
|
||||
// this is the container for the mesh weight information and eventually
|
||||
// any mesh data
|
||||
// but not the skin, just stuff important for rendering
|
||||
// skin is applied to mesh instance so not really required to be in here yet.
|
||||
// maybe later
|
||||
// fbx mesh id, FBXMeshData
|
||||
Map<uint64_t, Ref<FBXMeshData> > renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData> >();
|
||||
};
|
||||
|
||||
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,
|
||||
Skeleton *_skeleton,
|
||||
Spatial *_new_node,
|
||||
String &_node_name,
|
||||
aiNode *_assimp_node,
|
||||
Node *_parent_node,
|
||||
aiBone *_bone) :
|
||||
node_transform(_node_transform),
|
||||
skeleton(_skeleton),
|
||||
new_node(_new_node),
|
||||
node_name(_node_name),
|
||||
assimp_node(_assimp_node),
|
||||
parent_node(_parent_node),
|
||||
bone(_bone) {}
|
||||
|
||||
Transform node_transform;
|
||||
Skeleton *skeleton = NULL;
|
||||
Spatial *new_node = NULL;
|
||||
String node_name;
|
||||
aiNode *assimp_node = NULL;
|
||||
Node *parent_node = NULL;
|
||||
aiBone *bone = NULL;
|
||||
};
|
||||
} // namespace AssimpImporter
|
||||
|
||||
#endif // EDITOR_SCENE_IMPORT_STATE_H
|
||||
#endif // IMPORT_STATE_H
|
52
modules/fbx/data/model_abstraction.h
Normal file
52
modules/fbx/data/model_abstraction.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*************************************************************************/
|
||||
/* model_abstraction.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MODEL_ABSTRACTION_H
|
||||
#define MODEL_ABSTRACTION_H
|
||||
|
||||
#include "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
|
||||
struct ModelAbstraction {
|
||||
mutable const FBXDocParser::Model *fbx_model = nullptr;
|
||||
|
||||
void set_model(const FBXDocParser::Model *p_model) {
|
||||
fbx_model = p_model;
|
||||
}
|
||||
|
||||
bool has_model() const {
|
||||
return fbx_model != nullptr;
|
||||
}
|
||||
|
||||
const FBXDocParser::Model *get_model() const {
|
||||
return fbx_model;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MODEL_ABSTRACTION_H
|
257
modules/fbx/data/pivot_transform.cpp
Normal file
257
modules/fbx/data/pivot_transform.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void PivotTransform::ReadTransformChain() {
|
||||
const FBXDocParser::PropertyTable *props = fbx_model->Props();
|
||||
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
|
||||
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
|
||||
inherit_type = inheritType; // copy the inherit type we need it in the second step.
|
||||
print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType()));
|
||||
bool ok = false;
|
||||
raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok));
|
||||
if (ok) {
|
||||
pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation));
|
||||
print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok));
|
||||
if (ok) {
|
||||
post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation));
|
||||
print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok));
|
||||
if (ok) {
|
||||
rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot);
|
||||
}
|
||||
const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok));
|
||||
if (ok) {
|
||||
rotation_offset = ImportUtils::FixAxisConversions(RotationOffset);
|
||||
}
|
||||
const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok));
|
||||
if (ok) {
|
||||
scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset);
|
||||
}
|
||||
const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok));
|
||||
if (ok) {
|
||||
scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot);
|
||||
}
|
||||
const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok));
|
||||
if (ok) {
|
||||
translation = ImportUtils::FixAxisConversions(Translation);
|
||||
}
|
||||
raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok));
|
||||
if (ok) {
|
||||
rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation));
|
||||
}
|
||||
const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok));
|
||||
if (ok) {
|
||||
scaling = Scaling;
|
||||
}
|
||||
const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok));
|
||||
if (ok) {
|
||||
geometric_scaling = GeometricScaling;
|
||||
}
|
||||
const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok));
|
||||
if (ok) {
|
||||
geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation));
|
||||
}
|
||||
const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok));
|
||||
if (ok) {
|
||||
geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation);
|
||||
}
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(p_rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
}
|
||||
|
||||
Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(p_rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
Transform parent_global_xform;
|
||||
Transform parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform local_rotation_m, parent_global_rotation_m;
|
||||
Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
|
||||
parent_global_rotation_m.basis.set_quat(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
|
||||
|
||||
Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
//Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
|
||||
|
||||
// manual hack to force SSC not to be compensated for - until we can handle it properly with tests
|
||||
return parent_global_xform * local_transform;
|
||||
}
|
||||
|
||||
void PivotTransform::ComputePivotTransform() {
|
||||
Transform T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
if (!scaling.is_equal_approx(Vector3())) {
|
||||
S.scale(scaling);
|
||||
} else {
|
||||
S.scale(Vector3(1, 1, 1));
|
||||
}
|
||||
Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this.
|
||||
|
||||
// Rotation pivots
|
||||
Transform Rpre = Transform(pre_rotation);
|
||||
Transform R = Transform(rotation);
|
||||
Transform Rpost = Transform(post_rotation);
|
||||
|
||||
Transform parent_global_xform;
|
||||
Transform parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform local_rotation_m, parent_global_rotation_m;
|
||||
Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
|
||||
parent_global_rotation_m.basis.set_quat(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
|
||||
|
||||
Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
LocalTransform = Transform();
|
||||
LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
|
||||
ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
|
||||
|
||||
Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
|
||||
GlobalTransform = Transform();
|
||||
//GlobalTransform = parent_global_xform * LocalTransform;
|
||||
Transform global_origin = Transform(Basis(), parent_translation);
|
||||
GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale;
|
||||
|
||||
ImportUtils::debug_xform("local xform calculation", LocalTransform);
|
||||
print_verbose("scale of node: " + S.basis.get_scale_local());
|
||||
print_verbose("---------------------------------------------------------------");
|
||||
}
|
||||
|
||||
void PivotTransform::Execute() {
|
||||
ReadTransformChain();
|
||||
ComputePivotTransform();
|
||||
|
||||
ImportUtils::debug_xform("global xform: ", GlobalTransform);
|
||||
computed_global_xform = true;
|
||||
}
|
112
modules/fbx/data/pivot_transform.h
Normal file
112
modules/fbx/data/pivot_transform.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PIVOT_TRANSFORM_H
|
||||
#define PIVOT_TRANSFORM_H
|
||||
|
||||
#include "core/reference.h"
|
||||
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
enum TransformationComp {
|
||||
TransformationComp_Translation,
|
||||
TransformationComp_Scaling,
|
||||
TransformationComp_Rotation,
|
||||
TransformationComp_RotationOffset,
|
||||
TransformationComp_RotationPivot,
|
||||
TransformationComp_PreRotation,
|
||||
TransformationComp_PostRotation,
|
||||
TransformationComp_ScalingOffset,
|
||||
TransformationComp_ScalingPivot,
|
||||
TransformationComp_GeometricTranslation,
|
||||
TransformationComp_GeometricRotation,
|
||||
TransformationComp_GeometricScaling,
|
||||
TransformationComp_MAXIMUM
|
||||
};
|
||||
// Abstract away pivot data so its simpler to handle
|
||||
struct PivotTransform : Reference, ModelAbstraction {
|
||||
|
||||
// at the end we want to keep geometric_ everything, post and pre rotation
|
||||
// these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
|
||||
Quat pre_rotation = Quat();
|
||||
Quat post_rotation = Quat();
|
||||
Quat rotation = Quat();
|
||||
Quat geometric_rotation = Quat();
|
||||
Vector3 rotation_pivot = Vector3();
|
||||
Vector3 rotation_offset = Vector3();
|
||||
Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 translation = Vector3();
|
||||
Vector3 scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_translation = Vector3();
|
||||
|
||||
Vector3 raw_rotation = Vector3();
|
||||
Vector3 raw_post_rotation = Vector3();
|
||||
Vector3 raw_pre_rotation = Vector3();
|
||||
|
||||
/* Read pivots from the document */
|
||||
void ReadTransformChain();
|
||||
|
||||
void debug_pivot_xform(String p_name) {
|
||||
print_verbose("debugging node name: " + p_name);
|
||||
print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI));
|
||||
print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI));
|
||||
print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI));
|
||||
}
|
||||
Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
|
||||
Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
|
||||
|
||||
/* Extract into xforms and calculate once */
|
||||
void ComputePivotTransform();
|
||||
|
||||
/* Execute the command for the pivot generation */
|
||||
void Execute();
|
||||
|
||||
void set_parent(Ref<PivotTransform> p_parent) {
|
||||
parent_transform = p_parent;
|
||||
}
|
||||
|
||||
bool computed_global_xform = false;
|
||||
Ref<PivotTransform> parent_transform = Ref<PivotTransform>();
|
||||
//Transform chain[TransformationComp_MAXIMUM];
|
||||
|
||||
// cached for later use
|
||||
Transform GlobalTransform = Transform();
|
||||
Transform LocalTransform = Transform();
|
||||
Transform Local_Scaling_Matrix = Transform(); // used for inherit type.
|
||||
Transform GeometricTransform = Transform(); // 3DS max only
|
||||
FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3
|
||||
};
|
||||
|
||||
#endif // PIVOT_TRANSFORM_H
|
1428
modules/fbx/editor_scene_importer_fbx.cpp
Normal file
1428
modules/fbx/editor_scene_importer_fbx.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*************************************************************************/
|
||||
/* editor_scene_importer_assimp.h */
|
||||
/* editor_scene_importer_fbx.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
@ -28,10 +28,14 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_ASSIMP_H
|
||||
#define EDITOR_SCENE_IMPORTER_ASSIMP_H
|
||||
#ifndef EDITOR_SCENE_IMPORTER_FBX_H
|
||||
#define EDITOR_SCENE_IMPORTER_FBX_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/bind/core_bind.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/vector.h"
|
||||
@ -44,35 +48,16 @@
|
||||
#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 "fbx_parser/FBXDocument.h"
|
||||
#include "fbx_parser/FBXImportSettings.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "fbx_parser/FBXUtil.h"
|
||||
|
||||
#include "import_state.h"
|
||||
#include "import_utils.h"
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
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 {
|
||||
class EditorSceneImporterFBX : public EditorSceneImporter {
|
||||
private:
|
||||
GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter);
|
||||
GDCLASS(EditorSceneImporterFBX, EditorSceneImporter);
|
||||
|
||||
struct AssetImportAnimation {
|
||||
enum Interpolation {
|
||||
@ -83,67 +68,65 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
struct BoneInfo {
|
||||
uint32_t bone;
|
||||
float weight;
|
||||
};
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessDOMConnection(
|
||||
const FBXDocParser::Document *doc,
|
||||
uint64_t current_element,
|
||||
bool reverse_lookup = false) {
|
||||
|
||||
Ref<Mesh> _generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
|
||||
const aiNode *assimp_node, Ref<Skin> &skin,
|
||||
Skeleton *&skeleton_assigned);
|
||||
const std::vector<const FBXDocParser::Connection *> &conns = reverse_lookup ? doc->GetConnectionsByDestinationSequenced(current_element) : doc->GetConnectionsBySourceSequenced(current_element);
|
||||
//print_verbose("[doc] looking for " + String(element_to_find));
|
||||
// using the temp pattern here so we can debug before it returns
|
||||
// in some cases we return too early, with 'deformer object base class' in wrong place
|
||||
// in assimp this means we can accidentally return too early...
|
||||
const T *return_obj = nullptr;
|
||||
|
||||
// simple object creation functions
|
||||
Spatial *create_light(ImportState &state,
|
||||
const String &node_name,
|
||||
Transform &look_at_transform);
|
||||
Spatial *create_camera(
|
||||
ImportState &state,
|
||||
const String &node_name,
|
||||
Transform &look_at_transform);
|
||||
// non recursive - linear so must not use recursive arguments
|
||||
MeshInstance *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform);
|
||||
// recursive node generator
|
||||
void _generate_node(ImportState &state, const aiNode *assimp_node);
|
||||
void _insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
|
||||
int anim_fps, Ref<Animation> animation, float ticks_per_second,
|
||||
Skeleton *skeleton, const NodePath &node_path,
|
||||
const String &node_name, aiBone *track_bone);
|
||||
for (const FBXDocParser::Connection *con : conns) {
|
||||
const FBXDocParser::Object *source_object = con->SourceObject();
|
||||
const FBXDocParser::Object *dest_object = con->DestinationObject();
|
||||
if (source_object && dest_object != nullptr) {
|
||||
//print_verbose("[doc] connection name: " + String(source_object->Name().c_str()) + ", dest: " + String(dest_object->Name().c_str()));
|
||||
const T *temp = dynamic_cast<const T *>(reverse_lookup ? source_object : dest_object);
|
||||
if (temp) {
|
||||
return_obj = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _import_animation(ImportState &state, int p_animation_index, int p_bake_fps);
|
||||
Node *get_node_by_name(ImportState &state, String name);
|
||||
aiBone *get_bone_from_stack(ImportState &state, aiString name);
|
||||
Spatial *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
|
||||
if (return_obj != nullptr) {
|
||||
//print_verbose("[doc] returned valid element");
|
||||
//print_verbose("Found object for bone");
|
||||
return return_obj;
|
||||
}
|
||||
|
||||
// safe to return nothing, need to use nullptr here as nullptr is used internally for FBX document.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BuildDocumentBones(Ref<FBXBone> p_parent_bone,
|
||||
ImportState &state, const FBXDocParser::Document *p_doc,
|
||||
uint64_t p_id);
|
||||
|
||||
void BuildDocumentNodes(Ref<PivotTransform> parent_transform, ImportState &state, const FBXDocParser::Document *doc, uint64_t id, Ref<FBXNode> fbx_parent);
|
||||
|
||||
Spatial *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
|
||||
const uint32_t p_flags,
|
||||
int p_bake_fps, const 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();
|
||||
}
|
||||
EditorSceneImporterFBX() {}
|
||||
~EditorSceneImporterFBX() {}
|
||||
|
||||
virtual void get_extensions(List<String> *r_extensions) const;
|
||||
virtual uint32_t get_import_flags() const;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
|
||||
Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path);
|
||||
|
||||
static void RegenerateBoneStack(ImportState &state);
|
||||
|
||||
void RegenerateBoneStack(ImportState &state, aiMesh *mesh);
|
||||
void create_mesh_data_skin(ImportState &state, const Ref<FBXNode> &fbx_node, uint64_t mesh_id);
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
#endif // EDITOR_SCENE_IMPORTER_FBX_H
|
283
modules/fbx/fbx_parser/ByteSwapper.h
Normal file
283
modules/fbx/fbx_parser/ByteSwapper.h
Normal file
@ -0,0 +1,283 @@
|
||||
/*************************************************************************/
|
||||
/* ByteSwapper.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Helper class tp perform various byte oder swappings
|
||||
(e.g. little to big endian) */
|
||||
#ifndef BYTE_SWAPPER_H
|
||||
#define BYTE_SWAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
namespace FBXDocParser {
|
||||
// --------------------------------------------------------------------------------------
|
||||
/** Defines some useful byte order swap routines.
|
||||
*
|
||||
* This is required to read big-endian model formats on little-endian machines,
|
||||
* and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ByteSwap {
|
||||
ByteSwap() {}
|
||||
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[3]);
|
||||
std::swap(szOut[1], szOut[2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[7]);
|
||||
std::swap(szOut[1], szOut[6]);
|
||||
std::swap(szOut[2], szOut[5]);
|
||||
std::swap(szOut[3], szOut[4]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
//! Templatized ByteSwap
|
||||
//! \returns param tOut as swapped
|
||||
template <typename Type>
|
||||
static inline Type Swapped(Type tOut) {
|
||||
return _swapper<Type, sizeof(Type)>()(tOut);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, size_t size>
|
||||
struct _swapper;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 2> {
|
||||
T operator()(T tOut) {
|
||||
Swap2(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 4> {
|
||||
T operator()(T tOut) {
|
||||
Swap4(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 8> {
|
||||
T operator()(T tOut) {
|
||||
Swap8(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ByteSwap macros for BigEndian/LittleEndian support
|
||||
// --------------------------------------------------------------------------------------
|
||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||
#define AI_LE(t) (t)
|
||||
#define AI_BE(t) ByteSwap::Swapped(t)
|
||||
#define AI_LSWAP2(p)
|
||||
#define AI_LSWAP4(p)
|
||||
#define AI_LSWAP8(p)
|
||||
#define AI_LSWAP2P(p)
|
||||
#define AI_LSWAP4P(p)
|
||||
#define AI_LSWAP8P(p)
|
||||
#define LE_NCONST const
|
||||
#define AI_SWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_SWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_SWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_SWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_SWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_SWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define BE_NCONST
|
||||
#else
|
||||
#define AI_BE(t) (t)
|
||||
#define AI_LE(t) ByteSwap::Swapped(t)
|
||||
#define AI_SWAP2(p)
|
||||
#define AI_SWAP4(p)
|
||||
#define AI_SWAP8(p)
|
||||
#define AI_SWAP2P(p)
|
||||
#define AI_SWAP4P(p)
|
||||
#define AI_SWAP8P(p)
|
||||
#define BE_NCONST const
|
||||
#define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_LSWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_LSWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_LSWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define LE_NCONST
|
||||
#endif
|
||||
|
||||
namespace Intern {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <typename T, bool doit>
|
||||
struct ByteSwapper {
|
||||
void operator()(T *inout) {
|
||||
ByteSwap::Swap(inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwapper<T, false> {
|
||||
void operator()(T *) {
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
|
||||
struct Getter {
|
||||
void operator()(T *inout, bool le) {
|
||||
le = !le;
|
||||
if (le) {
|
||||
ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
|
||||
} else
|
||||
ByteSwapper<T, false>()(inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <bool SwapEndianess, typename T>
|
||||
struct Getter<SwapEndianess, T, false> {
|
||||
|
||||
void operator()(T *inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T, (SwapEndianess && sizeof(T) > 1)>()(inout);
|
||||
}
|
||||
};
|
||||
} // namespace Intern
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // BYTE_SWAPPER_H
|
@ -60,7 +60,7 @@ The GUY who performed some of the CSM mocaps.
|
||||
Contributed fixes for the documentation and the doxygen markup
|
||||
|
||||
- Zhao Lei
|
||||
Contributed several bugfixes fixing memory leaks and improving float parsing
|
||||
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.
|
||||
@ -129,7 +129,7 @@ Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
|
||||
Contributed the Debian build fixes ( architecture macro ).
|
||||
|
||||
- gellule
|
||||
Several LWO and LWS fixes (pivoting).
|
||||
Several LWO and LWS fixes (pivoting).
|
||||
|
||||
- Marcel Metz
|
||||
GCC/Linux fixes for the SimpleOpenGL sample.
|
294
modules/fbx/fbx_parser/FBXAnimation.cpp
Normal file
294
modules/fbx/fbx_parser/FBXAnimation.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
/*************************************************************************/
|
||||
/* FBXAnimation.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXAnimation.cpp
|
||||
* @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
|
||||
* Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
|
||||
*/
|
||||
|
||||
#include "FBXCommon.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document & /*doc*/) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr KeyTime = GetRequiredElement(sc, "KeyTime");
|
||||
const ElementPtr KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
|
||||
|
||||
// note preserved keys and values for legacy FBXConverter.cpp
|
||||
// we can remove this once the animation system is written
|
||||
// and clean up this code so we do not have copies everywhere.
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
|
||||
if (keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values", KeyTime);
|
||||
}
|
||||
|
||||
// put the two lists into the map, underlying container is really just a dictionary
|
||||
// these will always match, if not an error will throw and the file will not import
|
||||
// this is useful because we then can report something and fix this later if it becomes an issue
|
||||
// at this point we do not need a different count of these elements so this makes the
|
||||
// most sense to do.
|
||||
for (size_t x = 0; x < keys.size(); x++) {
|
||||
keyvalues[keys[x]] = values[x];
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrDataFloat = sc->GetElement("KeyAttrDataFloat");
|
||||
if (KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, KeyAttrDataFloat);
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrFlags = sc->GetElement("KeyAttrFlags");
|
||||
if (KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, KeyAttrFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::~AnimationCurve() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
|
||||
const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
|
||||
size_t whitelist_size /*= 0*/) :
|
||||
Object(id, element, name), target(), doc(doc) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// find target node
|
||||
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *object = con->DestinationObject();
|
||||
|
||||
if (!object) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
target = object;
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::~AnimationCurveNode() {
|
||||
curves.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationMap &AnimationCurveNode::Curves() const {
|
||||
/* Lazy loaded animation curves, will only load if required */
|
||||
if (curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// So the advantage of having this STL boilerplate is that it's dead simple once you get it.
|
||||
// The other advantage is casting is guaranteed to be safe and nullptr will be returned in the last step if it fails.
|
||||
Object *ob = con->SourceObject();
|
||||
AnimationCurve *anim_curve = dynamic_cast<AnimationCurve *>(ob);
|
||||
ERR_CONTINUE_MSG(!anim_curve, "Failed to convert animation curve from object");
|
||||
|
||||
curves.insert(std::make_pair(con->PropertyName(), anim_curve));
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), doc(doc) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// note: the props table here bears little importance and is usually absent
|
||||
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::~AnimationLayer() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist,
|
||||
size_t whitelist_size /*= 0*/) const {
|
||||
AnimationCurveNodeList nodes;
|
||||
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurveNode *anim = dynamic_cast<AnimationCurveNode *>(ob);
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_prop_whitelist) {
|
||||
const char *s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
|
||||
props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
|
||||
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationLayer *anim = dynamic_cast<const AnimationLayer *>(ob);
|
||||
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::~AnimationStack() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
470
modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
Normal file
470
modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
Normal file
@ -0,0 +1,470 @@
|
||||
/*************************************************************************/
|
||||
/* FBXBinaryTokenizer.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
/** @file FBXBinaryTokenizer.cpp
|
||||
* @brief Implementation of a fake lexer for binary fbx files -
|
||||
* we emit tokens so the parser needs almost no special handling
|
||||
* for binary files.
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FBXDocParser {
|
||||
//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) :
|
||||
sbegin(sbegin),
|
||||
send(send),
|
||||
type(type),
|
||||
line(offset),
|
||||
column(BINARY_MARKER) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
// calc length
|
||||
// measure from sBegin to sEnd and validate?
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal tokenization error
|
||||
void TokenizeError(const std::string &message, size_t offset) {
|
||||
print_error("[FBX-Tokenize] " + String(message.c_str()) + ", offset " + itos(offset));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Offset(const char *begin, const char *cursor) {
|
||||
//ai_assert(begin <= cursor);
|
||||
|
||||
return cursor - begin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, const char *begin, const char *cursor) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t ReadWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint32_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint32_t word;
|
||||
::memcpy(&word, cursor, 4);
|
||||
AI_SWAP4(word);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint64_t ReadDoubleWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint64_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadDoubleWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
|
||||
::memcpy(&dword, cursor, sizeof(uint64_t));
|
||||
AI_SWAP8(dword);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return dword;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint8_t ReadByte(const char *input, const char *&cursor, const char *end) {
|
||||
if (Offset(cursor, end) < sizeof(uint8_t)) {
|
||||
TokenizeError("cannot ReadByte, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint8_t word; /* = *reinterpret_cast< const uint8_t* >( cursor )*/
|
||||
::memcpy(&word, cursor, sizeof(uint8_t));
|
||||
++cursor;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const char *input,
|
||||
const char *&cursor, const char *end, bool long_length = false, bool allow_null = false) {
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if (Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length", input, cursor);
|
||||
}
|
||||
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
|
||||
send_out = cursor;
|
||||
|
||||
if (!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if (sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string", input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) {
|
||||
if (Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
|
||||
}
|
||||
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
|
||||
switch (type) {
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall through
|
||||
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
|
||||
// raw binary data
|
||||
case 'R': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i':
|
||||
case 'c': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
|
||||
// compute length based on type and check against the stored value
|
||||
if (encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch (type) {
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
stride = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
//ai_assert(stride > 0);
|
||||
if (length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims", input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding", input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
}
|
||||
|
||||
// string
|
||||
case 'S': {
|
||||
const char *sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
|
||||
}
|
||||
|
||||
if (cursor > end) {
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
|
||||
}
|
||||
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) {
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if (!end_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range", input, cursor);
|
||||
} else if (end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range", input, cursor);
|
||||
}
|
||||
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// the third data word contains the length of the property list
|
||||
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// now comes the name of the scope/key
|
||||
const char *sbeg, *send;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
|
||||
|
||||
// now come the individual properties
|
||||
const char *begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
|
||||
|
||||
if (i != prop_count - 1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong", input, cursor);
|
||||
}
|
||||
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
|
||||
const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t) * 3 + 1) : (sizeof(uint32_t) * 3 + 1);
|
||||
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
if (end_offset - Offset(input, cursor) < sentinel_block_length) {
|
||||
TokenizeError("insufficient padding bytes at block end", input, cursor);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor)));
|
||||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
|
||||
|
||||
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
|
||||
if (cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
|
||||
}
|
||||
}
|
||||
cursor += sentinel_block_length;
|
||||
}
|
||||
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong", input, cursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) {
|
||||
|
||||
if (length < 0x1b) {
|
||||
//TokenizeError("file is too short",0);
|
||||
}
|
||||
|
||||
//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);
|
||||
print_verbose("FBX Version: " + itos(version));
|
||||
//ASSIMP_LOG_DEBUG_F("FBX version: ", version);
|
||||
const bool is64bits = version >= 7500;
|
||||
const char *end = input + length;
|
||||
while (cursor < end) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
110
modules/fbx/fbx_parser/FBXCommon.h
Normal file
110
modules/fbx/fbx_parser/FBXCommon.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*************************************************************************/
|
||||
/* FBXCommon.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXCommon.h
|
||||
* Some useful constants and enums for dealing with FBX files.
|
||||
*/
|
||||
#ifndef FBX_COMMON_H
|
||||
#define FBX_COMMON_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
const std::string NULL_RECORD = { // 13 null bytes
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||
}; // who knows why
|
||||
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
|
||||
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||
|
||||
// rotation order. We'll probably use EulerXYZ for everything
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0,
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
|
||||
RotOrder_SphericXYZ,
|
||||
|
||||
RotOrder_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
Transform_RSrs = 1,
|
||||
Transform_Rrs = 2,
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_COMMON_H
|
279
modules/fbx/fbx_parser/FBXDeformer.cpp
Normal file
279
modules/fbx/fbx_parser/FBXDeformer.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDeformer.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/math/transform.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::~Deformer() {
|
||||
}
|
||||
|
||||
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
// used something.fbx as this is a cache name.
|
||||
props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
|
||||
}
|
||||
|
||||
Constraint::~Constraint() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name), valid_transformAssociateModel(false) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "cluster element: " << element.first << std::endl;
|
||||
// }
|
||||
//
|
||||
// element: Indexes
|
||||
// element: Transform
|
||||
// element: TransformAssociateModel
|
||||
// element: TransformLink
|
||||
// element: UserData
|
||||
// element: Version
|
||||
// element: Weights
|
||||
|
||||
const ElementPtr Indexes = sc->GetElement("Indexes");
|
||||
const ElementPtr Weights = sc->GetElement("Weights");
|
||||
|
||||
const ElementPtr TransformAssociateModel = sc->GetElement("TransformAssociateModel");
|
||||
if (TransformAssociateModel != nullptr) {
|
||||
//Transform t = ReadMatrix(*TransformAssociateModel);
|
||||
link_mode = SkinLinkMode_Additive;
|
||||
valid_transformAssociateModel = true;
|
||||
} else {
|
||||
link_mode = SkinLinkMode_Normalized;
|
||||
valid_transformAssociateModel = false;
|
||||
}
|
||||
|
||||
const ElementPtr Transform = GetRequiredElement(sc, "Transform", element);
|
||||
const ElementPtr TransformLink = GetRequiredElement(sc, "TransformLink", element);
|
||||
|
||||
// todo: check if we need this
|
||||
//const Element& TransformAssociateModel = GetRequiredElement(sc, "TransformAssociateModel", &element);
|
||||
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster", element);
|
||||
}
|
||||
|
||||
if (Indexes) {
|
||||
ParseVectorDataArray(indices, Indexes);
|
||||
ParseVectorDataArray(weights, Weights);
|
||||
}
|
||||
|
||||
if (indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up", element);
|
||||
}
|
||||
|
||||
// read assigned node
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Model");
|
||||
for (const Connection *con : conns) {
|
||||
const Model *mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if (mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster", element);
|
||||
node = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::~Cluster() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name), accuracy(0.0f) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// keep this it is used for debugging and any FBX format changes
|
||||
// for (auto element : sc.Elements()) {
|
||||
// std::cout << "skin element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
const ElementPtr Link_DeformAcuracy = sc->GetElement("Link_DeformAcuracy");
|
||||
if (Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(Link_DeformAcuracy, 0));
|
||||
}
|
||||
|
||||
const ElementPtr SkinType = sc->GetElement("SkinningType");
|
||||
|
||||
if (SkinType) {
|
||||
std::string skin_type = ParseTokenAsString(GetRequiredToken(SkinType, 0));
|
||||
|
||||
if (skin_type == "Linear") {
|
||||
skinType = Skin_Linear;
|
||||
} else if (skin_type == "Rigid") {
|
||||
skinType = Skin_Rigid;
|
||||
} else if (skin_type == "DualQuaternion") {
|
||||
skinType = Skin_DualQuaternion;
|
||||
} else if (skin_type == "Blend") {
|
||||
skinType = Skin_Blend;
|
||||
} else {
|
||||
print_error("[doc:skin] could not find valid skin type: " + String(skin_type.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
|
||||
//
|
||||
|
||||
clusters.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const Cluster *cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if (cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::~Skin() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
blendShapeChannels.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const BlendShapeChannel *bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::~BlendShape() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr DeformPercent = sc->GetElement("DeformPercent");
|
||||
if (DeformPercent) {
|
||||
percent = ParseTokenAsFloat(GetRequiredToken(DeformPercent, 0));
|
||||
}
|
||||
const ElementPtr FullWeights = sc->GetElement("FullWeights");
|
||||
if (FullWeights) {
|
||||
ParseVectorDataArray(fullWeights, FullWeights);
|
||||
}
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
|
||||
shapeGeometries.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const ShapeGeometry *const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::~BlendShapeChannel() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
} // namespace FBXDocParser
|
699
modules/fbx/fbx_parser/FBXDocument.cpp
Normal file
699
modules/fbx/fbx_parser/FBXDocument.cpp
Normal file
@ -0,0 +1,699 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocument.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the*
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocument.cpp
|
||||
* @brief Implementation of the FBX DOM classes
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
|
||||
doc(doc), element(element), id(id), flags() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::~LazyObject() {
|
||||
object.reset();
|
||||
}
|
||||
|
||||
ObjectPtr LazyObject::LoadObject() {
|
||||
if (IsBeingConstructed() || FailedToConstruct()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (object) {
|
||||
return object.get();
|
||||
}
|
||||
|
||||
TokenPtr key = element->KeyToken();
|
||||
ERR_FAIL_COND_V(!key, nullptr);
|
||||
const TokenList &tokens = element->Tokens();
|
||||
|
||||
if (tokens.size() < 3) {
|
||||
//DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *err = nullptr;
|
||||
std::string name = ParseTokenAsString(tokens[1], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if (tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i + 1] == 0x1) {
|
||||
name = name.substr(i + 2) + "::" + name.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string classtag = ParseTokenAsString(tokens[2], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char *obtype = key->begin();
|
||||
const size_t length = static_cast<size_t>(key->end() - key->begin());
|
||||
|
||||
if (!strncmp(obtype, "Pose", length)) {
|
||||
object.reset(new FbxPose(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Geometry", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Mesh")) {
|
||||
object.reset(new MeshGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Shape")) {
|
||||
object.reset(new ShapeGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Line")) {
|
||||
object.reset(new LineGeometry(id, element, name, doc));
|
||||
}
|
||||
} else if (!strncmp(obtype, "NodeAttribute", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Camera")) {
|
||||
object.reset(new Camera(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Light")) {
|
||||
object.reset(new Light(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Null")) {
|
||||
object.reset(new Null(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
// This is an older format for bones
|
||||
// this is what blender uses I believe
|
||||
object.reset(new LimbNode(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Constraint", length)) {
|
||||
object.reset(new Constraint(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Deformer", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Cluster")) {
|
||||
object.reset(new Cluster(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Skin")) {
|
||||
|
||||
object.reset(new Skin(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShape")) {
|
||||
object.reset(new BlendShape(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
|
||||
object.reset(new BlendShapeChannel(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Model", length)) {
|
||||
// Model is normal node
|
||||
|
||||
// LimbNode model is a 'bone' node.
|
||||
if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
object.reset(new ModelLimbNode(id, element, doc, name));
|
||||
|
||||
} else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) {
|
||||
// FK and IK effectors are not supporte
|
||||
object.reset(new Model(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Material", length)) {
|
||||
object.reset(new Material(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Texture", length)) {
|
||||
object.reset(new Texture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "LayeredTexture", length)) {
|
||||
object.reset(new LayeredTexture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Video", length)) {
|
||||
object.reset(new Video(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "AnimationStack", length)) {
|
||||
object.reset(new AnimationStack(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationLayer", length)) {
|
||||
object.reset(new AnimationLayer(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurve", length)) {
|
||||
object.reset(new AnimationCurve(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurveNode", length)) {
|
||||
object.reset(new AnimationCurveNode(id, element, name, doc));
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(nullptr, "FBX contains unsupported object: " + String(obtype));
|
||||
}
|
||||
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
|
||||
element(element), name(name), id(id) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::~Object() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
|
||||
props(props), doc(doc) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::~FileGlobalSettings() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser &parser, const ImportSettings &settings) :
|
||||
settings(settings), parser(parser), SafeToImport(false) {
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (unsigned int &timeStamp : creationTimeStamp) {
|
||||
timeStamp = 0;
|
||||
}
|
||||
|
||||
// we must check if we can read the header version safely, if its outdated then drop it.
|
||||
if (ReadHeader()) {
|
||||
SafeToImport = true;
|
||||
ReadPropertyTemplates();
|
||||
|
||||
ReadGlobalSettings();
|
||||
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document() {
|
||||
for (PropertyTemplateMap::value_type v : templates) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ObjectMap::value_type &v : objects) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ConnectionMap::value_type &v : src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
// clear globals import pointer
|
||||
globals.reset();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int LowerSupportedVersion = 7100;
|
||||
static const unsigned int UpperSupportedVersion = 7700;
|
||||
|
||||
bool Document::ReadHeader() {
|
||||
// Read ID objects from "Objects" section
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr ehead = sc->GetElement("FBXHeaderExtension");
|
||||
if (!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
|
||||
const ScopePtr shead = ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
|
||||
|
||||
// While we may have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if (fbxVersion < LowerSupportedVersion) {
|
||||
DOMWarning("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013, you can re-export using Maya, 3DS, blender or Autodesk FBX tool");
|
||||
return false;
|
||||
}
|
||||
if (fbxVersion > UpperSupportedVersion) {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2011, up to FBX 2020"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
|
||||
const ElementPtr ecreator = shead->GetElement("Creator");
|
||||
if (ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
|
||||
}
|
||||
|
||||
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
|
||||
if (etimestamp && etimestamp->Compound()) {
|
||||
const ScopePtr stimestamp = etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Year"), 0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Month"), 0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Day"), 0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Hour"), 0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Minute"), 0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Second"), 0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Millisecond"), 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings() {
|
||||
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
|
||||
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr ehead = sc->GetElement("GlobalSettings");
|
||||
if (nullptr == ehead || !ehead->Compound()) {
|
||||
DOMWarning("no GlobalSettings dictionary found");
|
||||
globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
|
||||
return;
|
||||
}
|
||||
|
||||
const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
|
||||
|
||||
//double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
|
||||
|
||||
if (!props) {
|
||||
DOMError("GlobalSettings dictionary contains no property table");
|
||||
}
|
||||
|
||||
globals = std::make_shared<FileGlobalSettings>(*this, props);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects() {
|
||||
// read ID objects from "Objects" section
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr eobjects = sc->GetElement("Objects");
|
||||
if (!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, eobjects, *this);
|
||||
|
||||
const ScopePtr sobjects = eobjects->Compound();
|
||||
for (const ElementMap::value_type &iter : sobjects->Elements()) {
|
||||
|
||||
// extract ID
|
||||
const TokenList &tok = iter.second->Tokens();
|
||||
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key", iter.second);
|
||||
}
|
||||
|
||||
const char *err;
|
||||
const uint64_t id = ParseTokenAsID(tok[0], err);
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
// id=0 is normally implicit
|
||||
if (id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0", iter.second);
|
||||
}
|
||||
|
||||
if (objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence", iter.second);
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, iter.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if (!strcmp(iter.first.c_str(), "AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Constraint")) {
|
||||
constraints.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Pose")) {
|
||||
bind_poses.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Material")) {
|
||||
materials.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Deformer")) {
|
||||
TokenPtr key = iter.second->KeyToken();
|
||||
ERR_CONTINUE_MSG(!key, "[parser bug] invalid token key for deformer");
|
||||
const TokenList &tokens = iter.second->Tokens();
|
||||
const std::string class_tag = ParseTokenAsString(tokens[2], err);
|
||||
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
if (class_tag == "Skin") {
|
||||
//print_verbose("registered skin:" + itos(id));
|
||||
skins.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates() {
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const ElementPtr edefs = sc->GetElement("Definitions");
|
||||
if (!edefs || !edefs->Compound()) {
|
||||
DOMWarning("no Definitions dictionary found");
|
||||
return;
|
||||
}
|
||||
|
||||
const ScopePtr sdefs = edefs->Compound();
|
||||
const ElementCollection otypes = sdefs->GetCollection("ObjectType");
|
||||
for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||
const ElementPtr el = (*it).second;
|
||||
const ScopePtr sc_2 = el->Compound();
|
||||
if (!sc_2) {
|
||||
DOMWarning("expected nested scope in ObjectType, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList &tok = el->Tokens();
|
||||
if (tok.empty()) {
|
||||
DOMWarning("expected name for ObjectType element, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &oname = ParseTokenAsString(tok[0]);
|
||||
|
||||
const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
|
||||
for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
|
||||
const ElementPtr el_2 = (*iter).second;
|
||||
const ScopePtr sc_3 = el_2->Compound();
|
||||
if (!sc_3) {
|
||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList &tok_2 = el_2->Tokens();
|
||||
if (tok_2.empty()) {
|
||||
DOMWarning("expected name for PropertyTemplate element, ignoring", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &pname = ParseTokenAsString(tok_2[0]);
|
||||
|
||||
const ElementPtr Properties70 = sc_3->GetElement("Properties70");
|
||||
if (Properties70) {
|
||||
// PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
|
||||
const PropertyTable *props = new PropertyTable(Properties70, nullptr);
|
||||
|
||||
templates[oname + "." + pname] = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections() {
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
|
||||
// read property templates from "Definitions" section
|
||||
const ElementPtr econns = sc->GetElement("Connections");
|
||||
if (!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
|
||||
uint64_t insertionOrder = 0l;
|
||||
const ScopePtr sconns = econns->Compound();
|
||||
const ElementCollection conns = sconns->GetCollection("C");
|
||||
for (ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const ElementPtr el = (*it).second;
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(el, 0));
|
||||
|
||||
// PP = property-property connection, ignored for now
|
||||
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
|
||||
if (type == "PP") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el, 1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el, 2));
|
||||
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string &prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el, 3)) : "");
|
||||
|
||||
if (objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if (objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add new connection
|
||||
const Connection *const c = new Connection(insertionOrder++, src, dest, prop, *this);
|
||||
src_connections.insert(ConnectionMap::value_type(src, c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest, c));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack *> &Document::AnimationStacks() const {
|
||||
if (!animationStacksResolved.empty() || animationStacks.empty()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
for (uint64_t id : animationStacks) {
|
||||
LazyObject *lazy = GetObject(id);
|
||||
|
||||
// Two things happen here:
|
||||
// We cast internally an Object PTR to an Animation Stack PTR
|
||||
// We return invalid weak_ptrs for objects which are invalid
|
||||
|
||||
const AnimationStack *stack = lazy->Get<AnimationStack>();
|
||||
ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure");
|
||||
|
||||
// We push back the weak reference :) to keep things simple, as ownership is on the parser side so it wont be cleaned up.
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Document::GetObject(uint64_t id) const {
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap &conns) const {
|
||||
std::vector<const Connection *> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap &conns,
|
||||
const char *const *classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
size_t lengths[MAX_CLASSNAMES];
|
||||
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lengths[i] = strlen(classnames[i]);
|
||||
}
|
||||
|
||||
std::vector<const Connection *> temp;
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
TokenPtr key = (is_src ? (*it).second->LazyDestinationObject() : (*it).second->LazySourceObject())->GetElement()->KeyToken();
|
||||
|
||||
const char *obtype = key->begin();
|
||||
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
//ai_assert(classnames[i]);
|
||||
if (static_cast<size_t>(std::distance(key->begin(), key->end())) == lengths[i] && !strncmp(classnames[i], obtype, lengths[i])) {
|
||||
obtype = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source) const {
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t src, const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsBySourceSequenced(src, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsByDestinationSequenced(dest, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop,
|
||||
const Document &doc) :
|
||||
insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::~Connection() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazySourceObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(src);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazyDestinationObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(dest);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::SourceObject() const {
|
||||
LazyObject *lazy = doc.GetObject(src);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::DestinationObject() const {
|
||||
LazyObject *lazy = doc.GetObject(dest);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
1311
modules/fbx/fbx_parser/FBXDocument.h
Normal file
1311
modules/fbx/fbx_parser/FBXDocument.h
Normal file
File diff suppressed because it is too large
Load Diff
172
modules/fbx/fbx_parser/FBXDocumentUtil.cpp
Normal file
172
modules/fbx/fbx_parser/FBXDocumentUtil.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.cpp
|
||||
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
|
||||
*/
|
||||
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
void DOMError(const std::string &message) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Token *token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Element *element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Token *token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Element *element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// fetch a property table and the corresponding property template
|
||||
const PropertyTable *GetPropertyTable(const Document &doc,
|
||||
const std::string &templateName,
|
||||
const ElementPtr element,
|
||||
const ScopePtr sc,
|
||||
bool no_warn /*= false*/) {
|
||||
// todo: make this an abstraction
|
||||
const ElementPtr Properties70 = sc->GetElement("Properties70");
|
||||
const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
|
||||
|
||||
if (templateName.length()) {
|
||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||
if (it != doc.Templates().end()) {
|
||||
templateProps = (*it).second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Properties70 || !Properties70->Compound()) {
|
||||
if (!no_warn) {
|
||||
DOMWarning("property table (Properties70) not found", element);
|
||||
}
|
||||
if (templateProps) {
|
||||
return templateProps;
|
||||
} else {
|
||||
return new const PropertyTable();
|
||||
}
|
||||
}
|
||||
|
||||
return new PropertyTable(Properties70, templateProps);
|
||||
}
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
142
modules/fbx/fbx_parser/FBXDocumentUtil.h
Normal file
142
modules/fbx/fbx_parser/FBXDocumentUtil.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.h
|
||||
* @brief FBX internal utilities used by the DOM reading code
|
||||
*/
|
||||
#ifndef FBX_DOCUMENT_UTIL_H
|
||||
#define FBX_DOCUMENT_UTIL_H
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct Token;
|
||||
struct Element;
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// Parser errors
|
||||
void DOMError(const std::string &message);
|
||||
void DOMError(const std::string &message, const Token *token);
|
||||
void DOMError(const std::string &message, const Element *element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token);
|
||||
|
||||
// Parser warnings
|
||||
void DOMWarning(const std::string &message);
|
||||
void DOMWarning(const std::string &message, const Token *token);
|
||||
void DOMWarning(const std::string &message, const Element *element);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
|
||||
|
||||
// fetch a property table and the corresponding property template
|
||||
const PropertyTable *GetPropertyTable(const Document &doc,
|
||||
const std::string &templateName,
|
||||
const ElementPtr element,
|
||||
const ScopePtr sc,
|
||||
bool no_warn = false);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessSimpleConnection(const Connection &con,
|
||||
bool is_object_property_conn,
|
||||
const char *name,
|
||||
const ElementPtr element,
|
||||
const char **propNameOut = nullptr) {
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
} else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
|
||||
// Cast Object to AnimationPlayer for example using safe functions, which return nullptr etc
|
||||
Object *ob = con.SourceObject();
|
||||
ERR_FAIL_COND_V_MSG(!ob, nullptr, "Failed to load object from SourceObject ptr");
|
||||
return dynamic_cast<const T *>(ob);
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_DOCUMENT_UTIL_H
|
174
modules/fbx/fbx_parser/FBXImportSettings.h
Normal file
174
modules/fbx/fbx_parser/FBXImportSettings.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*************************************************************************/
|
||||
/* FBXImportSettings.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImportSettings.h
|
||||
* @brief FBX importer runtime configuration
|
||||
*/
|
||||
#ifndef FBX_IMPORT_SETTINGS_H
|
||||
#define FBX_IMPORT_SETTINGS_H
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
|
||||
struct ImportSettings {
|
||||
ImportSettings() :
|
||||
strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated. Strict mode is off by default. */
|
||||
bool strictMode;
|
||||
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers. The default
|
||||
* value for this option is true.*/
|
||||
bool readAllLayers;
|
||||
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed .
|
||||
* This bit is ignored unless readMaterials=true*/
|
||||
bool readAllMaterials;
|
||||
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material. The default value is true.*/
|
||||
bool readMaterials;
|
||||
|
||||
/** import embedded textures? Default value is true.*/
|
||||
bool readTextures;
|
||||
|
||||
/** import cameras? Default value is true.*/
|
||||
bool readCameras;
|
||||
|
||||
/** import light sources? Default value is true.*/
|
||||
bool readLights;
|
||||
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported). Default value is true. */
|
||||
bool readAnimations;
|
||||
|
||||
/** read bones (vertex weights and deform info).
|
||||
* Default value is true. */
|
||||
bool readWeights;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower. The default value
|
||||
* is true.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots;
|
||||
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.
|
||||
* The default value is true. */
|
||||
bool optimizeEmptyAnimationCurves;
|
||||
|
||||
/** use legacy naming for embedded textures eg: (*0, *1, *2)
|
||||
*/
|
||||
bool useLegacyEmbeddedTextureNaming;
|
||||
|
||||
/** Empty bones shall be removed
|
||||
*/
|
||||
bool removeEmptyBones;
|
||||
|
||||
/** Set to true to perform a conversion from cm to meter after the import
|
||||
*/
|
||||
bool convertToMeters;
|
||||
};
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_IMPORT_SETTINGS_H
|
406
modules/fbx/fbx_parser/FBXMaterial.cpp
Normal file
406
modules/fbx/fbx_parser/FBXMaterial.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMaterial.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMaterial.cpp
|
||||
* @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include <algorithm> // std::transform
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr ShadingModel = sc->GetElement("ShadingModel");
|
||||
const ElementPtr MultiLayer = sc->GetElement("MultiLayer");
|
||||
|
||||
if (MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(MultiLayer, 0));
|
||||
}
|
||||
|
||||
if (ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(ShadingModel, 0));
|
||||
} else {
|
||||
DOMWarning("shading mode not specified, assuming phong", element);
|
||||
shading = "phong";
|
||||
}
|
||||
|
||||
std::string templateName;
|
||||
|
||||
if (shading == "phong") {
|
||||
templateName = "Material.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;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture *tex = dynamic_cast<const Texture *>(ob);
|
||||
if (!tex) {
|
||||
LayeredTexture *layeredTexture = dynamic_cast<LayeredTexture *>(ob);
|
||||
|
||||
if (!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop, element);
|
||||
}
|
||||
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
layeredTexture->fillTexture(doc);
|
||||
} else {
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop, element);
|
||||
}
|
||||
|
||||
textures[prop] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
const ElementPtr FileName = sc->GetElement("FileName");
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr ModelUVTranslation = sc->GetElement("ModelUVTranslation");
|
||||
const ElementPtr ModelUVScaling = sc->GetElement("ModelUVScaling");
|
||||
const ElementPtr Texture_Alpha_Source = sc->GetElement("Texture_Alpha_Source");
|
||||
const ElementPtr Cropping = sc->GetElement("Cropping");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (ModelUVTranslation) {
|
||||
uvTrans = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 1)));
|
||||
}
|
||||
|
||||
if (ModelUVScaling) {
|
||||
uvScaling = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 1)));
|
||||
}
|
||||
|
||||
if (Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(Cropping, 0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(Cropping, 1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(Cropping, 2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(Cropping, 3));
|
||||
} else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
|
||||
if (Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
|
||||
|
||||
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
|
||||
bool ok;
|
||||
const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
|
||||
if (ok) {
|
||||
uvScaling.x = scaling.x;
|
||||
uvScaling.y = scaling.y;
|
||||
}
|
||||
|
||||
const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok);
|
||||
if (ok) {
|
||||
uvTrans.x = trans.x;
|
||||
uvTrans.y = trans.y;
|
||||
}
|
||||
|
||||
// resolve video links
|
||||
if (doc.Settings().readTextures) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (const Connection *con : conns) {
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Video *const video = dynamic_cast<const Video *>(ob);
|
||||
if (video) {
|
||||
media = video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
|
||||
Object(id, element, name), blendMode(BlendMode_Modulate), alpha(1) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
ElementPtr BlendModes = sc->GetElement("BlendModes");
|
||||
ElementPtr Alphas = sc->GetElement("Alphas");
|
||||
|
||||
if (BlendModes != 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 ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), contentLength(0), content(0) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
// File Version 7500 Crashes if this is not checked fully.
|
||||
// As of writing this comment 7700 exists, in August 2020
|
||||
ElementPtr FileName = nullptr;
|
||||
if (HasElement(sc, "Filename")) {
|
||||
FileName = (ElementPtr)sc->GetElement("Filename");
|
||||
} else if (HasElement(sc, "FileName")) {
|
||||
FileName = (ElementPtr)sc->GetElement("FileName");
|
||||
} else {
|
||||
print_error("file has invalid video material returning...");
|
||||
return;
|
||||
}
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr Content = sc->GetElement("Content");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (Content && !Content->Tokens().empty()) {
|
||||
//this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
|
||||
try {
|
||||
const Token *token = GetRequiredToken(Content, 0);
|
||||
const char *data = token->begin();
|
||||
if (!token->IsBinary()) {
|
||||
if (*data != '"') {
|
||||
DOMError("embedded content is not surrounded by quotation marks", element);
|
||||
} else {
|
||||
size_t targetLength = 0;
|
||||
auto numTokens = Content->Tokens().size();
|
||||
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
|
||||
if (outLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
targetLength += outLength;
|
||||
}
|
||||
if (targetLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
content = new uint8_t[targetLength];
|
||||
contentLength = static_cast<uint64_t>(targetLength);
|
||||
size_t dst_offset = 0;
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
ERR_FAIL_COND(!dataToken);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
|
||||
}
|
||||
if (targetLength != dst_offset) {
|
||||
delete[] content;
|
||||
contentLength = 0;
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
}
|
||||
} else if (static_cast<size_t>(token->end() - data) < 5) {
|
||||
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", element);
|
||||
} else if (*data != 'R') {
|
||||
DOMWarning("video content is not raw binary data, ignoring", element);
|
||||
} else {
|
||||
// read number of elements
|
||||
uint32_t len = 0;
|
||||
::memcpy(&len, data + 1, sizeof(len));
|
||||
AI_SWAP4(len);
|
||||
|
||||
contentLength = len;
|
||||
|
||||
content = new uint8_t[len];
|
||||
::memcpy(content, data + 5, len);
|
||||
}
|
||||
} catch (...) {
|
||||
// //we don't need the content data for contents that has already been loaded
|
||||
// ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
|
||||
// runtimeError.what());
|
||||
}
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
if (content) {
|
||||
delete[] content;
|
||||
}
|
||||
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
451
modules/fbx/fbx_parser/FBXMeshGeometry.cpp
Normal file
451
modules/fbx/fbx_parser/FBXMeshGeometry.cpp
Normal file
@ -0,0 +1,451 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMeshGeometry.cpp
|
||||
* @brief Assimp::FBX::MeshGeometry implementation
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), skin() {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
for (const Connection *con : conns) {
|
||||
const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if (sk) {
|
||||
skin = sk;
|
||||
}
|
||||
const BlendShape *bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry",
|
||||
element);
|
||||
if (bsp) {
|
||||
blendShapes.push_back(bsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::~Geometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape *> &Geometry::get_blend_shapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Skin *Geometry::DeformerSkin() const {
|
||||
return skin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
print_verbose("mesh name: " + String(name.c_str()));
|
||||
|
||||
ScopePtr sc = element->Compound();
|
||||
ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash");
|
||||
ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertexes, didn't populate the mesh");
|
||||
|
||||
// must have Mesh elements:
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
const ElementPtr PolygonVertexIndex = GetRequiredElement(sc, "PolygonVertexIndex", element);
|
||||
|
||||
if (HasElement(sc, "Edges")) {
|
||||
const ElementPtr element_edges = GetRequiredElement(sc, "Edges", element);
|
||||
ParseVectorDataArray(m_edges, element_edges);
|
||||
}
|
||||
|
||||
// read mesh data into arrays
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_face_indices, PolygonVertexIndex);
|
||||
|
||||
ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertexes in FBX file, did you mean to delete it?");
|
||||
ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?");
|
||||
|
||||
// Retrieve layer elements, for all of the mesh
|
||||
const ElementCollection &Layer = sc->GetCollection("Layer");
|
||||
|
||||
// Store all layers
|
||||
std::vector<std::tuple<int, std::string> > valid_layers;
|
||||
|
||||
// now read the sub mesh information from the geometry (normals, uvs, etc)
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const ScopePtr layer = GetRequiredScope(it->second);
|
||||
const ElementCollection &LayerElement = layer->GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
std::string layer_name = eit->first;
|
||||
ElementPtr element_layer = eit->second;
|
||||
const ScopePtr layer_element = GetRequiredScope(element_layer);
|
||||
|
||||
// Actual usable 'type' LayerElementUV, LayerElementNormal, etc
|
||||
const ElementPtr Type = GetRequiredElement(layer_element, "Type");
|
||||
const ElementPtr TypedIndex = GetRequiredElement(layer_element, "TypedIndex");
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
|
||||
|
||||
// we only need the layer name and the typed index.
|
||||
valid_layers.push_back(std::tuple<int, std::string>(typedIndex, type));
|
||||
}
|
||||
}
|
||||
|
||||
// get object / mesh directly from the FBX by the element ID.
|
||||
const ScopePtr top = GetRequiredScope(element);
|
||||
|
||||
// iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc)
|
||||
for (size_t x = 0; x < valid_layers.size(); x++) {
|
||||
const int layer_id = std::get<0>(valid_layers[x]);
|
||||
const std::string &layer_type_name = std::get<1>(valid_layers[x]);
|
||||
|
||||
// Get collection of elements from the XLayerMap (example: LayerElementUV)
|
||||
// this must contain our proper elements.
|
||||
|
||||
// This is stupid, because it means we select them ALL not just the one we want.
|
||||
// but it's fine we can match by id.
|
||||
GetRequiredElement(top, layer_type_name);
|
||||
const ElementCollection &candidates = top->GetCollection(layer_type_name);
|
||||
|
||||
ElementMap::const_iterator iter;
|
||||
for (iter = candidates.first; iter != candidates.second; ++iter) {
|
||||
const ScopePtr layer_scope = GetRequiredScope(iter->second);
|
||||
TokenPtr layer_token = GetRequiredToken(iter->second, 0);
|
||||
const int index = ParseTokenAsInt(layer_token);
|
||||
|
||||
ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid");
|
||||
|
||||
if (index == layer_id) {
|
||||
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "MappingInformationType"), 0));
|
||||
|
||||
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "ReferenceInformationType"), 0));
|
||||
|
||||
if (layer_type_name == "LayerElementUV") {
|
||||
if (index == 0) {
|
||||
m_uv_0 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
} else if (index == 1) {
|
||||
m_uv_1 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
}
|
||||
} else if (layer_type_name == "LayerElementMaterial") {
|
||||
m_material_allocation_ids = resolve_vertex_data_array<int>(layer_scope, MappingInformationType, ReferenceInformationType, "Materials");
|
||||
} else if (layer_type_name == "LayerElementNormal") {
|
||||
m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals");
|
||||
} else if (layer_type_name == "LayerElementColor") {
|
||||
m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size()));
|
||||
|
||||
// Compose the edge of the mesh.
|
||||
// You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6
|
||||
for (size_t i = 0; i < m_edges.size(); i += 1) {
|
||||
ERR_FAIL_INDEX_MSG((size_t)m_edges[i], m_face_indices.size(), "The edge is pointing to a weird location in the face indices. The FBX is corrupted.");
|
||||
int polygon_vertex_0 = m_face_indices[m_edges[i]];
|
||||
int polygon_vertex_1;
|
||||
if (polygon_vertex_0 < 0) {
|
||||
// The polygon_vertex_0 points to the end of a polygon, so it's
|
||||
// connected with the beginning of polygon in the edge list.
|
||||
|
||||
// Fist invert the vertex.
|
||||
polygon_vertex_0 = ~polygon_vertex_0;
|
||||
|
||||
// Search the start vertex of the polygon.
|
||||
// Iterate from the polygon_vertex_index backward till the start of
|
||||
// the polygon is found.
|
||||
ERR_FAIL_COND_MSG(m_edges[i] - 1 < 0, "The polygon is not yet started and we already need the final vertex. This FBX is corrupted.");
|
||||
bool found_it = false;
|
||||
for (int x = m_edges[i] - 1; x >= 0; x -= 1) {
|
||||
if (x == 0) {
|
||||
// This for sure is the start.
|
||||
polygon_vertex_1 = m_face_indices[x];
|
||||
found_it = true;
|
||||
break;
|
||||
} else if (m_face_indices[x] < 0) {
|
||||
// This is the end of the previous polygon, so the next is
|
||||
// the start of the polygon we need.
|
||||
polygon_vertex_1 = m_face_indices[x + 1];
|
||||
found_it = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// As the algorithm above, this check is useless. Because the first
|
||||
// ever vertex is always considered the begining of a polygon.
|
||||
ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted.");
|
||||
|
||||
} else {
|
||||
ERR_FAIL_INDEX_MSG((size_t)(m_edges[i] + 1), m_face_indices.size(), "FBX The other FBX edge seems to point to an invalid vertices. This FBX file is corrupted.");
|
||||
// Take the next vertex
|
||||
polygon_vertex_1 = m_face_indices[m_edges[i] + 1];
|
||||
}
|
||||
|
||||
if (polygon_vertex_1 < 0) {
|
||||
// We don't care if the `polygon_vertex_1` is the end of the polygon,
|
||||
// for `polygon_vertex_1` so we can just invert it.
|
||||
polygon_vertex_1 = ~polygon_vertex_1;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(polygon_vertex_0 == polygon_vertex_1, "The vertices of this edge can't be the same, Is this a point???. This FBX file is corrupted.");
|
||||
|
||||
// Just create the edge.
|
||||
edge_map.push_back({ polygon_vertex_0, polygon_vertex_1 });
|
||||
}
|
||||
}
|
||||
|
||||
MeshGeometry::~MeshGeometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
const std::vector<Vector3> &MeshGeometry::get_vertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
const std::vector<MeshGeometry::Edge> &MeshGeometry::get_edge_map() const {
|
||||
return edge_map;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_polygon_indices() const {
|
||||
return m_face_indices;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_edges() const {
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector3> &MeshGeometry::get_normals() const {
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_0() const {
|
||||
//print_verbose("get uv_0 " + m_uv_0.debug_info() );
|
||||
return m_uv_0;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_1() const {
|
||||
//print_verbose("get uv_1 " + m_uv_1.debug_info() );
|
||||
return m_uv_1;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Color> &MeshGeometry::get_colors() const {
|
||||
return m_colors;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<int> &MeshGeometry::get_material_allocation_id() const {
|
||||
return m_material_allocation_ids;
|
||||
}
|
||||
|
||||
int MeshGeometry::get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b) {
|
||||
for (size_t i = 0; i < p_map.size(); i += 1) {
|
||||
if ((p_map[i].vertex_0 == p_vertex_a && p_map[i].vertex_1 == p_vertex_b) || (p_map[i].vertex_1 == p_vertex_a && p_map[i].vertex_0 == p_vertex_b)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MeshGeometry::Edge MeshGeometry::get_edge(const std::vector<Edge> &p_map, int p_id) {
|
||||
ERR_FAIL_INDEX_V_MSG((size_t)p_id, p_map.size(), Edge({ -1, -1 }), "ID not found.");
|
||||
return p_map[p_id];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName) {
|
||||
|
||||
ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption");
|
||||
|
||||
// UVIndex, MaterialIndex, NormalIndex, etc..
|
||||
std::string indexDataElementName = dataElementName + "Index";
|
||||
// goal: expand everything to be per vertex
|
||||
|
||||
ReferenceType l_ref_type = ReferenceType::direct;
|
||||
|
||||
// Read the reference type into the enumeration
|
||||
if (ReferenceInformationType == "IndexToDirect") {
|
||||
l_ref_type = ReferenceType::index_to_direct;
|
||||
} else if (ReferenceInformationType == "Index") {
|
||||
// set non legacy index to direct mapping
|
||||
l_ref_type = ReferenceType::index;
|
||||
} else if (ReferenceInformationType == "Direct") {
|
||||
l_ref_type = ReferenceType::direct;
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(MappingData<T>(), "invalid reference type has the FBX format changed?");
|
||||
}
|
||||
|
||||
MapType l_map_type = MapType::none;
|
||||
|
||||
if (MappingInformationType == "None") {
|
||||
l_map_type = MapType::none;
|
||||
} else if (MappingInformationType == "ByVertice") {
|
||||
l_map_type = MapType::vertex;
|
||||
} else if (MappingInformationType == "ByPolygonVertex") {
|
||||
l_map_type = MapType::polygon_vertex;
|
||||
} else if (MappingInformationType == "ByPolygon") {
|
||||
l_map_type = MapType::polygon;
|
||||
} else if (MappingInformationType == "ByEdge") {
|
||||
l_map_type = MapType::edge;
|
||||
} else if (MappingInformationType == "AllSame") {
|
||||
l_map_type = MapType::all_the_same;
|
||||
} else {
|
||||
print_error("invalid mapping type: " + String(MappingInformationType.c_str()));
|
||||
}
|
||||
|
||||
// create mapping data
|
||||
MeshGeometry::MappingData<T> tempData;
|
||||
tempData.map_type = l_map_type;
|
||||
tempData.ref_type = l_ref_type;
|
||||
|
||||
// parse data into array
|
||||
ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName));
|
||||
|
||||
// index array wont always exist
|
||||
const ElementPtr element = GetOptionalElement(source, indexDataElementName);
|
||||
if (element) {
|
||||
ParseVectorDataArray(tempData.index, element);
|
||||
}
|
||||
|
||||
return tempData;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const ElementPtr Indexes = GetRequiredElement(sc, "Indexes", element);
|
||||
const ElementPtr Normals = GetRequiredElement(sc, "Normals", element);
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
ParseVectorDataArray(m_indices, Indexes);
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_normals, Normals);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::~ShapeGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||
}
|
||||
const ElementPtr Points = GetRequiredElement(sc, "Points", element);
|
||||
const ElementPtr PointsIndex = GetRequiredElement(sc, "PointsIndex", element);
|
||||
ParseVectorDataArray(m_vertices, Points);
|
||||
ParseVectorDataArray(m_indices, PointsIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::~LineGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &LineGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<int> &LineGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
263
modules/fbx/fbx_parser/FBXMeshGeometry.h
Normal file
263
modules/fbx/fbx_parser/FBXMeshGeometry.h
Normal file
@ -0,0 +1,263 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FBX_MESH_GEOMETRY_H
|
||||
#define FBX_MESH_GEOMETRY_H
|
||||
|
||||
#include "core/color.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
#include "core/vector.h"
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define AI_MAX_NUMBER_OF_TEXTURECOORDS 4
|
||||
#define AI_MAX_NUMBER_OF_COLOR_SETS 8
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/*
|
||||
* DOM base class for all kinds of FBX geometry
|
||||
*/
|
||||
class Geometry : public Object {
|
||||
public:
|
||||
Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
virtual ~Geometry();
|
||||
|
||||
/** Get the Skin attached to this geometry or NULL */
|
||||
const Skin *DeformerSkin() const;
|
||||
|
||||
const std::vector<const BlendShape *> &get_blend_shapes() const;
|
||||
|
||||
size_t get_blend_shape_count() const {
|
||||
return blendShapes.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Skin *skin;
|
||||
std::vector<const BlendShape *> blendShapes;
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
||||
/// Map Geometry stores the FBX file information.
|
||||
///
|
||||
/// # FBX doc.
|
||||
/// ## Reference type declared:
|
||||
/// - Direct (directly related to the mapping information type)
|
||||
/// - IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
///
|
||||
/// ## Map Type:
|
||||
/// * None The mapping is undetermined.
|
||||
/// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex).
|
||||
/// * If you have direct reference type verticies[x]
|
||||
/// * If you have IndexToDirect reference type the UV
|
||||
/// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
/// * ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
/// * One mapping per polygon polygon x has this normal x
|
||||
/// * For each vertex of the polygon then set the normal to x
|
||||
/// * ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
/// * AllSame There can be only one mapping coordinate for the whole surface.
|
||||
class MeshGeometry : public Geometry {
|
||||
public:
|
||||
enum class MapType {
|
||||
none = 0, // No mapping type. Stored as "None".
|
||||
vertex, // Maps per vertex. Stored as "ByVertice".
|
||||
polygon_vertex, // Maps per polygon vertex. Stored as "ByPolygonVertex".
|
||||
polygon, // Maps per polygon. Stored as "ByPolygon".
|
||||
edge, // Maps per edge. Stored as "ByEdge".
|
||||
all_the_same // Uaps to everything. Stored as "AllSame".
|
||||
};
|
||||
|
||||
enum class ReferenceType {
|
||||
direct = 0,
|
||||
index = 1,
|
||||
index_to_direct = 2
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MappingData {
|
||||
MapType map_type = MapType::none;
|
||||
ReferenceType ref_type = ReferenceType::direct;
|
||||
std::vector<T> data;
|
||||
/// The meaning of the indices depends from the `MapType`.
|
||||
/// If `ref_type` is `direct` this map is hollow.
|
||||
std::vector<int> index;
|
||||
|
||||
String debug_info() const {
|
||||
return "indexes: " + itos(index.size()) + " data: " + itos(data.size());
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
int vertex_0 = 0, vertex_1 = 0;
|
||||
Edge(int v0, int v1) :
|
||||
vertex_0(v0), vertex_1(v1) {}
|
||||
Edge() {}
|
||||
};
|
||||
|
||||
public:
|
||||
MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
virtual ~MeshGeometry();
|
||||
|
||||
const std::vector<Vector3> &get_vertices() const;
|
||||
const std::vector<Edge> &get_edge_map() const;
|
||||
const std::vector<int> &get_polygon_indices() const;
|
||||
const std::vector<int> &get_edges() const;
|
||||
const MappingData<Vector3> &get_normals() const;
|
||||
const MappingData<Vector2> &get_uv_0() const;
|
||||
const MappingData<Vector2> &get_uv_1() const;
|
||||
const MappingData<Color> &get_colors() const;
|
||||
const MappingData<int> &get_material_allocation_id() const;
|
||||
|
||||
/// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't
|
||||
// matter.
|
||||
static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b);
|
||||
// Retuns the edge point bu that ID, or the edge with -1 vertices if the
|
||||
// id is not valid.
|
||||
static Edge get_edge(const std::vector<Edge> &p_map, int p_id);
|
||||
|
||||
private:
|
||||
// Read directly from the FBX file.
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Edge> edge_map;
|
||||
std::vector<int> m_face_indices;
|
||||
std::vector<int> m_edges;
|
||||
MappingData<Vector3> m_normals;
|
||||
MappingData<Vector2> m_uv_0; // first uv coordinates
|
||||
MappingData<Vector2> m_uv_1; // second uv coordinates
|
||||
MappingData<Color> m_colors; // colors for the mesh
|
||||
MappingData<int> m_material_allocation_ids; // slot of material used
|
||||
|
||||
template <class T>
|
||||
MappingData<T> resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName);
|
||||
};
|
||||
|
||||
/*
|
||||
* DOM class for FBX geometry of type "Shape"
|
||||
*/
|
||||
class ShapeGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~ShapeGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
const std::vector<Vector3> &GetNormals() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<unsigned int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Vector3> m_normals;
|
||||
std::vector<unsigned int> m_indices;
|
||||
};
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Line"
|
||||
*/
|
||||
class LineGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~LineGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<int> m_indices;
|
||||
};
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_MESH_GEOMETRY_H
|
181
modules/fbx/fbx_parser/FBXModel.cpp
Normal file
181
modules/fbx/fbx_parser/FBXModel.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*************************************************************************/
|
||||
/* FBXModel.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXModel.cpp
|
||||
* @brief Assimp::FBX::Model implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), shading("Y") {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr Shading = sc->GetElement("Shading");
|
||||
const ElementPtr Culling = sc->GetElement("Culling");
|
||||
|
||||
if (Shading) {
|
||||
shading = GetRequiredToken(Shading, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
|
||||
ResolveLinks(element, doc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::~Model() {
|
||||
if (props != nullptr) {
|
||||
delete props;
|
||||
props = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Model(id, element, doc, name){
|
||||
|
||||
};
|
||||
|
||||
ModelLimbNode::~ModelLimbNode() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const ElementPtr element, const Document &doc) {
|
||||
const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
|
||||
|
||||
// resolve material
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3);
|
||||
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
//DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Material *const mat = dynamic_cast<const Material *>(ob);
|
||||
if (mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Geometry *const geo = dynamic_cast<const Geometry *>(ob);
|
||||
if (geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
|
||||
const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob);
|
||||
if (att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Model::IsNull() const {
|
||||
const std::vector<const NodeAttribute *> &attrs = GetAttributes();
|
||||
for (const NodeAttribute *att : attrs) {
|
||||
|
||||
const Null *null_tag = dynamic_cast<const Null *>(att);
|
||||
if (null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
184
modules/fbx/fbx_parser/FBXNodeAttribute.cpp
Normal file
184
modules/fbx/fbx_parser/FBXNodeAttribute.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*************************************************************************/
|
||||
/* FBXNodeAttribute.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), props() {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
|
||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||
// the property table is by design absent and no warning should be generated
|
||||
// for it.
|
||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||
props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::~NodeAttribute() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr CameraId = sc->GetElement("CameraId");
|
||||
const ElementPtr CameraName = sc->GetElement("CameraName");
|
||||
const ElementPtr CameraIndexName = sc->GetElement("CameraIndexName");
|
||||
|
||||
if (CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(CameraId, 0));
|
||||
}
|
||||
|
||||
if (CameraName) {
|
||||
cameraName = GetRequiredToken(CameraName, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(CameraIndexName, 0)->StringContents();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::~CameraSwitcher() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::~Camera() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::~Light() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::~Null() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
//std::cout << "limb node: " << name << std::endl;
|
||||
//const Scope &sc = GetRequiredScope(element);
|
||||
|
||||
//const ElementPtr const TypeFlag = sc["TypeFlags"];
|
||||
|
||||
// keep this it can dump new properties for you
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "limbnode element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
// if(TypeFlag)
|
||||
// {
|
||||
// // std::cout << "type flag: " << GetRequiredToken(*TypeFlag, 0).StringContents() << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::~LimbNode() {
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
111
modules/fbx/fbx_parser/FBXParseTools.h
Normal file
111
modules/fbx/fbx_parser/FBXParseTools.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParseTools.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 FBX_PARSE_TOOLS_H
|
||||
#define FBX_PARSE_TOOLS_H
|
||||
|
||||
#include "core/error_macros.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsNewLine(char_t c) {
|
||||
return c == '\n' || c == '\r';
|
||||
}
|
||||
template <class char_t>
|
||||
inline bool IsSpace(char_t c) {
|
||||
return (c == (char_t)' ' || c == (char_t)'\t');
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsSpaceOrNewLine(char_t c) {
|
||||
return IsNewLine(c) || IsSpace(c);
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsLineEnd(char_t c) {
|
||||
return (c == (char_t)'\r' || c == (char_t)'\n' || c == (char_t)'\0' || c == (char_t)'\f');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Special version of the function, providing higher accuracy and safety
|
||||
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = 0, unsigned int *max_inout = 0) {
|
||||
unsigned int cur = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
errored = *in < '0' || *in > '9';
|
||||
ERR_FAIL_COND_V_MSG(errored, 0, "The string cannot be converted parser error");
|
||||
|
||||
for (;;) {
|
||||
if (*in < '0' || *in > '9') {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint64_t new_value = (value * (uint64_t)10) + ((uint64_t)(*in - '0'));
|
||||
|
||||
// numeric overflow, we rely on you
|
||||
if (new_value < value) {
|
||||
//WARN_PRINT( "Converting the string \" " + in + " \" into a value resulted in overflow." );
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = new_value;
|
||||
|
||||
++in;
|
||||
++cur;
|
||||
|
||||
if (max_inout && *max_inout == cur) {
|
||||
if (out) { /* skip to end */
|
||||
while (*in >= '0' && *in <= '9') {
|
||||
++in;
|
||||
}
|
||||
*out = in;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (out) {
|
||||
*out = in;
|
||||
}
|
||||
|
||||
if (max_inout) {
|
||||
*max_inout = cur;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif // FBX_PARSE_TOOLS_H
|
1295
modules/fbx/fbx_parser/FBXParser.cpp
Normal file
1295
modules/fbx/fbx_parser/FBXParser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
264
modules/fbx/fbx_parser/FBXParser.h
Normal file
264
modules/fbx/fbx_parser/FBXParser.h
Normal file
@ -0,0 +1,264 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParser.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXParser.h
|
||||
* @brief FBX parsing code
|
||||
*/
|
||||
#ifndef FBX_PARSER_H
|
||||
#define FBX_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "core/color.h"
|
||||
#include "core/math/transform.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
|
||||
typedef Element *ElementPtr;
|
||||
typedef Scope *ScopePtr;
|
||||
|
||||
typedef std::vector<ScopePtr> ScopeList;
|
||||
typedef std::multimap<std::string, ElementPtr> ElementMap;
|
||||
typedef std::pair<ElementMap::const_iterator, ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
#define new_Scope new Scope
|
||||
#define new_Element new Element
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* AnimationCurve: 23, "AnimCurve::", "" {
|
||||
* [..]
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
class Element {
|
||||
public:
|
||||
Element(TokenPtr key_token, Parser &parser);
|
||||
~Element();
|
||||
|
||||
ScopePtr Compound() const {
|
||||
return compound;
|
||||
}
|
||||
|
||||
TokenPtr KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
|
||||
const TokenList &Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
TokenList tokens;
|
||||
ScopePtr compound = nullptr;
|
||||
std::vector<ScopePtr> compound_scope;
|
||||
TokenPtr key_token = nullptr;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
* of not necessarily unique #Element instances.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* GlobalSettings: {
|
||||
* Version: 1000
|
||||
* Properties70:
|
||||
* [...]
|
||||
* }
|
||||
* @endverbatim */
|
||||
class Scope {
|
||||
public:
|
||||
Scope(Parser &parser, bool topLevel = false);
|
||||
~Scope();
|
||||
|
||||
ElementPtr GetElement(const std::string &index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
|
||||
for (auto element = elements.begin(); element != elements.end(); ++element) {
|
||||
if (element->first.compare(elementName)) {
|
||||
return element->second;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing to reference / expired.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ElementCollection GetCollection(const std::string &index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
|
||||
const ElementMap &Elements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementMap elements;
|
||||
};
|
||||
|
||||
/** FBX parsing class, takes a list of input tokens and generates a hierarchy
|
||||
* of nested #Scope instances, representing the fbx DOM.*/
|
||||
class Parser {
|
||||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser(const TokenList &tokens, bool is_binary);
|
||||
~Parser();
|
||||
|
||||
const ScopePtr GetRootScope() const {
|
||||
return root;
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
||||
TokenPtr AdvanceToNextToken();
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
|
||||
private:
|
||||
ScopeList scopes;
|
||||
const TokenList &tokens;
|
||||
|
||||
TokenPtr last = nullptr, current = nullptr;
|
||||
TokenList::const_iterator cursor;
|
||||
ScopePtr root = nullptr;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
||||
/* token parsing - this happens when building the DOM out of the parse-tree*/
|
||||
uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out);
|
||||
size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out);
|
||||
float ParseTokenAsFloat(const TokenPtr t, const char *&err_out);
|
||||
int ParseTokenAsInt(const TokenPtr t, const char *&err_out);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out);
|
||||
std::string ParseTokenAsString(const TokenPtr t, const char *&err_out);
|
||||
|
||||
/* wrapper around ParseTokenAsXXX() with DOMError handling */
|
||||
uint64_t ParseTokenAsID(const TokenPtr t);
|
||||
size_t ParseTokenAsDim(const TokenPtr t);
|
||||
float ParseTokenAsFloat(const TokenPtr t);
|
||||
int ParseTokenAsInt(const TokenPtr t);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t);
|
||||
std::string ParseTokenAsString(const TokenPtr t);
|
||||
|
||||
/* read data arrays */
|
||||
void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr ep);
|
||||
void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el);
|
||||
bool HasElement(const ScopePtr sc, const std::string &index);
|
||||
|
||||
// extract a required element from a scope, abort if the element cannot be found
|
||||
const ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
const ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
|
||||
const ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
// extract required compound scope
|
||||
const ScopePtr GetRequiredScope(const ElementPtr el);
|
||||
// get token at a particular index
|
||||
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a 4x4 matrix from an array of 16 floats
|
||||
Transform ReadMatrix(const ElementPtr element);
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PARSER_H
|
105
modules/fbx/fbx_parser/FBXPose.cpp
Normal file
105
modules/fbx/fbx_parser/FBXPose.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*************************************************************************/
|
||||
/* FBXPose.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class FbxPoseNode;
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
//const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
|
||||
const ElementCollection &PoseNodes = sc->GetCollection("PoseNode");
|
||||
for (ElementMap::const_iterator it = PoseNodes.first; it != PoseNodes.second; ++it) {
|
||||
std::string entry_name = (*it).first;
|
||||
ElementPtr some_element = (*it).second;
|
||||
FbxPoseNode *pose_node = new FbxPoseNode(some_element, doc, entry_name);
|
||||
pose_nodes.push_back(pose_node);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::~FbxPose() {
|
||||
pose_nodes.clear();
|
||||
// empty
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
238
modules/fbx/fbx_parser/FBXProperties.cpp
Normal file
238
modules/fbx/fbx_parser/FBXProperties.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.cpp
|
||||
* @brief Implementation of the FBX dynamic properties system
|
||||
*/
|
||||
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::Property() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::~Property() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
|
||||
PropertyPtr ReadTypedProperty(const ElementPtr element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
|
||||
const TokenList &tok = element->Tokens();
|
||||
//ai_assert(tok.size() >= 5);
|
||||
|
||||
const std::string &s = ParseTokenAsString(tok[1]);
|
||||
const char *const cs = s.c_str();
|
||||
if (!strcmp(cs, "KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(tok[4]));
|
||||
} else if (!strcmp(cs, "bool") || !strcmp(cs, "Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(tok[4]) != 0);
|
||||
} else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(tok[4]));
|
||||
} else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(tok[4]));
|
||||
} else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(tok[4]));
|
||||
} else if (!strcmp(cs, "Vector3D") ||
|
||||
!strcmp(cs, "ColorRGB") ||
|
||||
!strcmp(cs, "Vector") ||
|
||||
!strcmp(cs, "Color") ||
|
||||
!strcmp(cs, "Lcl Translation") ||
|
||||
!strcmp(cs, "Lcl Rotation") ||
|
||||
!strcmp(cs, "Lcl Scaling")) {
|
||||
return new TypedProperty<Vector3>(Vector3(
|
||||
ParseTokenAsFloat(tok[4]),
|
||||
ParseTokenAsFloat(tok[5]),
|
||||
ParseTokenAsFloat(tok[6])));
|
||||
} else if (!strcmp(cs, "double") || !strcmp(cs, "Number") || !strcmp(cs, "Float") || !strcmp(cs, "FieldOfView") || !strcmp(cs, "UnitScaleFactor")) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(tok[4]));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// peek into an element and check if it contains a FBX property, if so return its name.
|
||||
std::string PeekPropertyName(const Element &element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList &tok = element.Tokens();
|
||||
if (tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ParseTokenAsString(tok[0]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable() :
|
||||
templateProps(), element() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
|
||||
templateProps(templateProps), element(element) {
|
||||
const ScopePtr scope = GetRequiredScope(element);
|
||||
ERR_FAIL_COND(!scope);
|
||||
for (const ElementMap::value_type &v : scope->Elements()) {
|
||||
if (v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &name = PeekPropertyName(*v.second);
|
||||
if (!name.length()) {
|
||||
DOMWarning("could not read property name", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name, v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
// since the above checks for duplicates we can be sure to insert the only match here.
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::~PropertyTable() {
|
||||
for (PropertyMap::value_type &v : props) {
|
||||
delete v.second;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyPtr PropertyTable::Get(const std::string &name) const {
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if (lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(lit->second);
|
||||
it = props.find(name);
|
||||
|
||||
//ai_assert(it != props.end());
|
||||
}
|
||||
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
if (templateProps) {
|
||||
return templateProps->Get(name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
|
||||
DirectPropertyMap result;
|
||||
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
for (const LazyPropertyMap::value_type &element : lazyProps) {
|
||||
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) continue;
|
||||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
Property *prop = ReadTypedProperty(element.second);
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) continue;
|
||||
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
222
modules/fbx/fbx_parser/FBXProperties.h
Normal file
222
modules/fbx/fbx_parser/FBXProperties.h
Normal file
@ -0,0 +1,222 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.h
|
||||
* @brief FBX dynamic properties
|
||||
*/
|
||||
#ifndef FBX_PROPERTIES_H
|
||||
#define FBX_PROPERTIES_H
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// Forward declarations
|
||||
class Element;
|
||||
|
||||
/** Represents a dynamic property. Type info added by deriving classes,
|
||||
* see #TypedProperty.
|
||||
Example:
|
||||
@verbatim
|
||||
P: "ShininessExponent", "double", "Number", "",0.5
|
||||
@endvebatim
|
||||
*/
|
||||
class Property {
|
||||
protected:
|
||||
Property();
|
||||
|
||||
public:
|
||||
virtual ~Property();
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
const T *As() const {
|
||||
return dynamic_cast<const T *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedProperty : public Property {
|
||||
public:
|
||||
explicit TypedProperty(const T &value) :
|
||||
value(value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
const T &Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
#define new_Property new Property
|
||||
typedef Property *PropertyPtr;
|
||||
typedef std::map<std::string, PropertyPtr> DirectPropertyMap;
|
||||
typedef std::map<std::string, PropertyPtr> PropertyMap;
|
||||
typedef std::map<std::string, ElementPtr> LazyPropertyMap;
|
||||
|
||||
/**
|
||||
* Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
|
||||
*/
|
||||
class PropertyTable {
|
||||
public:
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
PropertyTable(const ElementPtr element, const PropertyTable *templateProps);
|
||||
~PropertyTable();
|
||||
|
||||
PropertyPtr Get(const std::string &name) const;
|
||||
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
const ElementPtr GetElement() const {
|
||||
return element;
|
||||
}
|
||||
|
||||
const PropertyMap &GetProperties() const {
|
||||
return props;
|
||||
}
|
||||
|
||||
const LazyPropertyMap &GetLazyProperties() const {
|
||||
return lazyProps;
|
||||
}
|
||||
|
||||
const PropertyTable *TemplateProps() const {
|
||||
return templateProps;
|
||||
}
|
||||
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
|
||||
private:
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
const PropertyTable *templateProps = nullptr;
|
||||
const ElementPtr element = nullptr;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, const T &defaultValue) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T> >();
|
||||
if (nullptr == tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
if (!useTemplate) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
const PropertyTable *templ = in->TemplateProps();
|
||||
if (nullptr == templ) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
prop = templ->Get(name);
|
||||
if (nullptr == prop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T> >();
|
||||
if (nullptr == tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PROPERTIES_H
|
249
modules/fbx/fbx_parser/FBXTokenizer.cpp
Normal file
249
modules/fbx/fbx_parser/FBXTokenizer.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.cpp
|
||||
* @brief Implementation of the FBX broadphase lexer
|
||||
*/
|
||||
|
||||
// tab width for logging columns
|
||||
#define ASSIMP_FBX_TAB_WIDTH 4
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) :
|
||||
sbegin(p_sbegin),
|
||||
send(p_send),
|
||||
type(p_type),
|
||||
line(p_line),
|
||||
column(p_column) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::~Token() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, unsigned int line, unsigned int column) {
|
||||
print_error("[FBX-Tokenize]" + String(message.c_str()) + " " + itos(line) + ":" + itos(column));
|
||||
}
|
||||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *&end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
bool must_have_token = false) {
|
||||
if (start && end) {
|
||||
// sanity check:
|
||||
// tokens should have no whitespace outside quoted text and [start,end] should
|
||||
// properly delimit the valid range.
|
||||
bool in_double_quotes = false;
|
||||
for (const char *c = start; c != end + 1; ++c) {
|
||||
if (*c == '\"') {
|
||||
in_double_quotes = !in_double_quotes;
|
||||
}
|
||||
|
||||
if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
|
||||
TokenizeError("unexpected whitespace in token", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
TokenizeError("non-terminated double quotes", line, column);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(start, end + 1, type, line, column));
|
||||
} else if (must_have_token) {
|
||||
TokenizeError("unexpected character, expected data token", line, column);
|
||||
}
|
||||
|
||||
start = end = nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList &output_tokens, const char *input) {
|
||||
// line and column numbers numbers are one-based
|
||||
unsigned int line = 1;
|
||||
unsigned int column = 1;
|
||||
|
||||
bool comment = false;
|
||||
bool in_double_quotes = false;
|
||||
bool pending_data_token = false;
|
||||
|
||||
const char *token_begin = nullptr, *token_end = nullptr;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBXDocParser
|
204
modules/fbx/fbx_parser/FBXTokenizer.h
Normal file
204
modules/fbx/fbx_parser/FBXTokenizer.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.h
|
||||
* @brief FBX lexer
|
||||
*/
|
||||
#ifndef FBX_TOKENIZER_H
|
||||
#define FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXParseTools.h"
|
||||
#include "core/ustring.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
/** Rough classification for text FBX tokens used for constructing the
|
||||
* basic scope hierarchy. */
|
||||
enum TokenType {
|
||||
// {
|
||||
TokenType_OPEN_BRACKET = 0,
|
||||
|
||||
// }
|
||||
TokenType_CLOSE_BRACKET,
|
||||
|
||||
// '"blablubb"', '2', '*14' - very general token class,
|
||||
// further processing happens at a later stage.
|
||||
TokenType_DATA,
|
||||
|
||||
//
|
||||
TokenType_BINARY_DATA,
|
||||
|
||||
// ,
|
||||
TokenType_COMMA,
|
||||
|
||||
// blubb:
|
||||
TokenType_KEY
|
||||
};
|
||||
|
||||
/** Represents a single token in a FBX file. Tokens are
|
||||
* classified by the #TokenType enumerated types.
|
||||
*
|
||||
* Offers iterator protocol. Tokens are immutable. */
|
||||
class Token {
|
||||
private:
|
||||
static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
|
||||
|
||||
public:
|
||||
/** construct a textual token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column);
|
||||
|
||||
/** construct a binary token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, size_t p_offset);
|
||||
~Token();
|
||||
|
||||
public:
|
||||
std::string StringContents() const {
|
||||
return std::string(begin(), end());
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return column == BINARY_MARKER;
|
||||
}
|
||||
|
||||
const char *begin() const {
|
||||
return sbegin;
|
||||
}
|
||||
|
||||
const char *end() const {
|
||||
return send;
|
||||
}
|
||||
|
||||
TokenType Type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
size_t Offset() const {
|
||||
return offset;
|
||||
}
|
||||
|
||||
unsigned int Line() const {
|
||||
return static_cast<unsigned int>(line);
|
||||
}
|
||||
|
||||
unsigned int Column() const {
|
||||
return column;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DEBUG_ENABLED
|
||||
// full string copy for the sole purpose that it nicely appears
|
||||
// in msvc's debugger window.
|
||||
std::string contents;
|
||||
#endif
|
||||
|
||||
const char *sbegin = nullptr;
|
||||
const char *send = nullptr;
|
||||
const TokenType type;
|
||||
|
||||
union {
|
||||
size_t line;
|
||||
size_t offset;
|
||||
};
|
||||
const unsigned int column = 0;
|
||||
};
|
||||
|
||||
// Fixed leak by using shared_ptr for tokens
|
||||
typedef Token *TokenPtr;
|
||||
typedef std::vector<TokenPtr> TokenList;
|
||||
|
||||
#define new_Token new Token
|
||||
|
||||
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
|
||||
*
|
||||
* Skips over comments and generates line and column numbers.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @print_error if something goes wrong */
|
||||
void Tokenize(TokenList &output_tokens, const char *input);
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
*
|
||||
* Emits a token list suitable for direct parsing.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @print_error if something goes wrong */
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length);
|
||||
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_TOKENIZER_H
|
221
modules/fbx/fbx_parser/FBXUtil.cpp
Normal file
221
modules/fbx/fbx_parser/FBXUtil.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.cpp
|
||||
* @brief Implementation of internal FBX utility functions
|
||||
*/
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char *TokenTypeString(TokenType t) {
|
||||
switch (t) {
|
||||
case TokenType_OPEN_BRACKET:
|
||||
return "TOK_OPEN_BRACKET";
|
||||
|
||||
case TokenType_CLOSE_BRACKET:
|
||||
return "TOK_CLOSE_BRACKET";
|
||||
|
||||
case TokenType_DATA:
|
||||
return "TOK_DATA";
|
||||
|
||||
case TokenType_COMMA:
|
||||
return "TOK_COMMA";
|
||||
|
||||
case TokenType_KEY:
|
||||
return "TOK_KEY";
|
||||
|
||||
case TokenType_BINARY_DATA:
|
||||
return "TOK_BINARY_DATA";
|
||||
}
|
||||
|
||||
//ai_assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
static const uint8_t base64DecodeTable[128] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
|
||||
uint8_t DecodeBase64(char ch) {
|
||||
const auto idx = static_cast<uint8_t>(ch);
|
||||
if (idx > 127)
|
||||
return 255;
|
||||
return base64DecodeTable[idx];
|
||||
}
|
||||
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength) {
|
||||
if (inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
|
||||
const size_t full_length = (inLength * 3) >> 2; // div by 4
|
||||
if (full_length < equals) {
|
||||
return 0;
|
||||
}
|
||||
return full_length - equals;
|
||||
}
|
||||
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength) {
|
||||
if (maxOutLength == 0 || inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
|
||||
size_t dst_offset = 0;
|
||||
int val = 0, valb = -8;
|
||||
for (size_t src_offset = 0; src_offset < realLength; ++src_offset) {
|
||||
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
|
||||
if (table_value == 255) {
|
||||
return 0;
|
||||
}
|
||||
val = (val << 6) + table_value;
|
||||
valb += 6;
|
||||
if (valb >= 0) {
|
||||
out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
|
||||
valb -= 8;
|
||||
val &= 0xFFF;
|
||||
}
|
||||
}
|
||||
return dst_offset;
|
||||
}
|
||||
|
||||
static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
char EncodeBase64(char byte) {
|
||||
return to_base64_string[(size_t)byte];
|
||||
}
|
||||
|
||||
/** Encodes a block of 4 bytes to base64 encoding
|
||||
*
|
||||
* @param bytes Bytes to encode.
|
||||
* @param out_string String to write encoded values to.
|
||||
* @param string_pos Position in out_string.*/
|
||||
void EncodeByteBlock(const char *bytes, std::string &out_string, size_t string_pos) {
|
||||
char b0 = (bytes[0] & 0xFC) >> 2;
|
||||
char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
|
||||
char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
|
||||
char b3 = (bytes[2] & 0x3F);
|
||||
|
||||
out_string[string_pos + 0] = EncodeBase64(b0);
|
||||
out_string[string_pos + 1] = EncodeBase64(b1);
|
||||
out_string[string_pos + 2] = EncodeBase64(b2);
|
||||
out_string[string_pos + 3] = EncodeBase64(b3);
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const char *data, size_t length) {
|
||||
// calculate extra bytes needed to get a multiple of 3
|
||||
size_t extraBytes = 3 - length % 3;
|
||||
|
||||
// number of base64 bytes
|
||||
size_t encodedBytes = 4 * (length + extraBytes) / 3;
|
||||
|
||||
std::string encoded_string(encodedBytes, '=');
|
||||
|
||||
// read blocks of 3 bytes
|
||||
for (size_t ib3 = 0; ib3 < length / 3; ib3++) {
|
||||
const size_t iByte = ib3 * 3;
|
||||
const size_t iEncodedByte = ib3 * 4;
|
||||
const char *currData = &data[iByte];
|
||||
|
||||
EncodeByteBlock(currData, encoded_string, iEncodedByte);
|
||||
}
|
||||
|
||||
// if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
|
||||
if (extraBytes > 0) {
|
||||
char finalBytes[4] = { 0, 0, 0, 0 };
|
||||
memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
|
||||
|
||||
const size_t iEncodedByte = encodedBytes - 4;
|
||||
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
|
||||
|
||||
// add '=' at the end
|
||||
for (size_t i = 0; i < 4 * extraBytes / 3; i++)
|
||||
encoded_string[encodedBytes - i - 1] = '=';
|
||||
}
|
||||
return encoded_string;
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
@ -1,3 +1,33 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.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. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
@ -43,61 +73,26 @@ 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
|
||||
#ifndef FBX_UTIL_H
|
||||
#define FBX_UTIL_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
const char *TokenTypeString(TokenType t);
|
||||
|
||||
/** Decode a single Base64-encoded character.
|
||||
*
|
||||
@ -110,7 +105,7 @@ uint8_t DecodeBase64(char ch);
|
||||
* @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);
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength);
|
||||
|
||||
/** Decode a Base64-encoded string
|
||||
*
|
||||
@ -119,7 +114,7 @@ size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
|
||||
* @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);
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength);
|
||||
|
||||
char EncodeBase64(char byte);
|
||||
|
||||
@ -128,10 +123,9 @@ char EncodeBase64(char byte);
|
||||
* @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);
|
||||
std::string EncodeBase64(const char *data, size_t length);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // ! INCLUDED_AI_FBX_UTIL_H
|
||||
#endif // FBX_UTIL_H
|
@ -1,6 +1,6 @@
|
||||
Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2016, assimp team
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@ -33,8 +33,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(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.
|
||||
@ -43,7 +41,7 @@ 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
|
||||
are a copyright holder and believe that we credited you improperly or
|
||||
if you don't want your files to appear in the repository.
|
||||
|
||||
|
197
modules/fbx/readme.md
Normal file
197
modules/fbx/readme.md
Normal file
@ -0,0 +1,197 @@
|
||||
# Open Source FBX Specification for the Importer
|
||||
|
||||
The goal of this document is to make everything in FBX clearly stated, any errors will be corrected over time this
|
||||
is a first draft.
|
||||
|
||||
## fbx parser - originally from assimp
|
||||
|
||||
- Folder: /modules/fbx/fbx_parser
|
||||
- Upstream: assimp
|
||||
- Original Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
This can never be updated from upstream, we have heavily modified the parser to provide memory safety and add some
|
||||
functionality. If anything we should give this parser back to assimp at some point as it has a lot of new features.
|
||||
|
||||
# Updating assimp fbx parser
|
||||
|
||||
Don't. it's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
|
||||
|
||||
Many days were put into rewriting the parser to use safe code and safe memory accessors.
|
||||
|
||||
# File Headers
|
||||
|
||||
FBX Binaries start with the header "Kaydara FBX Binary"
|
||||
|
||||
FBX ASCII documents contain a larger header, sometimes with copyright information for a file.
|
||||
|
||||
Detecting these is pretty simple.
|
||||
|
||||
# What is an OP link?
|
||||
It's an object to property link. It lists the properties for that object in some cases. Source and destination based by
|
||||
ID.
|
||||
|
||||
# What is a OO link?
|
||||
Its an object to object link, it contains the ID source and destination ID.
|
||||
|
||||
# FBX Node connections
|
||||
|
||||
Nodes in FBX are connected using OO links, This means Object to Object.
|
||||
|
||||
FBX has a single other kind of link which is Object Property, this is used for Object to Property Links, this can be
|
||||
extra attributes, defaults, or even some simple settings.
|
||||
|
||||
# Bones / Joints / Locators
|
||||
|
||||
Bones in FBX are nodes, they initially have the Model:: Type, then have links to SubDeformer the sub deformer
|
||||
is part of the skin there is also an explicit Skin link, which then links to the geometry using OO links in the
|
||||
document.
|
||||
|
||||
# Rotation Order in FBX compared to Godot
|
||||
|
||||
**Godot uses the rotation order:** YXZ
|
||||
|
||||
**FBX has dynamic rotation order to prevent gimbal lock with complex animations**
|
||||
|
||||
```cpp
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
RotOrder_SphericXYZ // nobody uses this - as far as we can tell
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
# Pivot transforms
|
||||
|
||||
### Pivot description:
|
||||
- Maya and 3DS max consider everything to be in node space (bones joints, skins, lights, cameras, etc)
|
||||
- Everything is a node, this means essentially nodes are auto or variants
|
||||
- They are local to the node in the tree.
|
||||
- They are used to calculate where a node is in space
|
||||
```c++
|
||||
// For a better reference you can check editor_scene_importer_fbx.h
|
||||
// references: GenFBXTransform / read the data in
|
||||
// references: ComputePivotTransform / run the calculation
|
||||
// This is the local pivot transform for the node, not the global transforms
|
||||
Transform ComputePivotTransform(
|
||||
Transform chain[TransformationComp_MAXIMUM],
|
||||
Transform &geometric_transform) {
|
||||
|
||||
// Maya pivots
|
||||
Transform T = chain[TransformationComp_Translation];
|
||||
Transform Roff = chain[TransformationComp_RotationOffset];
|
||||
Transform Rp = chain[TransformationComp_RotationPivot];
|
||||
Transform Rpre = chain[TransformationComp_PreRotation];
|
||||
Transform R = chain[TransformationComp_Rotation];
|
||||
Transform Rpost = chain[TransformationComp_PostRotation];
|
||||
Transform Soff = chain[TransformationComp_ScalingOffset];
|
||||
Transform Sp = chain[TransformationComp_ScalingPivot];
|
||||
Transform S = chain[TransformationComp_Scaling];
|
||||
|
||||
// 3DS Max Pivots
|
||||
Transform OT = chain[TransformationComp_GeometricTranslation];
|
||||
Transform OR = chain[TransformationComp_GeometricRotation];
|
||||
Transform OS = chain[TransformationComp_GeometricScaling];
|
||||
|
||||
// Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node)
|
||||
geometric_transform = OT * OR * OS;
|
||||
// Calculate standard maya pivots
|
||||
return T * Roff * Rp * Rpre * R * Rpost.inverse() * Rp.inverse() * Soff * Sp * S * Sp.inverse();
|
||||
}
|
||||
```
|
||||
|
||||
# Transform inheritance for FBX Nodes
|
||||
|
||||
The goal of below is to explain why they implement this in the first place.
|
||||
|
||||
The use case is to make nodes have an option to override their local scaling or to make scaling influenced by orientation, which i would imagine would be useful for when you need to rotate a node and the child to scale based on the orientation rather than setting on the rotation matrix planes.
|
||||
```cpp
|
||||
// not modified the formatting here since this code must remain clear
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Parent Rotation * Local Rotation * Parent Scale * Local Scale -- Parent Rotation Offset * Parent ScalingOffset (Local scaling is offset by rotation of parent node)
|
||||
Transform_RSrs = 1, // Parent Rotation * Parent Scale * Local Rotation * Local Scale -- Parent * Local (normal mode)
|
||||
Transform_Rrs = 2, // Parent Rotation * Local Rotation * Local Scale -- Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Local scaling is offset by rotation of parent node
|
||||
Transform_RSrs = 1,
|
||||
// Parent * Local (normal mode)
|
||||
Transform_Rrs = 2,
|
||||
// Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
```
|
||||
|
||||
# Axis in FBX
|
||||
|
||||
Godot has one format for the declared axis
|
||||
|
||||
AXIS X, AXIS Y, -AXIS Z
|
||||
|
||||
FBX supports any format you can think of. As it has to support Maya and 3DS Max.
|
||||
|
||||
#### FBX File Header
|
||||
```json
|
||||
GlobalSettings: {
|
||||
Version: 1000
|
||||
Properties70: {
|
||||
P: "UpAxis", "int", "Integer", "",1
|
||||
P: "UpAxisSign", "int", "Integer", "",1
|
||||
P: "FrontAxis", "int", "Integer", "",2
|
||||
P: "FrontAxisSign", "int", "Integer", "",1
|
||||
P: "CoordAxis", "int", "Integer", "",0
|
||||
P: "CoordAxisSign", "int", "Integer", "",1
|
||||
P: "OriginalUpAxis", "int", "Integer", "",1
|
||||
P: "OriginalUpAxisSign", "int", "Integer", "",1
|
||||
P: "UnitScaleFactor", "double", "Number", "",1
|
||||
P: "OriginalUnitScaleFactor", "double", "Number", "",1
|
||||
P: "AmbientColor", "ColorRGB", "Color", "",0,0,0
|
||||
P: "DefaultCamera", "KString", "", "", "Producer Perspective"
|
||||
P: "TimeMode", "enum", "", "",6
|
||||
P: "TimeProtocol", "enum", "", "",2
|
||||
P: "SnapOnFrameMode", "enum", "", "",0
|
||||
P: "TimeSpanStart", "KTime", "Time", "",0
|
||||
P: "TimeSpanStop", "KTime", "Time", "",92372316000
|
||||
P: "CustomFrameRate", "double", "Number", "",-1
|
||||
P: "TimeMarker", "Compound", "", ""
|
||||
P: "CurrentTimeMarker", "int", "Integer", "",-1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### FBX FILE declares axis dynamically using FBX header
|
||||
Coord is X
|
||||
Up is Y
|
||||
Front is Z
|
||||
|
||||
#### GODOT - constant reference point
|
||||
Coord is X positive,
|
||||
Y is up positive,
|
||||
Front is -Z negative
|
||||
|
||||
### Explaining MeshGeometry indexing
|
||||
|
||||
Reference type declared:
|
||||
- Direct (directly related to the mapping information type)
|
||||
- IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
|
||||
ControlPoint is a vertex
|
||||
* None The mapping is undetermined.
|
||||
* ByVertex There will be one mapping coordinate for each surface control point/vertex.
|
||||
* If you have direct reference type vertices [x]
|
||||
* If you have IndexToDirect reference type the UV
|
||||
* ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
* ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
* One mapping per polygon polygon x has this normal x
|
||||
* For each vertex of the polygon then set the normal to x
|
||||
* ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
* AllSame There can be only one mapping coordinate for the whole surface.
|
@ -31,23 +31,23 @@
|
||||
#include "register_types.h"
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor_scene_importer_assimp.h"
|
||||
#include "editor_scene_importer_fbx.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _editor_init() {
|
||||
Ref<EditorSceneImporterAssimp> import_assimp;
|
||||
import_assimp.instance();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_assimp);
|
||||
Ref<EditorSceneImporterFBX> import_fbx;
|
||||
import_fbx.instance();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_fbx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_assimp_types() {
|
||||
void register_fbx_types() {
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
ClassDB::register_class<EditorSceneImporterAssimp>();
|
||||
ClassDB::register_class<EditorSceneImporterFBX>();
|
||||
|
||||
ClassDB::set_current_api(prev_api);
|
||||
|
||||
@ -55,5 +55,5 @@ void register_assimp_types() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_assimp_types() {
|
||||
void unregister_fbx_types() {
|
||||
}
|
@ -28,10 +28,10 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ASSIMP_REGISTER_TYPES_H
|
||||
#define ASSIMP_REGISTER_TYPES_H
|
||||
#ifndef FBX_REGISTER_TYPES_H
|
||||
#define FBX_REGISTER_TYPES_H
|
||||
|
||||
void register_assimp_types();
|
||||
void unregister_assimp_types();
|
||||
void register_fbx_types();
|
||||
void unregister_fbx_types();
|
||||
|
||||
#endif // ASSIMP_REGISTER_TYPES_H
|
||||
#endif // FBX_REGISTER_TYPES_H
|
152
modules/fbx/tools/import_utils.cpp
Normal file
152
modules/fbx/tools/import_utils.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "import_utils.h"
|
||||
|
||||
Vector3 ImportUtils::deg2rad(const Vector3 &p_rotation) {
|
||||
return p_rotation / 180.0 * Math_PI;
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::rad2deg(const Vector3 &p_rotation) {
|
||||
return p_rotation / Math_PI * 180.0;
|
||||
}
|
||||
|
||||
Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
Basis ret;
|
||||
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
ret.set_euler_zyx(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
ret.set_euler_yzx(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
ret.set_euler_xzy(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
ret.set_euler_zxy(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
ret.set_euler_yxz(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
ret.set_euler_xyz(p_rotation);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO do this.
|
||||
break;
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Quat ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
return ImportUtils::EulerToBasis(mode, p_rotation);
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation) {
|
||||
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
return p_rotation.get_euler_zyx();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
return p_rotation.get_euler_yzx();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
return p_rotation.get_euler_xzy();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
return p_rotation.get_euler_zxy();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
return p_rotation.get_euler_yxz();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
return p_rotation.get_euler_xyz();
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO
|
||||
return Vector3();
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
return Vector3();
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation) {
|
||||
return BasisToEuler(mode, p_rotation);
|
||||
}
|
||||
|
||||
Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) {
|
||||
Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale);
|
||||
ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?");
|
||||
return unscaled;
|
||||
}
|
||||
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
|
||||
ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necesary");
|
||||
// Using long double to make sure that normal is computed for even really tiny objects.
|
||||
typedef long double ldouble;
|
||||
ldouble x = 0.0;
|
||||
ldouble y = 0.0;
|
||||
ldouble z = 0.0;
|
||||
for (size_t i = 0; i < p_vertices.size(); i += 1) {
|
||||
const Vector3 current = p_vertices[i];
|
||||
const Vector3 next = p_vertices[(i + 1) % p_vertices.size()];
|
||||
x += (ldouble(current.y) - ldouble(next.y)) * (ldouble(current.z) + ldouble(next.z));
|
||||
y += (ldouble(current.z) - ldouble(next.z)) * (ldouble(current.x) + ldouble(next.x));
|
||||
z += (ldouble(current.x) - ldouble(next.x)) * (ldouble(current.y) + ldouble(next.y));
|
||||
}
|
||||
const ldouble l2 = x * x + y * y + z * z;
|
||||
if (l2 == 0.0) {
|
||||
return (p_vertices[0] - p_vertices[1]).normalized().cross((p_vertices[0] - p_vertices[2]).normalized()).normalized();
|
||||
} else {
|
||||
const double l = Math::sqrt(double(l2));
|
||||
return Vector3(x / l, y / l, z / l);
|
||||
}
|
||||
}
|
386
modules/fbx/tools/import_utils.h
Normal file
386
modules/fbx/tools/import_utils.h
Normal file
@ -0,0 +1,386 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_UTILS_FBX_IMPORTER_H
|
||||
#define IMPORT_UTILS_FBX_IMPORTER_H
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
/**
|
||||
* Import Utils
|
||||
* Conversion tools / glue code to convert from FBX to Godot
|
||||
*/
|
||||
class ImportUtils {
|
||||
public:
|
||||
/// Convert a vector from degrees to radians.
|
||||
static Vector3 deg2rad(const Vector3 &p_rotation);
|
||||
|
||||
/// Convert a vector from radians to degrees.
|
||||
static Vector3 rad2deg(const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts basis into rotation order vector (in rad).
|
||||
static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
|
||||
|
||||
/// Converts quaternion into rotation order vector (in rad).
|
||||
static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation);
|
||||
|
||||
static void debug_xform(String name, const Transform &t) {
|
||||
print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static String FBXNodeToName(const std::string &name) {
|
||||
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
|
||||
// this causes ambiguities, well possible between empty identifiers,
|
||||
// such as "Model::" and ""). Make sure the behaviour is consistent
|
||||
// across multiple calls to FixNodeName().
|
||||
|
||||
// We must remove this from the name
|
||||
// Some bones have this
|
||||
// SubDeformer::
|
||||
// Meshes, Joints have this, some other IK elements too.
|
||||
// Model::
|
||||
|
||||
String node_name = String(name.c_str());
|
||||
|
||||
if (node_name.substr(0, 7) == "Model::") {
|
||||
node_name = node_name.substr(7, node_name.length() - 7);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 13) == "SubDeformer::") {
|
||||
node_name = node_name.substr(13, node_name.length() - 13);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimStack::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 15) == "AnimCurveNode::") {
|
||||
node_name = node_name.substr(15, node_name.length() - 15);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimCurve::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Geometry::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Material::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 9) == "Texture::") {
|
||||
node_name = node_name.substr(9, node_name.length() - 9);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
static std::string FBXAnimMeshName(const std::string &name) {
|
||||
if (name.length()) {
|
||||
size_t indexOf = name.find_first_of("::");
|
||||
if (indexOf != std::string::npos && indexOf < name.size() - 2) {
|
||||
return name.substr(indexOf + 2);
|
||||
}
|
||||
}
|
||||
return name.length() ? name : "AnimMesh";
|
||||
}
|
||||
|
||||
static Vector3 safe_import_vector3(const Vector3 &p_vec) {
|
||||
Vector3 vector = p_vec;
|
||||
if (Math::is_equal_approx(0, vector.x)) {
|
||||
vector.x = 0;
|
||||
}
|
||||
|
||||
if (Math::is_equal_approx(0, vector.y)) {
|
||||
vector.y = 0;
|
||||
}
|
||||
|
||||
if (Math::is_equal_approx(0, vector.z)) {
|
||||
vector.z = 0;
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
static void debug_xform(String name, const Basis &t) {
|
||||
//print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static Vector3 FixAxisConversions(Vector3 input) {
|
||||
return Vector3(input.x, input.y, input.z);
|
||||
}
|
||||
|
||||
static void AlignMeshAxes(std::vector<Vector3> &vertex_data) {
|
||||
for (size_t x = 0; x < vertex_data.size(); x++) {
|
||||
vertex_data[x] = FixAxisConversions(vertex_data[x]);
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetImportFbx {
|
||||
enum ETimeMode {
|
||||
TIME_MODE_DEFAULT = 0,
|
||||
TIME_MODE_120 = 1,
|
||||
TIME_MODE_100 = 2,
|
||||
TIME_MODE_60 = 3,
|
||||
TIME_MODE_50 = 4,
|
||||
TIME_MODE_48 = 5,
|
||||
TIME_MODE_30 = 6,
|
||||
TIME_MODE_30_DROP = 7,
|
||||
TIME_MODE_NTSC_DROP_FRAME = 8,
|
||||
TIME_MODE_NTSC_FULL_FRAME = 9,
|
||||
TIME_MODE_PAL = 10,
|
||||
TIME_MODE_CINEMA = 11,
|
||||
TIME_MODE_1000 = 12,
|
||||
TIME_MODE_CINEMA_ND = 13,
|
||||
TIME_MODE_CUSTOM = 14,
|
||||
TIME_MODE_TIME_MODE_COUNT = 15
|
||||
};
|
||||
enum UpAxis {
|
||||
UP_VECTOR_AXIS_X = 1,
|
||||
UP_VECTOR_AXIS_Y = 2,
|
||||
UP_VECTOR_AXIS_Z = 3
|
||||
};
|
||||
enum FrontAxis {
|
||||
FRONT_PARITY_EVEN = 1,
|
||||
FRONT_PARITY_ODD = 2,
|
||||
};
|
||||
|
||||
enum CoordAxis {
|
||||
COORD_RIGHT = 0,
|
||||
COORD_LEFT = 1
|
||||
};
|
||||
};
|
||||
|
||||
/** Get fbx fps for time mode meta data
|
||||
*/
|
||||
static float get_fbx_fps(int32_t time_mode) {
|
||||
switch (time_mode) {
|
||||
case AssetImportFbx::TIME_MODE_DEFAULT: return 24;
|
||||
case AssetImportFbx::TIME_MODE_120: return 120;
|
||||
case AssetImportFbx::TIME_MODE_100: return 100;
|
||||
case AssetImportFbx::TIME_MODE_60: return 60;
|
||||
case AssetImportFbx::TIME_MODE_50: return 50;
|
||||
case AssetImportFbx::TIME_MODE_48: return 48;
|
||||
case AssetImportFbx::TIME_MODE_30: return 30;
|
||||
case AssetImportFbx::TIME_MODE_30_DROP: return 30;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME: return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME: return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_PAL: return 25;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA: return 24;
|
||||
case AssetImportFbx::TIME_MODE_1000: return 1000;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA_ND: return 23.976f;
|
||||
case AssetImportFbx::TIME_MODE_CUSTOM: return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) {
|
||||
int time_mode = FBXSettings->TimeMode();
|
||||
|
||||
// get the animation FPS
|
||||
float frames_per_second = get_fbx_fps(time_mode);
|
||||
|
||||
// handle animation custom FPS time.
|
||||
if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) {
|
||||
print_verbose("FBX Animation has custom FPS setting");
|
||||
frames_per_second = FBXSettings->CustomFrameRate();
|
||||
|
||||
// not our problem this is the modeller, we can print as an error so they can fix the source.
|
||||
if (frames_per_second == 0) {
|
||||
print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value");
|
||||
}
|
||||
}
|
||||
return frames_per_second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find hardcoded textures from assimp which could be in many different directories
|
||||
*/
|
||||
|
||||
/**
|
||||
* set_texture_mapping_mode
|
||||
* Helper to check the mapping mode of the texture (repeat, clamp and mirror)
|
||||
*/
|
||||
// static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
|
||||
// ERR_FAIL_COND(texture.is_null());
|
||||
// ERR_FAIL_COND(map_mode == NULL);
|
||||
// aiTextureMapMode tex_mode = map_mode[0];
|
||||
|
||||
// int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
// if (tex_mode == aiTextureMapMode_Wrap) {
|
||||
// //Default
|
||||
// } else if (tex_mode == aiTextureMapMode_Clamp) {
|
||||
// flags = flags & ~Texture::FLAG_REPEAT;
|
||||
// } else if (tex_mode == aiTextureMapMode_Mirror) {
|
||||
// flags = flags | Texture::FLAG_MIRRORED_REPEAT;
|
||||
// }
|
||||
// texture->set_flags(flags);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Load or load from cache image :)
|
||||
* We need to upgrade this in the later version :) should not be hard
|
||||
*/
|
||||
//static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){
|
||||
|
||||
// Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
|
||||
|
||||
// // if our cache contains this image then don't bother
|
||||
// if (match) {
|
||||
// return match->get();
|
||||
// }
|
||||
|
||||
// Vector<String> split_path = p_path.get_basename().split("*");
|
||||
// if (split_path.size() == 2) {
|
||||
// size_t texture_idx = split_path[1].to_int();
|
||||
// ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
|
||||
// aiTexture *tex = p_scene->mTextures[texture_idx];
|
||||
// String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
|
||||
// filename = filename.get_file();
|
||||
// print_verbose("Open Asset Import: Loading embedded texture " + filename);
|
||||
// if (tex->mHeight == 0) {
|
||||
// if (tex->CheckFormat("png")) {
|
||||
// Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("jpg")) {
|
||||
// Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("dds")) {
|
||||
// ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
|
||||
// }
|
||||
// } else {
|
||||
// Ref<Image> img;
|
||||
// img.instance();
|
||||
// PoolByteArray arr;
|
||||
// uint32_t size = tex->mWidth * tex->mHeight;
|
||||
// arr.resize(size);
|
||||
// memcpy(arr.write().ptr(), tex->pcData, size);
|
||||
// ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
|
||||
// //ARGB8888 to RGBA8888
|
||||
// for (int32_t i = 0; i < arr.size() / 4; i++) {
|
||||
// arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
|
||||
// arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
|
||||
// arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
|
||||
// arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
|
||||
// }
|
||||
// img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// }
|
||||
// return Ref<Image>();
|
||||
// } else {
|
||||
// Ref<Texture> texture = ResourceLoader::load(p_path);
|
||||
// ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
|
||||
// Ref<Image> image = texture->get_data();
|
||||
// ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, image);
|
||||
// return image;
|
||||
// }
|
||||
|
||||
// return Ref<Image>();
|
||||
//}
|
||||
|
||||
// /* create texture from assimp data, if found in path */
|
||||
// static bool CreateAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiString texture_path,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// filename = get_raw_string_from_assimp(texture_path);
|
||||
// path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
|
||||
// bool found = false;
|
||||
// find_texture_path(state.path, path, found);
|
||||
// if (found) {
|
||||
// image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
|
||||
// if (image_state.raw_image.is_valid()) {
|
||||
// image_state.texture.instance();
|
||||
// image_state.texture->create_from_image(image_state.raw_image);
|
||||
// image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
// /** GetAssimpTexture
|
||||
// * Designed to retrieve textures for you
|
||||
// */
|
||||
// static bool GetAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiMaterial *ai_material,
|
||||
// aiTextureType texture_type,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// aiString ai_filename = aiString();
|
||||
// if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
|
||||
// return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
// Apply the transforms so the basis will have scale 1.
|
||||
Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale);
|
||||
|
||||
/// Uses the Newell's method to compute any polygon normal.
|
||||
/// The polygon must be at least size of 3 or bigger.
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices);
|
||||
|
||||
#endif // IMPORT_UTILS_FBX_IMPORTER_H
|
18
thirdparty/README.md
vendored
18
thirdparty/README.md
vendored
@ -1,24 +1,6 @@
|
||||
# Third party libraries
|
||||
|
||||
|
||||
## 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`
|
||||
|
||||
|
||||
## bullet
|
||||
|
||||
- Upstream: https://github.com/bulletphysics/bullet3
|
||||
|
156
thirdparty/assimp/code/CApi/AssimpCExport.cpp
vendored
156
thirdparty/assimp/code/CApi/AssimpCExport.cpp
vendored
@ -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
|
136
thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp
vendored
136
thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp
vendored
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
695
thirdparty/assimp/code/Common/Assimp.cpp
vendored
695
thirdparty/assimp/code/Common/Assimp.cpp
vendored
@ -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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
656
thirdparty/assimp/code/Common/BaseImporter.cpp
vendored
656
thirdparty/assimp/code/Common/BaseImporter.cpp
vendored
@ -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 %%%");
|
||||
}
|
||||
}
|
107
thirdparty/assimp/code/Common/BaseProcess.cpp
vendored
107
thirdparty/assimp/code/Common/BaseProcess.cpp
vendored
@ -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;
|
||||
}
|
||||
|
290
thirdparty/assimp/code/Common/BaseProcess.h
vendored
290
thirdparty/assimp/code/Common/BaseProcess.h
vendored
@ -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
|
155
thirdparty/assimp/code/Common/Bitmap.cpp
vendored
155
thirdparty/assimp/code/Common/Bitmap.cpp
vendored
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
88
thirdparty/assimp/code/Common/CreateAnimMesh.cpp
vendored
88
thirdparty/assimp/code/Common/CreateAnimMesh.cpp
vendored
@ -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
|
154
thirdparty/assimp/code/Common/DefaultIOStream.cpp
vendored
154
thirdparty/assimp/code/Common/DefaultIOStream.cpp
vendored
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
216
thirdparty/assimp/code/Common/DefaultIOSystem.cpp
vendored
216
thirdparty/assimp/code/Common/DefaultIOSystem.cpp
vendored
@ -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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
418
thirdparty/assimp/code/Common/DefaultLogger.cpp
vendored
418
thirdparty/assimp/code/Common/DefaultLogger.cpp
vendored
@ -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
|
@ -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
|
636
thirdparty/assimp/code/Common/Exporter.cpp
vendored
636
thirdparty/assimp/code/Common/Exporter.cpp
vendored
@ -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
|
107
thirdparty/assimp/code/Common/FileLogStream.h
vendored
107
thirdparty/assimp/code/Common/FileLogStream.h
vendored
@ -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
|
345
thirdparty/assimp/code/Common/FileSystemFilter.h
vendored
345
thirdparty/assimp/code/Common/FileSystemFilter.h
vendored
@ -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
|
102
thirdparty/assimp/code/Common/IFF.h
vendored
102
thirdparty/assimp/code/Common/IFF.h
vendored
@ -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
|
1174
thirdparty/assimp/code/Common/Importer.cpp
vendored
1174
thirdparty/assimp/code/Common/Importer.cpp
vendored
File diff suppressed because it is too large
Load Diff
247
thirdparty/assimp/code/Common/Importer.h
vendored
247
thirdparty/assimp/code/Common/Importer.h
vendored
@ -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
|
377
thirdparty/assimp/code/Common/ImporterRegistry.cpp
vendored
377
thirdparty/assimp/code/Common/ImporterRegistry.cpp
vendored
@ -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
|
229
thirdparty/assimp/code/Common/PolyTools.h
vendored
229
thirdparty/assimp/code/Common/PolyTools.h
vendored
@ -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
|
265
thirdparty/assimp/code/Common/PostStepRegistry.cpp
vendored
265
thirdparty/assimp/code/Common/PostStepRegistry.cpp
vendored
@ -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
|
||||
}
|
||||
|
||||
}
|
113
thirdparty/assimp/code/Common/RemoveComments.cpp
vendored
113
thirdparty/assimp/code/Common/RemoveComments.cpp
vendored
@ -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
|
168
thirdparty/assimp/code/Common/SGSpatialSort.cpp
vendored
168
thirdparty/assimp/code/Common/SGSpatialSort.cpp
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
1350
thirdparty/assimp/code/Common/SceneCombiner.cpp
vendored
1350
thirdparty/assimp/code/Common/SceneCombiner.cpp
vendored
File diff suppressed because it is too large
Load Diff
261
thirdparty/assimp/code/Common/ScenePreprocessor.cpp
vendored
261
thirdparty/assimp/code/Common/ScenePreprocessor.cpp
vendored
@ -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. );
|
||||
}
|
||||
}
|
125
thirdparty/assimp/code/Common/ScenePreprocessor.h
vendored
125
thirdparty/assimp/code/Common/ScenePreprocessor.h
vendored
@ -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
|
105
thirdparty/assimp/code/Common/ScenePrivate.h
vendored
105
thirdparty/assimp/code/Common/ScenePrivate.h
vendored
@ -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
|
@ -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;
|
||||
}
|
342
thirdparty/assimp/code/Common/SpatialSort.cpp
vendored
342
thirdparty/assimp/code/Common/SpatialSort.cpp
vendored
@ -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;
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
@ -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
|
507
thirdparty/assimp/code/Common/StandardShapes.cpp
vendored
507
thirdparty/assimp/code/Common/StandardShapes.cpp
vendored
@ -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
|
101
thirdparty/assimp/code/Common/StdOStreamLogStream.h
vendored
101
thirdparty/assimp/code/Common/StdOStreamLogStream.h
vendored
@ -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
|
589
thirdparty/assimp/code/Common/Subdivision.cpp
vendored
589
thirdparty/assimp/code/Common/Subdivision.cpp
vendored
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
248
thirdparty/assimp/code/Common/TargetAnimation.cpp
vendored
248
thirdparty/assimp/code/Common/TargetAnimation.cpp
vendored
@ -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;
|
||||
}
|
||||
}
|
183
thirdparty/assimp/code/Common/TargetAnimation.h
vendored
183
thirdparty/assimp/code/Common/TargetAnimation.h
vendored
@ -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
|
181
thirdparty/assimp/code/Common/Version.cpp
vendored
181
thirdparty/assimp/code/Common/Version.cpp
vendored
@ -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 );
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
196
thirdparty/assimp/code/Common/assbin_chunks.h
vendored
196
thirdparty/assimp/code/Common/assbin_chunks.h
vendored
@ -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><root>/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><root>/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><root>/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><root>/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
|
140
thirdparty/assimp/code/Common/scene.cpp
vendored
140
thirdparty/assimp/code/Common/scene.cpp
vendored
@ -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;
|
||||
}
|
||||
}
|
79
thirdparty/assimp/code/Common/simd.cpp
vendored
79
thirdparty/assimp/code/Common/simd.cpp
vendored
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user