Merge pull request #44599 from RevoluPowered/remove_assimp_fbx
[fbx] remove old assimp plugin - pending fbx upgrade
This commit is contained in:
commit
a003ff0cf2
|
@ -1,108 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_assimp = env_modules.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
# Force bundled version for now, there's no released version of Assimp with
|
||||
# support for ArmaturePopulate which we use from their master branch.
|
||||
|
||||
if True: # env['builtin_assimp']:
|
||||
thirdparty_dir = "#thirdparty/assimp"
|
||||
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp"])
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/code"])
|
||||
env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/include"])
|
||||
|
||||
# env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_SINGLETHREADED"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_BOOST_WORKAROUND"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OWN_ZLIB"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_EXPORT"])
|
||||
|
||||
# Importers we don't need
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3DS_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3MF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AMF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASE_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASSBIN_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_B3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BLEND_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BVH_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_C4D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COB_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COLLADA_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_CSM_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_DXF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF2_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_HMP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IFC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRR_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRRMESH_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWO_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWS_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_M3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD2_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD3_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDC_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MMD_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MS3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NDO_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NFF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OBJ_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OFF_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OGRE_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OPENGEX_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_PLY_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3BSP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_RAW_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SIB_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SMD_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STEP_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_TERRAGEN_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X3D_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_XGL_IMPORTER"])
|
||||
env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X_IMPORTER"])
|
||||
|
||||
if env["platform"] == "windows":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_WINDOWS"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "WINDOWS")])
|
||||
elif env["platform"] == "linuxbsd":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_LINUX"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "LINUX")])
|
||||
elif env["platform"] == "osx":
|
||||
env_assimp.Append(CPPDEFINES=["PLATFORM_DARWIN"])
|
||||
env_assimp.Append(CPPDEFINES=[("PLATFORM", "DARWIN")])
|
||||
|
||||
env_thirdparty = env_assimp.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
|
||||
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Common/*.cpp"))
|
||||
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
|
||||
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/Material/*.cpp"))
|
||||
env_thirdparty.add_source_files(thirdparty_obj, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
|
||||
env.modules_sources += thirdparty_obj
|
||||
|
||||
|
||||
# Godot source files
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_assimp.add_source_files(module_obj, "*.cpp")
|
||||
env.modules_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
|
@ -1,6 +0,0 @@
|
|||
def can_build(env, platform):
|
||||
return env["tools"]
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
File diff suppressed because it is too large
Load Diff
|
@ -1,149 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* editor_scene_importer_assimp.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_ASSIMP_H
|
||||
#define EDITOR_SCENE_IMPORTER_ASSIMP_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "core/core_bind.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/Logger.hpp>
|
||||
#include <map>
|
||||
|
||||
#include "import_state.h"
|
||||
#include "import_utils.h"
|
||||
|
||||
using namespace AssimpImporter;
|
||||
|
||||
class AssimpStream : public Assimp::LogStream {
|
||||
public:
|
||||
// Constructor
|
||||
AssimpStream() {}
|
||||
|
||||
// Destructor
|
||||
~AssimpStream() {}
|
||||
// Write something using your own functionality
|
||||
void write(const char *message) {
|
||||
print_verbose(String("Open Asset Import: ") + String(message).strip_edges());
|
||||
}
|
||||
};
|
||||
|
||||
class EditorSceneImporterAssimp : public EditorSceneImporter {
|
||||
private:
|
||||
GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter);
|
||||
|
||||
struct AssetImportAnimation {
|
||||
enum Interpolation {
|
||||
INTERP_LINEAR,
|
||||
INTERP_STEP,
|
||||
INTERP_CATMULLROMSPLINE,
|
||||
INTERP_CUBIC_SPLINE
|
||||
};
|
||||
};
|
||||
|
||||
struct BoneInfo {
|
||||
uint32_t bone;
|
||||
float weight;
|
||||
};
|
||||
|
||||
Ref<Mesh> _generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
|
||||
const aiNode *assimp_node, Ref<Skin> &skin,
|
||||
Skeleton3D *&skeleton_assigned);
|
||||
|
||||
// simple object creation functions
|
||||
Node3D *create_light(ImportState &state,
|
||||
const String &node_name,
|
||||
Transform &look_at_transform);
|
||||
Node3D *create_camera(
|
||||
ImportState &state,
|
||||
const String &node_name,
|
||||
Transform &look_at_transform);
|
||||
// non recursive - linear so must not use recursive arguments
|
||||
MeshInstance3D *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform);
|
||||
// recursive node generator
|
||||
void _generate_node(ImportState &state, const aiNode *assimp_node);
|
||||
void _insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
|
||||
int anim_fps, Ref<Animation> animation, float ticks_per_second,
|
||||
Skeleton3D *skeleton, const NodePath &node_path,
|
||||
const String &node_name, aiBone *track_bone);
|
||||
|
||||
void _import_animation(ImportState &state, int p_animation_index, int p_bake_fps);
|
||||
Node *get_node_by_name(ImportState &state, String name);
|
||||
aiBone *get_bone_from_stack(ImportState &state, aiString name);
|
||||
Node3D *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
|
||||
|
||||
template <class T>
|
||||
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
|
||||
void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const;
|
||||
|
||||
struct ImportFormat {
|
||||
Vector<String> extensions;
|
||||
bool is_default;
|
||||
};
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
EditorSceneImporterAssimp() {
|
||||
Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
|
||||
unsigned int severity = Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
|
||||
Assimp::DefaultLogger::get()->attachStream(new AssimpStream(), severity);
|
||||
}
|
||||
~EditorSceneImporterAssimp() {
|
||||
Assimp::DefaultLogger::kill();
|
||||
}
|
||||
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
|
||||
Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path);
|
||||
|
||||
static void RegenerateBoneStack(ImportState &state);
|
||||
|
||||
void RegenerateBoneStack(ImportState &state, aiMesh *mesh);
|
||||
};
|
||||
#endif
|
||||
#endif
|
|
@ -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,132 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* import_state.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORT_STATE_H
|
||||
#define EDITOR_SCENE_IMPORT_STATE_H
|
||||
|
||||
#include "core/core_bind.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/Logger.hpp>
|
||||
|
||||
namespace AssimpImporter {
|
||||
/** Import state is for global scene import data
|
||||
* This makes the code simpler and contains useful lookups.
|
||||
*/
|
||||
struct ImportState {
|
||||
String path;
|
||||
Node3D *root;
|
||||
const aiScene *assimp_scene;
|
||||
uint32_t max_bone_weights;
|
||||
|
||||
Map<String, Ref<Mesh>> mesh_cache;
|
||||
Map<int, Ref<Material>> material_cache;
|
||||
Map<String, int> light_cache;
|
||||
Map<String, int> camera_cache;
|
||||
|
||||
// very useful for when you need to ask assimp for the bone mesh
|
||||
|
||||
Map<const aiNode *, Node *> assimp_node_map;
|
||||
Map<String, Ref<Image>> path_to_image_cache;
|
||||
|
||||
// Generation 3 - determinisitic iteration
|
||||
// to lower potential recursion errors
|
||||
List<const aiNode *> nodes;
|
||||
Map<const aiNode *, Node3D *> flat_node_map;
|
||||
AnimationPlayer *animation_player;
|
||||
|
||||
// Generation 3 - deterministic armatures
|
||||
// list of armature nodes - flat and simple to parse
|
||||
// assimp node, node in godot
|
||||
List<aiNode *> armature_nodes;
|
||||
Map<const aiNode *, Skeleton3D *> armature_skeletons;
|
||||
Map<aiBone *, Skeleton3D *> skeleton_bone_map;
|
||||
// Generation 3 - deterministic bone handling
|
||||
// bones from the stack are popped when found
|
||||
// this means we can detect
|
||||
// what bones are for other armatures
|
||||
List<aiBone *> bone_stack;
|
||||
|
||||
// EditorSceneImporter::ImportFlags
|
||||
uint32_t import_flags;
|
||||
};
|
||||
|
||||
struct AssimpImageData {
|
||||
Ref<Image> raw_image;
|
||||
Ref<ImageTexture> texture;
|
||||
aiTextureMapMode map_mode[2];
|
||||
};
|
||||
|
||||
/** Recursive state is used to push state into functions instead of specifying them
|
||||
* This makes the code easier to handle too and add extra arguments without breaking things
|
||||
*/
|
||||
struct RecursiveState {
|
||||
RecursiveState() {} // do not construct :)
|
||||
RecursiveState(
|
||||
Transform &_node_transform,
|
||||
Skeleton3D *_skeleton,
|
||||
Node3D *_new_node,
|
||||
String &_node_name,
|
||||
aiNode *_assimp_node,
|
||||
Node *_parent_node,
|
||||
aiBone *_bone) :
|
||||
node_transform(_node_transform),
|
||||
skeleton(_skeleton),
|
||||
new_node(_new_node),
|
||||
node_name(_node_name),
|
||||
assimp_node(_assimp_node),
|
||||
parent_node(_parent_node),
|
||||
bone(_bone) {}
|
||||
|
||||
Transform node_transform;
|
||||
Skeleton3D *skeleton = nullptr;
|
||||
Node3D *new_node = nullptr;
|
||||
String node_name;
|
||||
aiNode *assimp_node = nullptr;
|
||||
Node *parent_node = nullptr;
|
||||
aiBone *bone = nullptr;
|
||||
};
|
||||
} // namespace AssimpImporter
|
||||
|
||||
#endif // EDITOR_SCENE_IMPORT_STATE_H
|
|
@ -1,463 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* import_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_UTILS_IMPORTER_ASSIMP_H
|
||||
#define IMPORT_UTILS_IMPORTER_ASSIMP_H
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
#include "import_state.h"
|
||||
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/cexport.h>
|
||||
#include <assimp/cimport.h>
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <assimp/pbrmaterial.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/Logger.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace AssimpImporter;
|
||||
|
||||
#define AI_PROPERTIES aiTextureType_UNKNOWN, 0
|
||||
#define AI_NULL 0, 0
|
||||
#define AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR "$raw.Maya|baseColor"
|
||||
#define AI_MATKEY_FBX_MAYA_METALNESS_FACTOR "$raw.Maya|metalness"
|
||||
#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR "$raw.Maya|diffuseRoughness"
|
||||
|
||||
#define AI_MATKEY_FBX_MAYA_EMISSION_TEXTURE "$raw.Maya|emissionColor|file"
|
||||
#define AI_MATKEY_FBX_MAYA_EMISSIVE_FACTOR "$raw.Maya|emission"
|
||||
#define AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE "$raw.Maya|metalness|file"
|
||||
#define AI_MATKEY_FBX_MAYA_METALNESS_UV_XFORM "$raw.Maya|metalness|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE "$raw.Maya|diffuseRoughness|file"
|
||||
#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_UV_XFORM "$raw.Maya|diffuseRoughness|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE "$raw.Maya|baseColor|file"
|
||||
#define AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM "$raw.Maya|baseColor|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE "$raw.Maya|normalCamera|file"
|
||||
#define AI_MATKEY_FBX_MAYA_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo"
|
||||
|
||||
#define AI_MATKEY_FBX_NORMAL_TEXTURE "$raw.Maya|normalCamera|file"
|
||||
#define AI_MATKEY_FBX_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo"
|
||||
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_DISPLACEMENT_SCALING_FACTOR "$raw.Maya|displacementscaling"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR "$raw.Maya|base_color"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR "$raw.Maya|emissive"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR "$raw.Maya|metallic"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR "$raw.Maya|roughness"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR "$raw.Maya|emissive_intensity"
|
||||
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE "$raw.Maya|TEX_normal_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_UV_XFORM "$raw.Maya|TEX_normal_map|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE "$raw.Maya|TEX_color_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM "$raw.Maya|TEX_color_map|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE "$raw.Maya|TEX_metallic_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_UV_XFORM "$raw.Maya|TEX_metallic_map|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE "$raw.Maya|TEX_roughness_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_UV_XFORM "$raw.Maya|TEX_roughness_map|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE "$raw.Maya|TEX_emissive_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_UV_XFORM "$raw.Maya|TEX_emissive_map|uvtrafo"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_TEXTURE "$raw.Maya|TEX_ao_map|file"
|
||||
#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_UV_XFORM "$raw.Maya|TEX_ao_map|uvtrafo"
|
||||
|
||||
/**
|
||||
* Assimp Utils
|
||||
* Conversion tools / glue code to convert from assimp to godot
|
||||
*/
|
||||
class AssimpUtils {
|
||||
public:
|
||||
/**
|
||||
* calculate tangents for mesh data from assimp data
|
||||
*/
|
||||
static void calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, Color *w) {
|
||||
const aiVector3D normals = ai_mesh->mAnimMeshes[i]->mNormals[tri_index];
|
||||
const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
|
||||
const aiVector3D tangent = ai_mesh->mAnimMeshes[i]->mTangents[tri_index];
|
||||
const Vector3 godot_tangent = Vector3(tangent.x, tangent.y, tangent.z);
|
||||
const aiVector3D bitangent = ai_mesh->mAnimMeshes[i]->mBitangents[tri_index];
|
||||
const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
|
||||
float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
|
||||
Color plane_tangent = Color(tangent.x, tangent.y, tangent.z, d);
|
||||
w[index] = plane_tangent;
|
||||
}
|
||||
|
||||
struct AssetImportFbx {
|
||||
enum ETimeMode {
|
||||
TIME_MODE_DEFAULT = 0,
|
||||
TIME_MODE_120 = 1,
|
||||
TIME_MODE_100 = 2,
|
||||
TIME_MODE_60 = 3,
|
||||
TIME_MODE_50 = 4,
|
||||
TIME_MODE_48 = 5,
|
||||
TIME_MODE_30 = 6,
|
||||
TIME_MODE_30_DROP = 7,
|
||||
TIME_MODE_NTSC_DROP_FRAME = 8,
|
||||
TIME_MODE_NTSC_FULL_FRAME = 9,
|
||||
TIME_MODE_PAL = 10,
|
||||
TIME_MODE_CINEMA = 11,
|
||||
TIME_MODE_1000 = 12,
|
||||
TIME_MODE_CINEMA_ND = 13,
|
||||
TIME_MODE_CUSTOM = 14,
|
||||
TIME_MODE_TIME_MODE_COUNT = 15
|
||||
};
|
||||
enum UpAxis {
|
||||
UP_VECTOR_AXIS_X = 1,
|
||||
UP_VECTOR_AXIS_Y = 2,
|
||||
UP_VECTOR_AXIS_Z = 3
|
||||
};
|
||||
enum FrontAxis {
|
||||
FRONT_PARITY_EVEN = 1,
|
||||
FRONT_PARITY_ODD = 2,
|
||||
};
|
||||
|
||||
enum CoordAxis {
|
||||
COORD_RIGHT = 0,
|
||||
COORD_LEFT = 1
|
||||
};
|
||||
};
|
||||
|
||||
/** Get assimp string
|
||||
* automatically filters the string data
|
||||
*/
|
||||
static String get_assimp_string(const aiString &p_string) {
|
||||
//convert an assimp String to a Godot String
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
if (name.find(":") != -1) {
|
||||
String replaced_name = name.split(":")[1];
|
||||
print_verbose("Replacing " + name + " containing : with " + replaced_name);
|
||||
name = replaced_name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static String get_anim_string_from_assimp(const aiString &p_string) {
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
if (name.find(":") != -1) {
|
||||
String replaced_name = name.split(":")[1];
|
||||
print_verbose("Replacing " + name + " containing : with " + replaced_name);
|
||||
name = replaced_name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* No filter logic get_raw_string_from_assimp
|
||||
* This just convers the aiString to a parsed utf8 string
|
||||
* Without removing special chars etc
|
||||
*/
|
||||
static String get_raw_string_from_assimp(const aiString &p_string) {
|
||||
String name;
|
||||
name.parse_utf8(p_string.C_Str() /*,p_string.length*/);
|
||||
return name;
|
||||
}
|
||||
|
||||
static Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
||||
return Ref<Animation>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts aiMatrix4x4 to godot Transform
|
||||
*/
|
||||
static const Transform assimp_matrix_transform(const aiMatrix4x4 p_matrix) {
|
||||
aiMatrix4x4 matrix = p_matrix;
|
||||
Transform xform;
|
||||
xform.set(matrix.a1, matrix.a2, matrix.a3, matrix.b1, matrix.b2, matrix.b3, matrix.c1, matrix.c2, matrix.c3, matrix.a4, matrix.b4, matrix.c4);
|
||||
return xform;
|
||||
}
|
||||
|
||||
/** Get fbx fps for time mode meta data
|
||||
*/
|
||||
static float get_fbx_fps(int32_t time_mode, const aiScene *p_scene) {
|
||||
switch (time_mode) {
|
||||
case AssetImportFbx::TIME_MODE_DEFAULT:
|
||||
return 24; //hack
|
||||
case AssetImportFbx::TIME_MODE_120:
|
||||
return 120;
|
||||
case AssetImportFbx::TIME_MODE_100:
|
||||
return 100;
|
||||
case AssetImportFbx::TIME_MODE_60:
|
||||
return 60;
|
||||
case AssetImportFbx::TIME_MODE_50:
|
||||
return 50;
|
||||
case AssetImportFbx::TIME_MODE_48:
|
||||
return 48;
|
||||
case AssetImportFbx::TIME_MODE_30:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_30_DROP:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_PAL:
|
||||
return 25;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA:
|
||||
return 24;
|
||||
case AssetImportFbx::TIME_MODE_1000:
|
||||
return 1000;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA_ND:
|
||||
return 23.976f;
|
||||
case AssetImportFbx::TIME_MODE_CUSTOM:
|
||||
int32_t frame_rate = -1;
|
||||
p_scene->mMetaData->Get("FrameRate", frame_rate);
|
||||
return frame_rate;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global transform for the current node - so we can use world space rather than
|
||||
* local space coordinates
|
||||
* useful if you need global - although recommend using local wherever possible over global
|
||||
* as you could break fbx scaling :)
|
||||
*/
|
||||
static Transform _get_global_assimp_node_transform(const aiNode *p_current_node) {
|
||||
aiNode const *current_node = p_current_node;
|
||||
Transform xform;
|
||||
while (current_node != nullptr) {
|
||||
xform = assimp_matrix_transform(current_node->mTransformation) * xform;
|
||||
current_node = current_node->mParent;
|
||||
}
|
||||
return xform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find hardcoded textures from assimp which could be in many different directories
|
||||
*/
|
||||
static void find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension) {
|
||||
Vector<String> paths;
|
||||
paths.push_back(path.get_basename() + extension);
|
||||
paths.push_back(path + extension);
|
||||
paths.push_back(path);
|
||||
paths.push_back(p_path.get_base_dir().plus_file(path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file(path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file(path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("textures/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Textures/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Textures/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../textures/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("texture/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("Texture/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../Texture/" + path.get_file()));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file().get_basename() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file() + extension));
|
||||
paths.push_back(p_path.get_base_dir().plus_file("../texture/" + path.get_file()));
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
if (dir.file_exists(paths[i])) {
|
||||
found = true;
|
||||
path = paths[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** find the texture path for the supplied fbx path inside godot
|
||||
* very simple lookup for subfolders etc for a texture which may or may not be in a directory
|
||||
*/
|
||||
static void find_texture_path(const String &r_p_path, String &r_path, bool &r_found) {
|
||||
_Directory dir;
|
||||
|
||||
List<String> exts;
|
||||
ImageLoader::get_recognized_extensions(&exts);
|
||||
|
||||
Vector<String> split_path = r_path.get_basename().split("*");
|
||||
if (split_path.size() == 2) {
|
||||
r_found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir.file_exists(r_p_path.get_base_dir() + r_path.get_file())) {
|
||||
r_path = r_p_path.get_base_dir() + r_path.get_file();
|
||||
r_found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < exts.size(); i++) {
|
||||
if (r_found) {
|
||||
return;
|
||||
}
|
||||
find_texture_path(r_p_path, dir, r_path, r_found, "." + exts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set_texture_mapping_mode
|
||||
* Helper to check the mapping mode of the texture (repeat, clamp and mirror)
|
||||
*/
|
||||
static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
|
||||
ERR_FAIL_COND(texture.is_null());
|
||||
ERR_FAIL_COND(map_mode == nullptr);
|
||||
// FIXME: Commented out during Vulkan port.
|
||||
/*
|
||||
aiTextureMapMode tex_mode = map_mode[0];
|
||||
|
||||
int32_t flags = Texture2D::FLAGS_DEFAULT;
|
||||
if (tex_mode == aiTextureMapMode_Wrap) {
|
||||
//Default
|
||||
} else if (tex_mode == aiTextureMapMode_Clamp) {
|
||||
flags = flags & ~Texture2D::FLAG_REPEAT;
|
||||
} else if (tex_mode == aiTextureMapMode_Mirror) {
|
||||
flags = flags | Texture2D::FLAG_MIRRORED_REPEAT;
|
||||
}
|
||||
texture->set_flags(flags);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Load or load from cache image :)
|
||||
*/
|
||||
static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path) {
|
||||
Map<String, Ref<Image>>::Element *match = state.path_to_image_cache.find(p_path);
|
||||
|
||||
// if our cache contains this image then don't bother
|
||||
if (match) {
|
||||
return match->get();
|
||||
}
|
||||
|
||||
Vector<String> split_path = p_path.get_basename().split("*");
|
||||
if (split_path.size() == 2) {
|
||||
size_t texture_idx = split_path[1].to_int();
|
||||
ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
|
||||
aiTexture *tex = p_scene->mTextures[texture_idx];
|
||||
String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
|
||||
filename = filename.get_file();
|
||||
print_verbose("Open Asset Import: Loading embedded texture " + filename);
|
||||
if (tex->mHeight == 0) {
|
||||
if (tex->CheckFormat("png")) {
|
||||
ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, Ref<Image>());
|
||||
Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, img);
|
||||
return img;
|
||||
} else if (tex->CheckFormat("jpg")) {
|
||||
ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, Ref<Image>());
|
||||
Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, img);
|
||||
return img;
|
||||
} else if (tex->CheckFormat("dds")) {
|
||||
ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
|
||||
}
|
||||
} else {
|
||||
Ref<Image> img;
|
||||
img.instance();
|
||||
PackedByteArray arr;
|
||||
uint32_t size = tex->mWidth * tex->mHeight;
|
||||
arr.resize(size);
|
||||
memcpy(arr.ptrw(), tex->pcData, size);
|
||||
ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
|
||||
//ARGB8888 to RGBA8888
|
||||
for (int32_t i = 0; i < arr.size() / 4; i++) {
|
||||
arr.ptrw()[(4 * i) + 3] = arr[(4 * i) + 0];
|
||||
arr.ptrw()[(4 * i) + 0] = arr[(4 * i) + 1];
|
||||
arr.ptrw()[(4 * i) + 1] = arr[(4 * i) + 2];
|
||||
arr.ptrw()[(4 * i) + 2] = arr[(4 * i) + 3];
|
||||
}
|
||||
img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
|
||||
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, img);
|
||||
return img;
|
||||
}
|
||||
return Ref<Image>();
|
||||
} else {
|
||||
Ref<Texture2D> texture = ResourceLoader::load(p_path);
|
||||
ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
|
||||
Ref<Image> image = texture->get_data();
|
||||
ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
|
||||
state.path_to_image_cache.insert(p_path, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
return Ref<Image>();
|
||||
}
|
||||
|
||||
/* create texture from assimp data, if found in path */
|
||||
static bool CreateAssimpTexture(
|
||||
AssimpImporter::ImportState &state,
|
||||
aiString texture_path,
|
||||
String &filename,
|
||||
String &path,
|
||||
AssimpImageData &image_state) {
|
||||
filename = get_raw_string_from_assimp(texture_path);
|
||||
path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
|
||||
bool found = false;
|
||||
find_texture_path(state.path, path, found);
|
||||
if (found) {
|
||||
image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
|
||||
if (image_state.raw_image.is_valid()) {
|
||||
image_state.texture.instance();
|
||||
image_state.texture->create_from_image(image_state.raw_image);
|
||||
// FIXME: Commented out during Vulkan port.
|
||||
//image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/** GetAssimpTexture
|
||||
* Designed to retrieve textures for you
|
||||
*/
|
||||
static bool GetAssimpTexture(
|
||||
AssimpImporter::ImportState &state,
|
||||
aiMaterial *ai_material,
|
||||
aiTextureType texture_type,
|
||||
String &filename,
|
||||
String &path,
|
||||
AssimpImageData &image_state) {
|
||||
aiString ai_filename = aiString();
|
||||
if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
|
||||
return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IMPORT_UTILS_IMPORTER_ASSIMP_H
|
|
@ -1,58 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor_scene_importer_assimp.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _editor_init() {
|
||||
Ref<EditorSceneImporterAssimp> import_assimp;
|
||||
import_assimp.instance();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_assimp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_assimp_types() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
ClassDB::register_class<EditorSceneImporterAssimp>();
|
||||
|
||||
ClassDB::set_current_api(prev_api);
|
||||
|
||||
EditorNode::add_init_callback(_editor_init);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_assimp_types() {
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ASSIMP_REGISTER_TYPES_H
|
||||
#define ASSIMP_REGISTER_TYPES_H
|
||||
|
||||
void register_assimp_types();
|
||||
void unregister_assimp_types();
|
||||
|
||||
#endif // ASSIMP_REGISTER_TYPES_H
|
|
@ -6,24 +6,6 @@ readability.
|
|||
Subcategories (`###` level) where needed are separated by a single empty line.
|
||||
|
||||
|
||||
## assimp
|
||||
|
||||
- Upstream: http://github.com/assimp/assimp
|
||||
- Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- Run `cmake .` in root folder to generate files
|
||||
- `code/{CApi,Common,FBX,Material,PostProcessing}/`
|
||||
- `contrib/utf8cpp/source/`
|
||||
- `include/`
|
||||
- `revision.h`
|
||||
- `CREDITS` and `LICENSE` files
|
||||
- `rm -f code/Common/ZipArchiveIOSystem.cpp include/assimp/ZipArchiveIOSystem.h
|
||||
include/assimp/irrXMLWrapper.h`
|
||||
|
||||
|
||||
## basis_universal
|
||||
|
||||
- Upstream: https://github.com/BinomialLLC/basis_universal
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
===============================================================
|
||||
Open Asset Import Library (Assimp)
|
||||
Developers and Contributors
|
||||
===============================================================
|
||||
|
||||
The following is a non-exhaustive list of all constributors over the years.
|
||||
If you think your name should be listed here, drop us a line and we'll add you.
|
||||
|
||||
- Alexander Gessler,
|
||||
3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
|
||||
|
||||
- Thomas Schulze,
|
||||
X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
|
||||
|
||||
- Kim Kulling,
|
||||
Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
|
||||
|
||||
- R.Schmidt,
|
||||
Linux build, eclipse support.
|
||||
|
||||
- Matthias Gubisch,
|
||||
Assimp.net
|
||||
Visual Studio 9 support, bugfixes.
|
||||
|
||||
- Mark Sibly
|
||||
B3D-Loader, Assimp testing
|
||||
|
||||
- Jonathan Klein
|
||||
Ogre Loader, VC2010 fixes and CMake fixes.
|
||||
|
||||
- Sebastian Hempel,
|
||||
PyAssimp (first version)
|
||||
Compile-Bugfixes for mingw, add environment for static library support in make.
|
||||
|
||||
- Jonathan Pokrass
|
||||
Supplied a bugfix concerning the scaling in the md3 loader.
|
||||
|
||||
- Andrew Galante,
|
||||
Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
|
||||
|
||||
- Andreas Nagel
|
||||
First Assimp testing & verification under Windows Vista 64 Bit.
|
||||
|
||||
- Marius Schr<68>der
|
||||
Allowed us to use many of his models for screenshots and testing.
|
||||
|
||||
- Christian Schubert
|
||||
Supplied various XFiles for testing purposes.
|
||||
|
||||
- Tizian Wieland
|
||||
Searched the web for hundreds of test models for internal use
|
||||
|
||||
- John Connors
|
||||
Supplied patches for linux and SCons.
|
||||
|
||||
- T. R.
|
||||
The GUY who performed some of the CSM mocaps.
|
||||
|
||||
- Andy Maloney
|
||||
Contributed fixes for the documentation and the doxygen markup
|
||||
|
||||
- Zhao Lei
|
||||
Contributed several bugfixes fixing memory leaks and improving float parsing
|
||||
|
||||
- sueastside
|
||||
Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
|
||||
|
||||
- Tobias Rittig
|
||||
Collada testing with Cinema 4D
|
||||
|
||||
- Brad Grantham
|
||||
Improvements in OpenGL-Sample.
|
||||
|
||||
- Robert Ramirez
|
||||
Add group loading feature to Obj-Loader.
|
||||
|
||||
- Chris Maiwald
|
||||
Many bugreports, improving Assimp's portability, regular testing & feedback.
|
||||
|
||||
- Stepan Hrbek
|
||||
Bugreport and fix for a obj-materialloader crash.
|
||||
|
||||
- David Nadlinger
|
||||
D bindings, CMake install support.
|
||||
|
||||
- Dario Accornero
|
||||
Contributed several patches regarding Mac OS/XCode targets, bug reports.
|
||||
|
||||
- Martin Walser (Samhayne)
|
||||
Contributed the 'SimpleTexturedOpenGl' sample.
|
||||
|
||||
- Matthias Fauconneau
|
||||
Contributed a fix for the Q3-BSP loader.
|
||||
|
||||
- Jørgen P. Tjernø
|
||||
Contributed updated and improved xcode workspaces
|
||||
|
||||
- drparallax
|
||||
Contributed the /samples/SimpleAssimpViewX sample
|
||||
|
||||
- Carsten Fuchs
|
||||
Contributed a fix for the Normalize method in aiQuaternion.
|
||||
|
||||
- dbburgess
|
||||
Contributes a Android-specific build issue: log the hardware architecture for ARM.
|
||||
|
||||
- alfiereinre7
|
||||
Contributes a obj-fileparser fix: missing tokens in the obj-token list.
|
||||
|
||||
- Roman Kharitonov
|
||||
Contributes a fix for the configure script environment.
|
||||
|
||||
- Ed Diana
|
||||
Contributed AssimpDelphi (/port/AssimpDelphi).
|
||||
|
||||
- rdb
|
||||
Contributes a bundle of fixes and improvements for the bsp-importer.
|
||||
|
||||
- Mick P
|
||||
For contributing the De-bone postprocessing step and filing various bug reports.
|
||||
|
||||
- Rosen Diankov
|
||||
Contributed patches to build assimp debian packages using cmake.
|
||||
|
||||
- Mark Page
|
||||
Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
|
||||
|
||||
- IOhannes
|
||||
Contributed the Debian build fixes ( architecture macro ).
|
||||
|
||||
- gellule
|
||||
Several LWO and LWS fixes (pivoting).
|
||||
|
||||
- Marcel Metz
|
||||
GCC/Linux fixes for the SimpleOpenGL sample.
|
||||
|
||||
- Brian Miller
|
||||
Bugfix for a compiler fix for iOS on arm.
|
||||
|
||||
- Séverin Lemaignan
|
||||
Rewrite of PyAssimp, distutils and Python3 support
|
||||
|
||||
- albert-wang
|
||||
Bugfixes for the collada parser
|
||||
|
||||
- Ya ping Jin
|
||||
Bugfixes for uv-tanget calculation.
|
||||
|
||||
- Jonne Nauha
|
||||
Ogre Binary format support
|
||||
|
||||
- Filip Wasil, Tieto Poland Sp. z o.o.
|
||||
Android JNI asset extraction support
|
||||
|
||||
- Richard Steffen
|
||||
Contributed ExportProperties interface
|
||||
Contributed X File exporter
|
||||
Contributed Step (stp) exporter
|
||||
|
||||
- Thomas Iorns (mesilliac)
|
||||
Initial FBX Export support
|
||||
|
||||
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
||||
|
||||
|
||||
========
|
||||
Patreons
|
||||
========
|
||||
|
||||
Huge thanks to our Patreons!
|
||||
|
||||
- migenius
|
||||
- Marcus
|
||||
- Cort
|
||||
- elect
|
||||
- Steffen
|
||||
|
||||
|
||||
===================
|
||||
Commercial Sponsors
|
||||
===================
|
||||
|
||||
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
|
|
@ -1,78 +0,0 @@
|
|||
Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2016, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
******************************************************************************
|
||||
|
||||
AN EXCEPTION applies to all files in the ./test/models-nonbsd folder.
|
||||
These are 3d models for testing purposes, from various free sources
|
||||
on the internet. They are - unless otherwise stated - copyright of
|
||||
their respective creators, which may impose additional requirements
|
||||
on the use of their work. For any of these models, see
|
||||
<model-name>.source.txt for more legal information. Contact us if you
|
||||
are a copyright holder and believe that we credited you inproperly or
|
||||
if you don't want your files to appear in the repository.
|
||||
|
||||
|
||||
******************************************************************************
|
||||
|
||||
Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
http://code.google.com/p/poly2tri/
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
|
@ -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 %%%");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,102 +0,0 @@
|
|||
// Definitions for the Interchange File Format (IFF)
|
||||
// Alexander Gessler, 2006
|
||||
// Adapted to Assimp August 2008
|
||||
|
||||
#ifndef AI_IFF_H_INCLUDED
|
||||
#define AI_IFF_H_INCLUDED
|
||||
|
||||
#include <assimp/ByteSwapper.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace IFF {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct ChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct SubChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
|
||||
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
|
||||
((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
|
||||
|
||||
|
||||
#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Copy of the chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline ChunkHeader LoadChunk(uint8_t*& outFile)
|
||||
{
|
||||
ChunkHeader head;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 4);
|
||||
outFile += 4;
|
||||
AI_LSWAP4(head.length);
|
||||
AI_LSWAP4(head.type);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a sub chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Copy of the sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
|
||||
{
|
||||
SubChunkHeader head;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 2);
|
||||
outFile += 2;
|
||||
AI_LSWAP2(head.length);
|
||||
AI_LSWAP4(head.type);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Read the file header and return the type of the file and its size
|
||||
//! @param outFile Pointer to the file data. The buffer must at
|
||||
//! least be 12 bytes large.
|
||||
//! @param fileType Receives the type of the file
|
||||
//! @return 0 if everything was OK, otherwise an error message
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType)
|
||||
{
|
||||
ChunkHeader head = LoadChunk(outFile);
|
||||
if(AI_IFF_FOURCC_FORM != head.type)
|
||||
{
|
||||
return "The file is not an IFF file: FORM chunk is missing";
|
||||
}
|
||||
::memcpy(&fileType, outFile, 4);
|
||||
AI_LSWAP4(fileType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif // !! AI_IFF_H_INCLUDED
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Implementation of the helper class to quickly find
|
||||
vertices close to a given position. Special implementation for
|
||||
the 3ds loader handling smooth groups correctly */
|
||||
|
||||
#include <assimp/SGSpatialSort.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SGSpatialSort::SGSpatialSort()
|
||||
{
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SGSpatialSort::~SGSpatialSort()
|
||||
{
|
||||
// nothing to do here, everything destructs automatically
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index,
|
||||
unsigned int smoothingGroup)
|
||||
{
|
||||
// store position by index and distance
|
||||
float distance = vPosition * mPlaneNormal;
|
||||
mPositions.push_back( Entry( index, vPosition,
|
||||
distance, smoothingGroup));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Prepare()
|
||||
{
|
||||
// now sort the array ascending by distance.
|
||||
std::sort( this->mPositions.begin(), this->mPositions.end());
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults,
|
||||
bool exactMatch /*= false*/) const
|
||||
{
|
||||
float dist = pPosition * mPlaneNormal;
|
||||
float minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
|
||||
// clear the array
|
||||
poResults.clear();
|
||||
|
||||
// quick check for positions outside the range
|
||||
if( mPositions.empty() )
|
||||
return;
|
||||
if( maxDist < mPositions.front().mDistance)
|
||||
return;
|
||||
if( minDist > mPositions.back().mDistance)
|
||||
return;
|
||||
|
||||
// do a binary search for the minimal distance to start the iteration there
|
||||
unsigned int index = (unsigned int)mPositions.size() / 2;
|
||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||
while( binaryStepSize > 1)
|
||||
{
|
||||
if( mPositions[index].mDistance < minDist)
|
||||
index += binaryStepSize;
|
||||
else
|
||||
index -= binaryStepSize;
|
||||
|
||||
binaryStepSize /= 2;
|
||||
}
|
||||
|
||||
// depending on the direction of the last step we need to single step a bit back or forth
|
||||
// to find the actual beginning element of the range
|
||||
while( index > 0 && mPositions[index].mDistance > minDist)
|
||||
index--;
|
||||
while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
|
||||
index++;
|
||||
|
||||
// Mow start iterating from there until the first position lays outside of the distance range.
|
||||
// Add all positions inside the distance range within the given radius to the result aray
|
||||
|
||||
float squareEpsilon = pRadius * pRadius;
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
std::vector<Entry>::const_iterator end = mPositions.end();
|
||||
|
||||
if (exactMatch)
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG)
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it )break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the given smoothing group is 0, we'll return all surrounding vertices
|
||||
if (!pSG)
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
|
||||
poResults.push_back( it->mIndex);
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
}
|
||||
else while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || !it->mSmoothGroups))
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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. );
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <assimp/defs.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// @brief Checks if the platform supports SSE2 optimization
|
||||
/// @return true, if SSE2 is supported. false if SSE2 is not supported.
|
||||
bool ASSIMP_API CPUSupportsSSE2();
|
||||
|
||||
} // Namespace Assimp
|
|
@ -1,305 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXAnimation.cpp
|
||||
* @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
|
||||
* Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
|
||||
: Object(id, element, name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
|
||||
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
|
||||
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
|
||||
if(keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
|
||||
}
|
||||
|
||||
// check if the key times are well-ordered
|
||||
if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
|
||||
DOMError("the keyframes are not in ascending order",&KeyTime);
|
||||
}
|
||||
|
||||
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
|
||||
if(KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, *KeyAttrDataFloat);
|
||||
}
|
||||
|
||||
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
|
||||
if(KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, *KeyAttrFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::~AnimationCurve()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name,
|
||||
const Document& doc, const char* const * target_prop_whitelist /*= NULL*/,
|
||||
size_t whitelist_size /*= 0*/)
|
||||
: Object(id, element, name)
|
||||
, target()
|
||||
, doc(doc)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// find target node
|
||||
const char* whitelist[] = {"Model","NodeAttribute","Deformer"};
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3);
|
||||
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(target_prop_whitelist) {
|
||||
const char* const s = con->PropertyName().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
throw std::range_error("AnimationCurveNode target property is not in whitelist");
|
||||
}
|
||||
}
|
||||
|
||||
const Object* const ob = con->DestinationObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX support constraints as DOM class
|
||||
//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
|
||||
target = ob;
|
||||
if(!target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
|
||||
if(!target) {
|
||||
DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::~AnimationCurveNode()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveMap& AnimationCurveNode::Curves() const
|
||||
{
|
||||
if ( curves.empty() ) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
|
||||
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
curves[con->PropertyName()] = anim;
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element, name)
|
||||
, doc(doc)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// note: the props table here bears little importance and is usually absent
|
||||
props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::~AnimationLayer()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
|
||||
size_t whitelist_size /*= 0*/) const
|
||||
{
|
||||
AnimationCurveNodeList nodes;
|
||||
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(target_prop_whitelist) {
|
||||
const char* s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
|
||||
return nodes; // pray for NRVO
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element, name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
|
||||
props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
|
||||
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
|
||||
continue;
|
||||
}
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::~AnimationStack()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
} //!FBX
|
||||
} //!Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_FBX_IMPORTER
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
/** @file FBXBinaryTokenizer.cpp
|
||||
* @brief Implementation of a fake lexer for binary fbx files -
|
||||
* we emit tokens so the parser needs almost no special handling
|
||||
* for binary files.
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXUtil.h"
|
||||
#include <assimp/defs.h>
|
||||
#include <stdint.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/ByteSwapper.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
//enum Flag
|
||||
//{
|
||||
// e_unknown_0 = 1 << 0,
|
||||
// e_unknown_1 = 1 << 1,
|
||||
// e_unknown_2 = 1 << 2,
|
||||
// e_unknown_3 = 1 << 3,
|
||||
// e_unknown_4 = 1 << 4,
|
||||
// e_unknown_5 = 1 << 5,
|
||||
// e_unknown_6 = 1 << 6,
|
||||
// e_unknown_7 = 1 << 7,
|
||||
// e_unknown_8 = 1 << 8,
|
||||
// e_unknown_9 = 1 << 9,
|
||||
// e_unknown_10 = 1 << 10,
|
||||
// e_unknown_11 = 1 << 11,
|
||||
// e_unknown_12 = 1 << 12,
|
||||
// e_unknown_13 = 1 << 13,
|
||||
// e_unknown_14 = 1 << 14,
|
||||
// e_unknown_15 = 1 << 15,
|
||||
// e_unknown_16 = 1 << 16,
|
||||
// e_unknown_17 = 1 << 17,
|
||||
// e_unknown_18 = 1 << 18,
|
||||
// e_unknown_19 = 1 << 19,
|
||||
// e_unknown_20 = 1 << 20,
|
||||
// e_unknown_21 = 1 << 21,
|
||||
// e_unknown_22 = 1 << 22,
|
||||
// e_unknown_23 = 1 << 23,
|
||||
// e_flag_field_size_64_bit = 1 << 24, // Not sure what is
|
||||
// e_unknown_25 = 1 << 25,
|
||||
// e_unknown_26 = 1 << 26,
|
||||
// e_unknown_27 = 1 << 27,
|
||||
// e_unknown_28 = 1 << 28,
|
||||
// e_unknown_29 = 1 << 29,
|
||||
// e_unknown_30 = 1 << 30,
|
||||
// e_unknown_31 = 1 << 31
|
||||
//};
|
||||
//
|
||||
//bool check_flag(uint32_t flags, Flag to_check)
|
||||
//{
|
||||
// return (flags & to_check) != 0;
|
||||
//}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset)
|
||||
:
|
||||
#ifdef DEBUG
|
||||
contents(sbegin, static_cast<size_t>(send-sbegin)),
|
||||
#endif
|
||||
sbegin(sbegin)
|
||||
, send(send)
|
||||
, type(type)
|
||||
, line(offset)
|
||||
, column(BINARY_MARKER)
|
||||
{
|
||||
ai_assert(sbegin);
|
||||
ai_assert(send);
|
||||
|
||||
// binary tokens may have zero length because they are sometimes dummies
|
||||
// inserted by TokenizeBinary()
|
||||
ai_assert(send >= sbegin);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
|
||||
{
|
||||
throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Offset(const char* begin, const char* cursor) {
|
||||
ai_assert(begin <= cursor);
|
||||
|
||||
return cursor - begin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t ReadWord(const char* input, const char*& cursor, const char* end) {
|
||||
const size_t k_to_read = sizeof( uint32_t );
|
||||
if(Offset(cursor, end) < k_to_read ) {
|
||||
TokenizeError("cannot ReadWord, out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
uint32_t word;
|
||||
::memcpy(&word, cursor, 4);
|
||||
AI_SWAP4(word);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) {
|
||||
const size_t k_to_read = sizeof(uint64_t);
|
||||
if(Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
|
||||
::memcpy( &dword, cursor, sizeof( uint64_t ) );
|
||||
AI_SWAP8(dword);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return dword;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
|
||||
if(Offset(cursor, end) < sizeof( uint8_t ) ) {
|
||||
TokenizeError("cannot ReadByte, out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
|
||||
::memcpy( &word, cursor, sizeof( uint8_t ) );
|
||||
++cursor;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input,
|
||||
const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if(Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
|
||||
}
|
||||
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
|
||||
send_out = cursor;
|
||||
|
||||
if(!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if(sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
|
||||
if(Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
|
||||
}
|
||||
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall through
|
||||
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
|
||||
// raw binary data
|
||||
case 'R':
|
||||
{
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i':
|
||||
case 'c': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
|
||||
// compute length based on type and check against the stored value
|
||||
if(encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch(type)
|
||||
{
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
stride = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
ai_assert(false);
|
||||
};
|
||||
ai_assert(stride > 0);
|
||||
if(length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding",input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
}
|
||||
|
||||
// string
|
||||
case 'S': {
|
||||
const char* sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
|
||||
if(cursor > end) {
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits)
|
||||
{
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if(!end_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range",input, cursor);
|
||||
}
|
||||
else if(end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range",input, cursor);
|
||||
}
|
||||
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// the third data word contains the length of the property list
|
||||
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// now comes the name of the scope/key
|
||||
const char* sbeg, *send;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
|
||||
|
||||
// now come the individual properties
|
||||
const char* begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
|
||||
|
||||
if(i != prop_count-1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
|
||||
const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1);
|
||||
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
if (end_offset - Offset(input, cursor) < sentinel_block_length) {
|
||||
TokenizeError("insufficient padding bytes at block end",input, cursor);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while(Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
|
||||
if(cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
|
||||
}
|
||||
}
|
||||
cursor += sentinel_block_length;
|
||||
}
|
||||
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||
{
|
||||
ai_assert(input);
|
||||
|
||||
if(length < 0x1b) {
|
||||
TokenizeError("file is too short",0);
|
||||
}
|
||||
|
||||
//uint32_t offset = 0x15;
|
||||
/* const char* cursor = input + 0x15;
|
||||
|
||||
const uint32_t flags = ReadWord(input, cursor, input + length);
|
||||
|
||||
const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
|
||||
const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/
|
||||
|
||||
if (strncmp(input,"Kaydara FBX Binary",18)) {
|
||||
TokenizeError("magic bytes not found",0);
|
||||
}
|
||||
|
||||
const char* cursor = input + 18;
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
const uint32_t version = ReadWord(input, cursor, input + length);
|
||||
const bool is64bits = version >= 7500;
|
||||
const char *end = input + length;
|
||||
while (cursor < end ) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXCommon.h
|
||||
* Some useful constants and enums for dealing with FBX files.
|
||||
*/
|
||||
#ifndef AI_FBXCOMMON_H_INC
|
||||
#define AI_FBXCOMMON_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX
|
||||
{
|
||||
const std::string NULL_RECORD = { // 13 null bytes
|
||||
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
|
||||
}; // who knows why
|
||||
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
|
||||
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||
|
||||
// rotation order. We'll probably use EulerXYZ for everything
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0,
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
|
||||
RotOrder_SphericXYZ,
|
||||
|
||||
RotOrder_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
// transformation inheritance method. Most of the time RSrs
|
||||
enum TransformInheritance {
|
||||
TransformInheritance_RrSs = 0,
|
||||
TransformInheritance_RSrs,
|
||||
TransformInheritance_Rrs,
|
||||
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#endif // AI_FBXCOMMON_H_INC
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXCompileConfig.h
|
||||
* @brief FBX importer compile-time switches
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_COMPILECONFIG_H
|
||||
#define INCLUDED_AI_FBX_COMPILECONFIG_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//
|
||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||
# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
# define fbx_unordered_set set
|
||||
# define fbx_unordered_multiset multiset
|
||||
#endif
|
||||
|
||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# define fbx_unordered_set unordered_set
|
||||
# define fbx_unordered_multiset unordered_multiset
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# define fbx_unordered_set tr1::unordered_set
|
||||
# define fbx_unordered_multiset tr1::unordered_multiset
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // INCLUDED_AI_FBX_COMPILECONFIG_H
|
File diff suppressed because it is too large
Load Diff
|
@ -1,491 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDConverter.h
|
||||
* @brief FBX DOM to aiScene conversion
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_CONVERTER_H
|
||||
#define INCLUDED_AI_FBX_CONVERTER_H
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXImporter.h"
|
||||
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/light.h>
|
||||
#include <assimp/texture.h>
|
||||
#include <assimp/camera.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
|
||||
struct morphKeyData {
|
||||
std::vector<unsigned int> values;
|
||||
std::vector<float> weights;
|
||||
};
|
||||
typedef std::map<int64_t, morphKeyData*> morphAnimData;
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
class Document;
|
||||
/**
|
||||
* Convert a FBX #Document to #aiScene
|
||||
* @param out Empty scene to be populated
|
||||
* @param doc Parsed FBX document
|
||||
* @param removeEmptyBones Will remove bones, which do not have any references to vertices.
|
||||
*/
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones);
|
||||
|
||||
/** Dummy class to encapsulate the conversion process */
|
||||
class FBXConverter {
|
||||
public:
|
||||
/**
|
||||
* The different parts that make up the final local transformation of a fbx-node
|
||||
*/
|
||||
enum TransformationComp {
|
||||
TransformationComp_GeometricScalingInverse = 0,
|
||||
TransformationComp_GeometricRotationInverse,
|
||||
TransformationComp_GeometricTranslationInverse,
|
||||
TransformationComp_Translation,
|
||||
TransformationComp_RotationOffset,
|
||||
TransformationComp_RotationPivot,
|
||||
TransformationComp_PreRotation,
|
||||
TransformationComp_Rotation,
|
||||
TransformationComp_PostRotation,
|
||||
TransformationComp_RotationPivotInverse,
|
||||
TransformationComp_ScalingOffset,
|
||||
TransformationComp_ScalingPivot,
|
||||
TransformationComp_Scaling,
|
||||
TransformationComp_ScalingPivotInverse,
|
||||
TransformationComp_GeometricTranslation,
|
||||
TransformationComp_GeometricRotation,
|
||||
TransformationComp_GeometricScaling,
|
||||
|
||||
TransformationComp_MAXIMUM
|
||||
};
|
||||
|
||||
public:
|
||||
FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones);
|
||||
~FBXConverter();
|
||||
|
||||
private:
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// find scene root and trigger recursive scene conversion
|
||||
void ConvertRootNode();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// collect and assign child nodes
|
||||
void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertLights(const Model& model, const std::string &orig_name );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertCameras(const Model& model, const std::string &orig_name );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertLight( const Light& light, const std::string &orig_name );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertCamera( const Camera& cam, const std::string &orig_name );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GetUniqueName( const std::string &name, std::string& uniqueName );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// this returns unified names usable within assimp identifiers (i.e. no space characters -
|
||||
// while these would be allowed, they are a potential trouble spot so better not use them).
|
||||
const char* NameTransformationComp(TransformationComp comp);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and
|
||||
// then makes this name unique
|
||||
std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// note: this returns the REAL fbx property names
|
||||
const char* NameTransformationCompProperty(TransformationComp comp);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiVector3D TransformationCompDefaultValue(TransformationComp comp);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out);
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* checks if a node has more than just scaling, rotation and translation components
|
||||
*/
|
||||
bool NeedsComplexTransformationChain(const Model& model);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// note: name must be a FixNodeName() result
|
||||
std::string NameTransformationChainNode(const std::string& name, TransformationComp comp);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* note: memory for output_nodes will be managed by the caller
|
||||
*/
|
||||
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
||||
std::vector<unsigned int>
|
||||
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model,
|
||||
aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||
aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int>
|
||||
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
|
||||
aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
|
||||
static_cast<unsigned int>(-1);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* - if materialIndex == NO_MATERIAL_SEPARATION, materials are not taken into
|
||||
* account when determining which weights to include.
|
||||
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
||||
* each output vertex the DOM index it maps to.
|
||||
*/
|
||||
void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent = NULL, aiNode *root_node = NULL,
|
||||
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||
std::vector<unsigned int> *outputVertStartIndices = NULL);
|
||||
// lookup
|
||||
static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
MatIndexArray::value_type materialIndex);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int GetDefaultMaterial();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Material -> aiMaterial
|
||||
unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Video -> aiTexture
|
||||
unsigned int ConvertVideo(const Video& video);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// convert embedded texture if necessary and return actual texture path
|
||||
aiString GetTexturePath(const Texture* tex);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
||||
const std::string& propName,
|
||||
aiTextureType target, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
|
||||
const std::string& propName,
|
||||
aiTextureType target, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName,
|
||||
bool& result);
|
||||
aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName,
|
||||
const std::string& factorName, bool& result, bool useTemplate = true);
|
||||
aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName,
|
||||
bool& result, bool useTemplate = true);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props);
|
||||
void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// get the number of fps for a FrameRate enumerated value
|
||||
static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// convert animation data to aiAnimation et al
|
||||
void ConvertAnimations();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// takes a fbx node name and returns the identifier to be used in the assimp output scene.
|
||||
// the function is guaranteed to provide consistent results over multiple invocations
|
||||
// UNLESS RenameNode() is called for a particular node name.
|
||||
std::string FixNodeName(const std::string& name);
|
||||
std::string FixAnimMeshName(const std::string& name);
|
||||
|
||||
typedef std::map<const AnimationCurveNode*, const AnimationLayer*> LayerMap;
|
||||
|
||||
// XXX: better use multi_map ..
|
||||
typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertAnimationStack(const AnimationStack& st);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
|
||||
const std::string& fixed_name,
|
||||
const std::vector<const AnimationCurveNode*>& curves,
|
||||
const LayerMap& layer_map,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsRedundantAnimationData(const Model& target,
|
||||
TransformationComp comp,
|
||||
const std::vector<const AnimationCurveNode*>& curves);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNodeAnim* GenerateRotationNodeAnim(const std::string& name,
|
||||
const Model& target,
|
||||
const std::vector<const AnimationCurveNode*>& curves,
|
||||
const LayerMap& layer_map,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNodeAnim* GenerateScalingNodeAnim(const std::string& name,
|
||||
const Model& /*target*/,
|
||||
const std::vector<const AnimationCurveNode*>& curves,
|
||||
const LayerMap& layer_map,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name,
|
||||
const Model& /*target*/,
|
||||
const std::vector<const AnimationCurveNode*>& curves,
|
||||
const LayerMap& layer_map,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time,
|
||||
bool inverse = false);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// generate node anim, extracting only Rotation, Scaling and Translation from the given chain
|
||||
aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name,
|
||||
const Model& target,
|
||||
NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
|
||||
NodeMap::const_iterator iter_end,
|
||||
const LayerMap& layer_map,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time,
|
||||
bool reverse_order = false);
|
||||
|
||||
// key (time), value, mapto (component index)
|
||||
typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList;
|
||||
typedef std::vector<KeyFrameList> KeyFrameListList;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
|
||||
const aiVector3D& def_value,
|
||||
double& max_time,
|
||||
double& min_time);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
|
||||
const aiVector3D& def_value,
|
||||
double& maxTime,
|
||||
double& minTime,
|
||||
Model::RotOrder order);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale,
|
||||
aiVectorKey* out_translation,
|
||||
const KeyFrameListList& scaling,
|
||||
const KeyFrameListList& translation,
|
||||
const KeyFrameListList& rotation,
|
||||
const KeyTimeList& times,
|
||||
double& maxTime,
|
||||
double& minTime,
|
||||
Model::RotOrder order,
|
||||
const aiVector3D& def_scale,
|
||||
const aiVector3D& def_translate,
|
||||
const aiVector3D& def_rotation);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// euler xyz -> quat
|
||||
aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
|
||||
int64_t start, int64_t stop,
|
||||
double& maxTime,
|
||||
double& minTime);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
||||
const LayerMap& /*layers*/,
|
||||
int64_t start, int64_t stop,
|
||||
double& maxTime,
|
||||
double& minTime);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
||||
const LayerMap& /*layers*/,
|
||||
int64_t start, int64_t stop,
|
||||
double& maxTime,
|
||||
double& minTime,
|
||||
Model::RotOrder order);
|
||||
|
||||
void ConvertGlobalSettings();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
||||
void TransferDataToScene();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// FBX file could have embedded textures not connected to anything
|
||||
void ConvertOrphantEmbeddedTextures();
|
||||
|
||||
private:
|
||||
// 0: not assigned yet, others: index is value - 1
|
||||
unsigned int defaultMaterialIndex;
|
||||
|
||||
std::vector<aiMesh*> meshes;
|
||||
std::vector<aiMaterial*> materials;
|
||||
std::vector<aiAnimation*> animations;
|
||||
std::vector<aiLight*> lights;
|
||||
std::vector<aiCamera*> cameras;
|
||||
std::vector<aiTexture*> textures;
|
||||
|
||||
using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
|
||||
MaterialMap materials_converted;
|
||||
|
||||
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
|
||||
VideoMap textures_converted;
|
||||
|
||||
using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
|
||||
MeshMap meshes_converted;
|
||||
|
||||
// fixed node name -> which trafo chain components have animations?
|
||||
using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
|
||||
NodeAnimBitMap node_anim_chain_bits;
|
||||
|
||||
// number of nodes with the same name
|
||||
using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
|
||||
NodeNameCache mNodeNames;
|
||||
|
||||
// Deformer name is not the same as a bone name - it does contain the bone name though :)
|
||||
// Deformer names in FBX are always unique in an FBX file.
|
||||
std::map<const std::string, aiBone *> bone_map;
|
||||
|
||||
double anim_fps;
|
||||
|
||||
aiScene* const out;
|
||||
const FBX::Document& doc;
|
||||
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
std::vector<aiBone*>& bones);
|
||||
|
||||
void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode*> &node_stack );
|
||||
|
||||
static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INCLUDED_AI_FBX_CONVERTER_H
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::~Deformer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Deformer(id,element,doc,name)
|
||||
, node()
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Indexes = sc["Indexes"];
|
||||
const Element* const Weights = sc["Weights"];
|
||||
|
||||
const Element& Transform = GetRequiredElement(sc,"Transform",&element);
|
||||
const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
|
||||
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster",&element);
|
||||
}
|
||||
|
||||
if(Indexes) {
|
||||
ParseVectorDataArray(indices,*Indexes);
|
||||
ParseVectorDataArray(weights,*Weights);
|
||||
}
|
||||
|
||||
if(indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up",&element);
|
||||
}
|
||||
|
||||
// read assigned node
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
|
||||
for(const Connection* con : conns) {
|
||||
const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if(mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster",&element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::~Cluster()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Deformer(id,element,doc,name)
|
||||
, accuracy( 0.0f ) {
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
|
||||
if(Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
|
||||
}
|
||||
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
|
||||
clusters.reserve(conns.size());
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if(cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::~Skin()
|
||||
{
|
||||
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Deformer(id, element, doc, name)
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
blendShapeChannels.reserve(conns.size());
|
||||
for (const Connection* con : conns) {
|
||||
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::~BlendShape()
|
||||
{
|
||||
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Deformer(id, element, doc, name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const DeformPercent = sc["DeformPercent"];
|
||||
if (DeformPercent) {
|
||||
percent = ParseTokenAsFloat(GetRequiredToken(*DeformPercent, 0));
|
||||
}
|
||||
const Element* const FullWeights = sc["FullWeights"];
|
||||
if (FullWeights) {
|
||||
ParseVectorDataArray(fullWeights, *FullWeights);
|
||||
}
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
|
||||
shapeGeometries.reserve(conns.size());
|
||||
for (const Connection* con : conns) {
|
||||
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::~BlendShapeChannel()
|
||||
{
|
||||
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,718 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the*
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocument.cpp
|
||||
* @brief Implementation of the FBX DOM classes
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc)
|
||||
: doc(doc)
|
||||
, element(element)
|
||||
, id(id)
|
||||
, flags() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::~LazyObject()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* LazyObject::Get(bool dieOnError)
|
||||
{
|
||||
if(IsBeingConstructed() || FailedToConstruct()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (object.get()) {
|
||||
return object.get();
|
||||
}
|
||||
|
||||
const Token& key = element.KeyToken();
|
||||
const TokenList& tokens = element.Tokens();
|
||||
|
||||
if(tokens.size() < 3) {
|
||||
DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
}
|
||||
|
||||
const char* err;
|
||||
std::string name = ParseTokenAsString(*tokens[1],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if(tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i+1] == 0x1) {
|
||||
name = name.substr(i+2) + "::" + name.substr(0,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string classtag = ParseTokenAsString(*tokens[2],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
|
||||
try {
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char* obtype = key.begin();
|
||||
const size_t length = static_cast<size_t>(key.end()-key.begin());
|
||||
|
||||
// For debugging
|
||||
//dumpObjectClassInfo( objtype, classtag );
|
||||
|
||||
if (!strncmp(obtype,"Geometry",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Mesh")) {
|
||||
object.reset(new MeshGeometry(id,element,name,doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Shape")) {
|
||||
object.reset(new ShapeGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Line")) {
|
||||
object.reset(new LineGeometry(id, element, name, doc));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"NodeAttribute",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Camera")) {
|
||||
object.reset(new Camera(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Light")) {
|
||||
object.reset(new Light(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Null")) {
|
||||
object.reset(new Null(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"LimbNode")) {
|
||||
object.reset(new LimbNode(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Deformer",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Cluster")) {
|
||||
object.reset(new Cluster(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Skin")) {
|
||||
object.reset(new Skin(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(), "BlendShape")) {
|
||||
object.reset(new BlendShape(id, element, doc, name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
|
||||
object.reset(new BlendShapeChannel(id, element, doc, name));
|
||||
}
|
||||
}
|
||||
else if ( !strncmp( obtype, "Model", length ) ) {
|
||||
// FK and IK effectors are not supported
|
||||
if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) {
|
||||
object.reset( new Model( id, element, doc, name ) );
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Material",length)) {
|
||||
object.reset(new Material(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"Texture",length)) {
|
||||
object.reset(new Texture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"LayeredTexture",length)) {
|
||||
object.reset(new LayeredTexture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"Video",length)) {
|
||||
object.reset(new Video(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationStack",length)) {
|
||||
object.reset(new AnimationStack(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationLayer",length)) {
|
||||
object.reset(new AnimationLayer(id,element,name,doc));
|
||||
}
|
||||
// note: order matters for these two
|
||||
else if (!strncmp(obtype,"AnimationCurve",length)) {
|
||||
object.reset(new AnimationCurve(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationCurveNode",length)) {
|
||||
object.reset(new AnimationCurveNode(id,element,name,doc));
|
||||
}
|
||||
}
|
||||
catch(std::exception& ex) {
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
flags |= FAILED_TO_CONSTRUCT;
|
||||
|
||||
if(dieOnError || doc.Settings().strictMode) {
|
||||
throw;
|
||||
}
|
||||
|
||||
// note: the error message is already formatted, so raw logging is ok
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_ERROR(ex.what());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!object.get()) {
|
||||
//DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
|
||||
}
|
||||
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::Object(uint64_t id, const Element& element, const std::string& name)
|
||||
: element(element)
|
||||
, name(name)
|
||||
, id(id)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::~Object()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props)
|
||||
: props(props)
|
||||
, doc(doc)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::~FileGlobalSettings()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser& parser, const ImportSettings& settings)
|
||||
: settings(settings)
|
||||
, parser(parser)
|
||||
{
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (auto &timeStamp : creationTimeStamp) {
|
||||
timeStamp = 0;
|
||||
}
|
||||
|
||||
ReadHeader();
|
||||
ReadPropertyTemplates();
|
||||
|
||||
ReadGlobalSettings();
|
||||
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document()
|
||||
{
|
||||
for(ObjectMap::value_type& v : objects) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for(ConnectionMap::value_type& v : src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
// |dest_connections| contain the same Connection objects as the |src_connections|
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int LowerSupportedVersion = 7100;
|
||||
static const unsigned int UpperSupportedVersion = 7400;
|
||||
|
||||
void Document::ReadHeader() {
|
||||
// Read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["FBXHeaderExtension"];
|
||||
if(!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
|
||||
const Scope& shead = *ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
|
||||
|
||||
// While we may have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if(fbxVersion < LowerSupportedVersion ) {
|
||||
DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
|
||||
}
|
||||
if(fbxVersion > UpperSupportedVersion ) {
|
||||
if(Settings().strictMode) {
|
||||
DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
|
||||
" (turn off strict mode to try anyhow) ");
|
||||
}
|
||||
else {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
}
|
||||
|
||||
const Element* const ecreator = shead["Creator"];
|
||||
if(ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
|
||||
}
|
||||
|
||||
const Element* const etimestamp = shead["CreationTimeStamp"];
|
||||
if(etimestamp && etimestamp->Compound()) {
|
||||
const Scope& stimestamp = *etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["GlobalSettings"];
|
||||
if ( nullptr == ehead || !ehead->Compound() ) {
|
||||
DOMWarning( "no GlobalSettings dictionary found" );
|
||||
globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
|
||||
|
||||
//double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 );
|
||||
|
||||
if(!props) {
|
||||
DOMError("GlobalSettings dictionary contains no property table");
|
||||
}
|
||||
|
||||
globals.reset(new FileGlobalSettings(*this, props));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects()
|
||||
{
|
||||
// read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const eobjects = sc["Objects"];
|
||||
if(!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, *eobjects, *this);
|
||||
|
||||
const Scope& sobjects = *eobjects->Compound();
|
||||
for(const ElementMap::value_type& el : sobjects.Elements()) {
|
||||
|
||||
// extract ID
|
||||
const TokenList& tok = el.second->Tokens();
|
||||
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key",el.second);
|
||||
}
|
||||
|
||||
const char* err;
|
||||
const uint64_t id = ParseTokenAsID(*tok[0], err);
|
||||
if(err) {
|
||||
DOMError(err,el.second);
|
||||
}
|
||||
|
||||
// id=0 is normally implicit
|
||||
if(id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0",el.second);
|
||||
}
|
||||
|
||||
if(objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, *el.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if(!strcmp(el.first.c_str(),"AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const edefs = sc["Definitions"];
|
||||
if(!edefs || !edefs->Compound()) {
|
||||
DOMWarning("no Definitions dictionary found");
|
||||
return;
|
||||
}
|
||||
|
||||
const Scope& sdefs = *edefs->Compound();
|
||||
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
|
||||
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for ObjectType element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& oname = ParseTokenAsString(*tok[0]);
|
||||
|
||||
const ElementCollection templs = sc->GetCollection("PropertyTemplate");
|
||||
for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& pname = ParseTokenAsString(*tok[0]);
|
||||
|
||||
const Element* Properties70 = (*sc)["Properties70"];
|
||||
if(Properties70) {
|
||||
std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
|
||||
*Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
|
||||
);
|
||||
|
||||
templates[oname+"."+pname] = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
if(!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
|
||||
uint64_t insertionOrder = 0l;
|
||||
const Scope& sconns = *econns->Compound();
|
||||
const ElementCollection conns = sconns.GetCollection("C");
|
||||
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
|
||||
|
||||
// PP = property-property connection, ignored for now
|
||||
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
|
||||
if ( type == "PP" ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
|
||||
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
|
||||
|
||||
if(objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if(objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add new connection
|
||||
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
|
||||
src_connections.insert(ConnectionMap::value_type(src,c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest,c));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack*>& Document::AnimationStacks() const
|
||||
{
|
||||
if (!animationStacksResolved.empty() || animationStacks.empty()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
for(uint64_t id : animationStacks) {
|
||||
LazyObject* const lazy = GetObject(id);
|
||||
const AnimationStack* stack;
|
||||
if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
|
||||
DOMWarning("failed to read AnimationStack object");
|
||||
continue;
|
||||
}
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject* Document::GetObject(uint64_t id) const
|
||||
{
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const
|
||||
{
|
||||
std::vector<const Connection*> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap& conns,
|
||||
const char* const* classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
ai_assert(classnames);
|
||||
ai_assert( count != 0 );
|
||||
ai_assert( count <= MAX_CLASSNAMES);
|
||||
|
||||
size_t lengths[MAX_CLASSNAMES];
|
||||
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lengths[ i ] = strlen(classnames[i]);
|
||||
}
|
||||
|
||||
std::vector<const Connection*> temp;
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
const Token& key = (is_src
|
||||
? (*it).second->LazyDestinationObject()
|
||||
: (*it).second->LazySourceObject()
|
||||
).GetElement().KeyToken();
|
||||
|
||||
const char* obtype = key.begin();
|
||||
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
ai_assert(classnames[i]);
|
||||
if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
|
||||
obtype = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(obtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
|
||||
{
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const
|
||||
{
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsBySourceSequenced(src, arr,1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char* const* classnames, size_t count) const
|
||||
{
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* classname) const
|
||||
{
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsByDestinationSequenced(dest, arr,1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
|
||||
{
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* const* classnames, size_t count) const
|
||||
|
||||
{
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop,
|
||||
const Document& doc)
|
||||
|
||||
: insertionOrder(insertionOrder)
|
||||
, prop(prop)
|
||||
, src(src)
|
||||
, dest(dest)
|
||||
, doc(doc)
|
||||
{
|
||||
ai_assert(doc.Objects().find(src) != doc.Objects().end());
|
||||
// dest may be 0 (root node)
|
||||
ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::~Connection()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazySourceObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazyDestinationObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::SourceObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::DestinationObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.cpp
|
||||
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
namespace Util {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
||||
void DOMError(const std::string& message, const Token& token)
|
||||
{
|
||||
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DOMError(const std::string& message, const Element* element /*= NULL*/)
|
||||
{
|
||||
if(element) {
|
||||
DOMError(message,element->KeyToken());
|
||||
}
|
||||
throw DeadlyImportError("FBX-DOM " + message);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// print warning, do return
|
||||
void DOMWarning(const std::string& message, const Token& token)
|
||||
{
|
||||
if(DefaultLogger::get()) {
|
||||
ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
|
||||
{
|
||||
if(element) {
|
||||
DOMWarning(message,element->KeyToken());
|
||||
return;
|
||||
}
|
||||
if(DefaultLogger::get()) {
|
||||
ASSIMP_LOG_WARN("FBX-DOM: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// fetch a property table and the corresponding property template
|
||||
std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn /*= false*/)
|
||||
{
|
||||
const Element* const Properties70 = sc["Properties70"];
|
||||
std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
|
||||
static_cast<const PropertyTable*>(NULL));
|
||||
|
||||
if(templateName.length()) {
|
||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||
if(it != doc.Templates().end()) {
|
||||
templateProps = (*it).second;
|
||||
}
|
||||
}
|
||||
|
||||
if(!Properties70 || !Properties70->Compound()) {
|
||||
if(!no_warn) {
|
||||
DOMWarning("property table (Properties70) not found",&element);
|
||||
}
|
||||
if(templateProps) {
|
||||
return templateProps;
|
||||
}
|
||||
else {
|
||||
return std::make_shared<const PropertyTable>();
|
||||
}
|
||||
}
|
||||
return std::make_shared<const PropertyTable>(*Properties70,templateProps);
|
||||
}
|
||||
} // !Util
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.h
|
||||
* @brief FBX internal utilities used by the DOM reading code
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_DOCUMENT_UTIL_H
|
||||
#define INCLUDED_AI_FBX_DOCUMENT_UTIL_H
|
||||
|
||||
#include <assimp/defs.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "FBXDocument.h"
|
||||
|
||||
struct Token;
|
||||
struct Element;
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
namespace Util {
|
||||
|
||||
/* DOM/Parse error reporting - does not return */
|
||||
AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// does return
|
||||
void DOMWarning(const std::string& message, const Token& token);
|
||||
void DOMWarning(const std::string& message, const Element* element = NULL);
|
||||
|
||||
|
||||
// fetch a property table and the corresponding property template
|
||||
std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn = false);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
const T* ProcessSimpleConnection(const Connection& con,
|
||||
bool is_object_property_conn,
|
||||
const char* name,
|
||||
const Element& element,
|
||||
const char** propNameOut = nullptr)
|
||||
{
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
|
||||
const Object* const ob = con.SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming " + std::string(name) +
|
||||
" link, ignoring",
|
||||
&element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dynamic_cast<const T*>(ob);
|
||||
}
|
||||
|
||||
} //!Util
|
||||
} //!FBX
|
||||
} //!Assimp
|
||||
|
||||
#endif
|
|
@ -1,571 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#include "FBXExportNode.h"
|
||||
#include "FBXCommon.h"
|
||||
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/StringUtils.h> // ai_snprintf
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <sstream> // ostringstream
|
||||
#include <memory> // shared_ptr
|
||||
|
||||
namespace Assimp {
|
||||
// AddP70<type> helpers... there's no usable pattern here,
|
||||
// so all are defined as separate functions.
|
||||
// Even "animatable" properties are often completely different
|
||||
// from the standard (nonanimated) property definition,
|
||||
// so they are specified with an 'A' suffix.
|
||||
|
||||
void FBX::Node::AddP70int(
|
||||
const std::string& name, int32_t value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "int", "Integer", "", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70bool(
|
||||
const std::string& name, bool value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "bool", "", "", int32_t(value));
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70double(
|
||||
const std::string& name, double value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "double", "Number", "", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70numberA(
|
||||
const std::string& name, double value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "Number", "", "A", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70color(
|
||||
const std::string& name, double r, double g, double b
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "ColorRGB", "Color", "", r, g, b);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70colorA(
|
||||
const std::string& name, double r, double g, double b
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "Color", "", "A", r, g, b);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70vector(
|
||||
const std::string& name, double x, double y, double z
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "Vector3D", "Vector", "", x, y, z);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70vectorA(
|
||||
const std::string& name, double x, double y, double z
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "Vector", "", "A", x, y, z);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70string(
|
||||
const std::string& name, const std::string& value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "KString", "", "", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70enum(
|
||||
const std::string& name, int32_t value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "enum", "", "", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
void FBX::Node::AddP70time(
|
||||
const std::string& name, int64_t value
|
||||
) {
|
||||
FBX::Node n("P");
|
||||
n.AddProperties(name, "KTime", "Time", "", value);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
|
||||
// public member functions for writing nodes to stream
|
||||
|
||||
void FBX::Node::Dump(
|
||||
std::shared_ptr<Assimp::IOStream> outfile,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
Assimp::StreamWriterLE outstream(outfile);
|
||||
DumpBinary(outstream);
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
DumpAscii(ss, indent);
|
||||
std::string s = ss.str();
|
||||
outfile->Write(s.c_str(), s.size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::Dump(
|
||||
Assimp::StreamWriterLE &outstream,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
DumpBinary(outstream);
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
DumpAscii(ss, indent);
|
||||
outstream.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public member functions for low-level writing
|
||||
|
||||
void FBX::Node::Begin(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
BeginBinary(s);
|
||||
} else {
|
||||
// assume we're at the correct place to start already
|
||||
(void)indent;
|
||||
std::ostringstream ss;
|
||||
BeginAscii(ss, indent);
|
||||
s.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::DumpProperties(
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
DumpPropertiesBinary(s);
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
DumpPropertiesAscii(ss, indent);
|
||||
s.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::EndProperties(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
EndProperties(s, binary, indent, properties.size());
|
||||
}
|
||||
|
||||
void FBX::Node::EndProperties(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool binary, int indent,
|
||||
size_t num_properties
|
||||
) {
|
||||
if (binary) {
|
||||
EndPropertiesBinary(s, num_properties);
|
||||
} else {
|
||||
// nothing to do
|
||||
(void)indent;
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::BeginChildren(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
// nothing to do
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
BeginChildrenAscii(ss, indent);
|
||||
s.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::DumpChildren(
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
if (binary) {
|
||||
DumpChildrenBinary(s);
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
DumpChildrenAscii(ss, indent);
|
||||
if (ss.tellp() > 0)
|
||||
s.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::End(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool binary, int indent,
|
||||
bool has_children
|
||||
) {
|
||||
if (binary) {
|
||||
EndBinary(s, has_children);
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
EndAscii(ss, indent, has_children);
|
||||
if (ss.tellp() > 0)
|
||||
s.PutString(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public member functions for writing to binary fbx
|
||||
|
||||
void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s)
|
||||
{
|
||||
// write header section (with placeholders for some things)
|
||||
BeginBinary(s);
|
||||
|
||||
// write properties
|
||||
DumpPropertiesBinary(s);
|
||||
|
||||
// go back and fill in property related placeholders
|
||||
EndPropertiesBinary(s, properties.size());
|
||||
|
||||
// write children
|
||||
DumpChildrenBinary(s);
|
||||
|
||||
// finish, filling in end offset placeholder
|
||||
EndBinary(s, force_has_children || !children.empty());
|
||||
}
|
||||
|
||||
|
||||
// public member functions for writing to ascii fbx
|
||||
|
||||
void FBX::Node::DumpAscii(std::ostream &s, int indent)
|
||||
{
|
||||
// write name
|
||||
BeginAscii(s, indent);
|
||||
|
||||
// write properties
|
||||
DumpPropertiesAscii(s, indent);
|
||||
|
||||
if (force_has_children || !children.empty()) {
|
||||
// begin children (with a '{')
|
||||
BeginChildrenAscii(s, indent + 1);
|
||||
// write children
|
||||
DumpChildrenAscii(s, indent + 1);
|
||||
}
|
||||
|
||||
// finish (also closing the children bracket '}')
|
||||
EndAscii(s, indent, force_has_children || !children.empty());
|
||||
}
|
||||
|
||||
|
||||
// private member functions for low-level writing to fbx
|
||||
|
||||
void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
|
||||
{
|
||||
// remember start pos so we can come back and write the end pos
|
||||
this->start_pos = s.Tell();
|
||||
|
||||
// placeholders for end pos and property section info
|
||||
s.PutU4(0); // end pos
|
||||
s.PutU4(0); // number of properties
|
||||
s.PutU4(0); // total property section length
|
||||
|
||||
// node name
|
||||
s.PutU1(uint8_t(name.size())); // length of node name
|
||||
s.PutString(name); // node name as raw bytes
|
||||
|
||||
// property data comes after here
|
||||
this->property_start = s.Tell();
|
||||
}
|
||||
|
||||
void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s)
|
||||
{
|
||||
for (auto &p : properties) {
|
||||
p.DumpBinary(s);
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::EndPropertiesBinary(
|
||||
Assimp::StreamWriterLE &s,
|
||||
size_t num_properties
|
||||
) {
|
||||
if (num_properties == 0) { return; }
|
||||
size_t pos = s.Tell();
|
||||
ai_assert(pos > property_start);
|
||||
size_t property_section_size = pos - property_start;
|
||||
s.Seek(start_pos + 4);
|
||||
s.PutU4(uint32_t(num_properties));
|
||||
s.PutU4(uint32_t(property_section_size));
|
||||
s.Seek(pos);
|
||||
}
|
||||
|
||||
void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s)
|
||||
{
|
||||
for (FBX::Node& child : children) {
|
||||
child.DumpBinary(s);
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::EndBinary(
|
||||
Assimp::StreamWriterLE &s,
|
||||
bool has_children
|
||||
) {
|
||||
// if there were children, add a null record
|
||||
if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); }
|
||||
|
||||
// now go back and write initial pos
|
||||
this->end_pos = s.Tell();
|
||||
s.Seek(start_pos);
|
||||
s.PutU4(uint32_t(end_pos));
|
||||
s.Seek(end_pos);
|
||||
}
|
||||
|
||||
|
||||
void FBX::Node::BeginAscii(std::ostream& s, int indent)
|
||||
{
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << name << ": ";
|
||||
}
|
||||
|
||||
void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent)
|
||||
{
|
||||
for (size_t i = 0; i < properties.size(); ++i) {
|
||||
if (i > 0) { s << ", "; }
|
||||
properties[i].DumpAscii(s, indent);
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent)
|
||||
{
|
||||
// only call this if there are actually children
|
||||
s << " {";
|
||||
(void)indent;
|
||||
}
|
||||
|
||||
void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent)
|
||||
{
|
||||
// children will need a lot of padding and corralling
|
||||
if (children.size() || force_has_children) {
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
// no compression in ascii files, so skip this node if it exists
|
||||
if (children[i].name == "EncryptionType") { continue; }
|
||||
// the child can dump itself
|
||||
children[i].DumpAscii(s, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
|
||||
{
|
||||
if (!has_children) { return; } // nothing to do
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << "}";
|
||||
}
|
||||
|
||||
// private helpers for static member functions
|
||||
|
||||
// ascii property node from vector of doubles
|
||||
void FBX::Node::WritePropertyNodeAscii(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
int indent
|
||||
){
|
||||
char buffer[32];
|
||||
FBX::Node node(name);
|
||||
node.Begin(s, false, indent);
|
||||
std::string vsize = to_string(v.size());
|
||||
// *<size> {
|
||||
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
|
||||
// indent + 1
|
||||
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
|
||||
// a: value,value,value,...
|
||||
s.PutString("a: ");
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
if (i > 0) { s.PutChar(','); }
|
||||
int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]);
|
||||
count += len;
|
||||
if (count > 2048) { s.PutChar('\n'); count = 0; }
|
||||
if (len < 0 || len > 31) {
|
||||
// this should never happen
|
||||
throw DeadlyExportError("failed to convert double to string");
|
||||
}
|
||||
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
|
||||
}
|
||||
// }
|
||||
s.PutChar('\n');
|
||||
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
|
||||
s.PutChar('}'); s.PutChar(' ');
|
||||
node.End(s, false, indent, false);
|
||||
}
|
||||
|
||||
// ascii property node from vector of int32_t
|
||||
void FBX::Node::WritePropertyNodeAscii(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
int indent
|
||||
){
|
||||
char buffer[32];
|
||||
FBX::Node node(name);
|
||||
node.Begin(s, false, indent);
|
||||
std::string vsize = to_string(v.size());
|
||||
// *<size> {
|
||||
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
|
||||
// indent + 1
|
||||
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
|
||||
// a: value,value,value,...
|
||||
s.PutString("a: ");
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
if (i > 0) { s.PutChar(','); }
|
||||
int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]);
|
||||
count += len;
|
||||
if (count > 2048) { s.PutChar('\n'); count = 0; }
|
||||
if (len < 0 || len > 31) {
|
||||
// this should never happen
|
||||
throw DeadlyExportError("failed to convert double to string");
|
||||
}
|
||||
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
|
||||
}
|
||||
// }
|
||||
s.PutChar('\n');
|
||||
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
|
||||
s.PutChar('}'); s.PutChar(' ');
|
||||
node.End(s, false, indent, false);
|
||||
}
|
||||
|
||||
// binary property node from vector of doubles
|
||||
// TODO: optional zip compression!
|
||||
void FBX::Node::WritePropertyNodeBinary(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s
|
||||
){
|
||||
FBX::Node node(name);
|
||||
node.BeginBinary(s);
|
||||
s.PutU1('d');
|
||||
s.PutU4(uint32_t(v.size())); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
s.PutU4(uint32_t(v.size()) * 8); // data size
|
||||
for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
|
||||
node.EndPropertiesBinary(s, 1);
|
||||
node.EndBinary(s, false);
|
||||
}
|
||||
|
||||
// binary property node from vector of int32_t
|
||||
// TODO: optional zip compression!
|
||||
void FBX::Node::WritePropertyNodeBinary(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s
|
||||
){
|
||||
FBX::Node node(name);
|
||||
node.BeginBinary(s);
|
||||
s.PutU1('i');
|
||||
s.PutU4(uint32_t(v.size())); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
s.PutU4(uint32_t(v.size()) * 4); // data size
|
||||
for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
|
||||
node.EndPropertiesBinary(s, 1);
|
||||
node.EndBinary(s, false);
|
||||
}
|
||||
|
||||
// public static member functions
|
||||
|
||||
// convenience function to create and write a property node,
|
||||
// holding a single property which is an array of values.
|
||||
// does not copy the data, so is efficient for large arrays.
|
||||
void FBX::Node::WritePropertyNode(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
){
|
||||
if (binary) {
|
||||
FBX::Node::WritePropertyNodeBinary(name, v, s);
|
||||
} else {
|
||||
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
|
||||
}
|
||||
}
|
||||
|
||||
// convenience function to create and write a property node,
|
||||
// holding a single property which is an array of values.
|
||||
// does not copy the data, so is efficient for large arrays.
|
||||
void FBX::Node::WritePropertyNode(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
){
|
||||
if (binary) {
|
||||
FBX::Node::WritePropertyNodeBinary(name, v, s);
|
||||
} else {
|
||||
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -1,271 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXExportNode.h
|
||||
* Declares the FBX::Node helper class for fbx export.
|
||||
*/
|
||||
#ifndef AI_FBXEXPORTNODE_H_INC
|
||||
#define AI_FBXEXPORTNODE_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#include "FBXExportProperty.h"
|
||||
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
class Node;
|
||||
}
|
||||
|
||||
class FBX::Node {
|
||||
public:
|
||||
// TODO: accessors
|
||||
std::string name; // node name
|
||||
std::vector<FBX::FBXExportProperty> properties; // node properties
|
||||
std::vector<FBX::Node> children; // child nodes
|
||||
|
||||
// some nodes always pretend they have children...
|
||||
bool force_has_children = false;
|
||||
|
||||
public: // constructors
|
||||
/// The default class constructor.
|
||||
Node() = default;
|
||||
|
||||
/// The class constructor with the name.
|
||||
Node(const std::string& n)
|
||||
: name(n)
|
||||
, properties()
|
||||
, children()
|
||||
, force_has_children( false ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// convenience template to construct with properties directly
|
||||
template <typename... More>
|
||||
Node(const std::string& n, const More... more)
|
||||
: name(n)
|
||||
, properties()
|
||||
, children()
|
||||
, force_has_children(false) {
|
||||
AddProperties(more...);
|
||||
}
|
||||
|
||||
public: // functions to add properties or children
|
||||
// add a single property to the node
|
||||
template <typename T>
|
||||
void AddProperty(T value) {
|
||||
properties.emplace_back(value);
|
||||
}
|
||||
|
||||
// convenience function to add multiple properties at once
|
||||
template <typename T, typename... More>
|
||||
void AddProperties(T value, More... more) {
|
||||
properties.emplace_back(value);
|
||||
AddProperties(more...);
|
||||
}
|
||||
void AddProperties() {}
|
||||
|
||||
// add a child node directly
|
||||
void AddChild(const Node& node) { children.push_back(node); }
|
||||
|
||||
// convenience function to add a child node with a single property
|
||||
template <typename... More>
|
||||
void AddChild(
|
||||
const std::string& name,
|
||||
More... more
|
||||
) {
|
||||
FBX::Node c(name);
|
||||
c.AddProperties(more...);
|
||||
children.push_back(c);
|
||||
}
|
||||
|
||||
public: // support specifically for dealing with Properties70 nodes
|
||||
|
||||
// it really is simpler to make these all separate functions.
|
||||
// the versions with 'A' suffixes are for animatable properties.
|
||||
// those often follow a completely different format internally in FBX.
|
||||
void AddP70int(const std::string& name, int32_t value);
|
||||
void AddP70bool(const std::string& name, bool value);
|
||||
void AddP70double(const std::string& name, double value);
|
||||
void AddP70numberA(const std::string& name, double value);
|
||||
void AddP70color(const std::string& name, double r, double g, double b);
|
||||
void AddP70colorA(const std::string& name, double r, double g, double b);
|
||||
void AddP70vector(const std::string& name, double x, double y, double z);
|
||||
void AddP70vectorA(const std::string& name, double x, double y, double z);
|
||||
void AddP70string(const std::string& name, const std::string& value);
|
||||
void AddP70enum(const std::string& name, int32_t value);
|
||||
void AddP70time(const std::string& name, int64_t value);
|
||||
|
||||
// template for custom P70 nodes.
|
||||
// anything that doesn't fit in the above can be created manually.
|
||||
template <typename... More>
|
||||
void AddP70(
|
||||
const std::string& name,
|
||||
const std::string& type,
|
||||
const std::string& type2,
|
||||
const std::string& flags,
|
||||
More... more
|
||||
) {
|
||||
Node n("P");
|
||||
n.AddProperties(name, type, type2, flags, more...);
|
||||
AddChild(n);
|
||||
}
|
||||
|
||||
public: // member functions for writing data to a file or stream
|
||||
|
||||
// write the full node to the given file or stream
|
||||
void Dump(
|
||||
std::shared_ptr<Assimp::IOStream> outfile,
|
||||
bool binary, int indent
|
||||
);
|
||||
void Dump(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||
|
||||
// these other functions are for writing data piece by piece.
|
||||
// they must be used carefully.
|
||||
// for usage examples see FBXExporter.cpp.
|
||||
void Begin(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||
void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent);
|
||||
void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||
void EndProperties(
|
||||
Assimp::StreamWriterLE &s, bool binary, int indent,
|
||||
size_t num_properties
|
||||
);
|
||||
void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||
void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent);
|
||||
void End(
|
||||
Assimp::StreamWriterLE &s, bool binary, int indent,
|
||||
bool has_children
|
||||
);
|
||||
|
||||
private: // internal functions used for writing
|
||||
|
||||
void DumpBinary(Assimp::StreamWriterLE &s);
|
||||
void DumpAscii(Assimp::StreamWriterLE &s, int indent);
|
||||
void DumpAscii(std::ostream &s, int indent);
|
||||
|
||||
void BeginBinary(Assimp::StreamWriterLE &s);
|
||||
void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
|
||||
void EndPropertiesBinary(Assimp::StreamWriterLE &s);
|
||||
void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
|
||||
void DumpChildrenBinary(Assimp::StreamWriterLE& s);
|
||||
void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
|
||||
|
||||
void BeginAscii(std::ostream &s, int indent);
|
||||
void DumpPropertiesAscii(std::ostream &s, int indent);
|
||||
void BeginChildrenAscii(std::ostream &s, int indent);
|
||||
void DumpChildrenAscii(std::ostream &s, int indent);
|
||||
void EndAscii(std::ostream &s, int indent, bool has_children);
|
||||
|
||||
private: // data used for binary dumps
|
||||
size_t start_pos; // starting position in stream
|
||||
size_t end_pos; // ending position in stream
|
||||
size_t property_start; // starting position of property section
|
||||
|
||||
public: // static member functions
|
||||
|
||||
// convenience function to create a node with a single property,
|
||||
// and write it to the stream.
|
||||
template <typename T>
|
||||
static void WritePropertyNode(
|
||||
const std::string& name,
|
||||
const T value,
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
) {
|
||||
FBX::FBXExportProperty p(value);
|
||||
FBX::Node node(name, p);
|
||||
node.Dump(s, binary, indent);
|
||||
}
|
||||
|
||||
// convenience function to create and write a property node,
|
||||
// holding a single property which is an array of values.
|
||||
// does not copy the data, so is efficient for large arrays.
|
||||
static void WritePropertyNode(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
);
|
||||
|
||||
// convenience function to create and write a property node,
|
||||
// holding a single property which is an array of values.
|
||||
// does not copy the data, so is efficient for large arrays.
|
||||
static void WritePropertyNode(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
bool binary, int indent
|
||||
);
|
||||
|
||||
private: // static helper functions
|
||||
static void WritePropertyNodeAscii(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
int indent
|
||||
);
|
||||
static void WritePropertyNodeAscii(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s,
|
||||
int indent
|
||||
);
|
||||
static void WritePropertyNodeBinary(
|
||||
const std::string& name,
|
||||
const std::vector<double>& v,
|
||||
Assimp::StreamWriterLE& s
|
||||
);
|
||||
static void WritePropertyNodeBinary(
|
||||
const std::string& name,
|
||||
const std::vector<int32_t>& v,
|
||||
Assimp::StreamWriterLE& s
|
||||
);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#endif // AI_FBXEXPORTNODE_H_INC
|
|
@ -1,385 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#include "FBXExportProperty.h"
|
||||
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
#include <locale>
|
||||
#include <sstream> // ostringstream
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
// constructors for single element properties
|
||||
|
||||
FBXExportProperty::FBXExportProperty(bool v)
|
||||
: type('C')
|
||||
, data(1, uint8_t(v)) {}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(int16_t v)
|
||||
: type('Y')
|
||||
, data(2) {
|
||||
uint8_t* d = data.data();
|
||||
(reinterpret_cast<int16_t*>(d))[0] = v;
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(int32_t v)
|
||||
: type('I')
|
||||
, data(4) {
|
||||
uint8_t* d = data.data();
|
||||
(reinterpret_cast<int32_t*>(d))[0] = v;
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(float v)
|
||||
: type('F')
|
||||
, data(4) {
|
||||
uint8_t* d = data.data();
|
||||
(reinterpret_cast<float*>(d))[0] = v;
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(double v)
|
||||
: type('D')
|
||||
, data(8) {
|
||||
uint8_t* d = data.data();
|
||||
(reinterpret_cast<double*>(d))[0] = v;
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(int64_t v)
|
||||
: type('L')
|
||||
, data(8) {
|
||||
uint8_t* d = data.data();
|
||||
(reinterpret_cast<int64_t*>(d))[0] = v;
|
||||
}
|
||||
|
||||
// constructors for array-type properties
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const char* c, bool raw)
|
||||
: FBXExportProperty(std::string(c), raw) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// strings can either be saved as "raw" (R) data, or "string" (S) data
|
||||
FBXExportProperty::FBXExportProperty(const std::string& s, bool raw)
|
||||
: type(raw ? 'R' : 'S')
|
||||
, data(s.size()) {
|
||||
for (size_t i = 0; i < s.size(); ++i) {
|
||||
data[i] = uint8_t(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const std::vector<uint8_t>& r)
|
||||
: type('R')
|
||||
, data(r) {
|
||||
// empty
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va)
|
||||
: type('i')
|
||||
, data(4 * va.size() ) {
|
||||
int32_t* d = reinterpret_cast<int32_t*>(data.data());
|
||||
for (size_t i = 0; i < va.size(); ++i) {
|
||||
d[i] = va[i];
|
||||
}
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va)
|
||||
: type('l')
|
||||
, data(8 * va.size()) {
|
||||
int64_t* d = reinterpret_cast<int64_t*>(data.data());
|
||||
for (size_t i = 0; i < va.size(); ++i) {
|
||||
d[i] = va[i];
|
||||
}
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const std::vector<float>& va)
|
||||
: type('f')
|
||||
, data(4 * va.size()) {
|
||||
float* d = reinterpret_cast<float*>(data.data());
|
||||
for (size_t i = 0; i < va.size(); ++i) {
|
||||
d[i] = va[i];
|
||||
}
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const std::vector<double>& va)
|
||||
: type('d')
|
||||
, data(8 * va.size()) {
|
||||
double* d = reinterpret_cast<double*>(data.data());
|
||||
for (size_t i = 0; i < va.size(); ++i) {
|
||||
d[i] = va[i];
|
||||
}
|
||||
}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm)
|
||||
: type('d')
|
||||
, data(8 * 16) {
|
||||
double* d = reinterpret_cast<double*>(data.data());
|
||||
for (unsigned int c = 0; c < 4; ++c) {
|
||||
for (unsigned int r = 0; r < 4; ++r) {
|
||||
d[4 * c + r] = vm[r][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public member functions
|
||||
|
||||
size_t FBXExportProperty::size() {
|
||||
switch (type) {
|
||||
case 'C':
|
||||
case 'Y':
|
||||
case 'I':
|
||||
case 'F':
|
||||
case 'D':
|
||||
case 'L':
|
||||
return data.size() + 1;
|
||||
case 'S':
|
||||
case 'R':
|
||||
return data.size() + 5;
|
||||
case 'i':
|
||||
case 'd':
|
||||
return data.size() + 13;
|
||||
default:
|
||||
throw DeadlyExportError("Requested size on property of unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) {
|
||||
s.PutU1(type);
|
||||
uint8_t* d = data.data();
|
||||
size_t N;
|
||||
switch (type) {
|
||||
case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
|
||||
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
|
||||
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
|
||||
case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
|
||||
case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
|
||||
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
|
||||
case 'S':
|
||||
case 'R':
|
||||
s.PutU4(uint32_t(data.size()));
|
||||
for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
|
||||
return;
|
||||
case 'i':
|
||||
N = data.size() / 4;
|
||||
s.PutU4(uint32_t(N)); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
// TODO: compress if large?
|
||||
s.PutU4(uint32_t(data.size())); // data size
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
|
||||
}
|
||||
return;
|
||||
case 'l':
|
||||
N = data.size() / 8;
|
||||
s.PutU4(uint32_t(N)); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
// TODO: compress if large?
|
||||
s.PutU4(uint32_t(data.size())); // data size
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
|
||||
}
|
||||
return;
|
||||
case 'f':
|
||||
N = data.size() / 4;
|
||||
s.PutU4(uint32_t(N)); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
// TODO: compress if large?
|
||||
s.PutU4(uint32_t(data.size())); // data size
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
s.PutF4((reinterpret_cast<float*>(d))[i]);
|
||||
}
|
||||
return;
|
||||
case 'd':
|
||||
N = data.size() / 8;
|
||||
s.PutU4(uint32_t(N)); // number of elements
|
||||
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||
// TODO: compress if large?
|
||||
s.PutU4(uint32_t(data.size())); // data size
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
s.PutF8((reinterpret_cast<double*>(d))[i]);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
std::ostringstream err;
|
||||
err << "Tried to dump property with invalid type '";
|
||||
err << type << "'!";
|
||||
throw DeadlyExportError(err.str());
|
||||
}
|
||||
}
|
||||
|
||||
void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) {
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
ss.precision(15); // this seems to match official FBX SDK exports
|
||||
DumpAscii(ss, indent);
|
||||
outstream.PutString(ss.str());
|
||||
}
|
||||
|
||||
void FBXExportProperty::DumpAscii(std::ostream& s, int indent) {
|
||||
// no writing type... or anything. just shove it into the stream.
|
||||
uint8_t* d = data.data();
|
||||
size_t N;
|
||||
size_t swap = data.size();
|
||||
size_t count = 0;
|
||||
switch (type) {
|
||||
case 'C':
|
||||
if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; }
|
||||
else { s << 'F'; }
|
||||
return;
|
||||
case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return;
|
||||
case 'I': s << *(reinterpret_cast<int32_t*>(d)); return;
|
||||
case 'F': s << *(reinterpret_cast<float*>(d)); return;
|
||||
case 'D': s << *(reinterpret_cast<double*>(d)); return;
|
||||
case 'L': s << *(reinterpret_cast<int64_t*>(d)); return;
|
||||
case 'S':
|
||||
// first search to see if it has "\x00\x01" in it -
|
||||
// which separates fields which are reversed in the ascii version.
|
||||
// yeah.
|
||||
// FBX, yeah.
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
if (data[i] == '\0') {
|
||||
swap = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 'R':
|
||||
s << '"';
|
||||
// we might as well check this now,
|
||||
// probably it will never happen
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
char c = data[i];
|
||||
if (c == '"') {
|
||||
throw runtime_error("can't handle quotes in property string");
|
||||
}
|
||||
}
|
||||
// first write the SWAPPED member (if any)
|
||||
for (size_t i = swap + 2; i < data.size(); ++i) {
|
||||
char c = data[i];
|
||||
s << c;
|
||||
}
|
||||
// then a separator
|
||||
if (swap != data.size()) {
|
||||
s << "::";
|
||||
}
|
||||
// then the initial member
|
||||
for (size_t i = 0; i < swap; ++i) {
|
||||
char c = data[i];
|
||||
s << c;
|
||||
}
|
||||
s << '"';
|
||||
return;
|
||||
case 'i':
|
||||
N = data.size() / 4; // number of elements
|
||||
s << '*' << N << " {\n";
|
||||
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||
s << "a: ";
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (i > 0) { s << ','; }
|
||||
if (count++ > 120) { s << '\n'; count = 0; }
|
||||
s << (reinterpret_cast<int32_t*>(d))[i];
|
||||
}
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << "} ";
|
||||
return;
|
||||
case 'l':
|
||||
N = data.size() / 8;
|
||||
s << '*' << N << " {\n";
|
||||
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||
s << "a: ";
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (i > 0) { s << ','; }
|
||||
if (count++ > 120) { s << '\n'; count = 0; }
|
||||
s << (reinterpret_cast<int64_t*>(d))[i];
|
||||
}
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << "} ";
|
||||
return;
|
||||
case 'f':
|
||||
N = data.size() / 4;
|
||||
s << '*' << N << " {\n";
|
||||
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||
s << "a: ";
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (i > 0) { s << ','; }
|
||||
if (count++ > 120) { s << '\n'; count = 0; }
|
||||
s << (reinterpret_cast<float*>(d))[i];
|
||||
}
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << "} ";
|
||||
return;
|
||||
case 'd':
|
||||
N = data.size() / 8;
|
||||
s << '*' << N << " {\n";
|
||||
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||
s << "a: ";
|
||||
// set precision to something that can handle doubles
|
||||
s.precision(15);
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (i > 0) { s << ','; }
|
||||
if (count++ > 120) { s << '\n'; count = 0; }
|
||||
s << (reinterpret_cast<double*>(d))[i];
|
||||
}
|
||||
s << '\n';
|
||||
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||
s << "} ";
|
||||
return;
|
||||
default:
|
||||
std::ostringstream err;
|
||||
err << "Tried to dump property with invalid type '";
|
||||
err << type << "'!";
|
||||
throw runtime_error(err.str());
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace FBX
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXExportProperty.h
|
||||
* Declares the FBX::Property helper class for fbx export.
|
||||
*/
|
||||
#ifndef AI_FBXEXPORTPROPERTY_H_INC
|
||||
#define AI_FBXEXPORTPROPERTY_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#include <assimp/types.h> // aiMatrix4x4
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
#include <type_traits> // is_void
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
/** @brief FBX::Property
|
||||
*
|
||||
* Holds a value of any of FBX's recognized types,
|
||||
* each represented by a particular one-character code.
|
||||
* C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true
|
||||
* Y : 2-byte int16
|
||||
* I : 4-byte int32
|
||||
* F : 4-byte float
|
||||
* D : 8-byte double
|
||||
* L : 8-byte int64
|
||||
* i : array of int32
|
||||
* f : array of float
|
||||
* d : array of double
|
||||
* l : array of int64
|
||||
* b : array of 1-byte booleans (0x00 or 0x01)
|
||||
* S : string (array of 1-byte char)
|
||||
* R : raw data (array of bytes)
|
||||
*/
|
||||
class FBXExportProperty {
|
||||
public:
|
||||
// constructors for basic types.
|
||||
// all explicit to avoid accidental typecasting
|
||||
explicit FBXExportProperty(bool v);
|
||||
// TODO: determine if there is actually a byte type,
|
||||
// or if this always means <bool>. 'C' seems to imply <char>,
|
||||
// so possibly the above was intended to represent both.
|
||||
explicit FBXExportProperty(int16_t v);
|
||||
explicit FBXExportProperty(int32_t v);
|
||||
explicit FBXExportProperty(float v);
|
||||
explicit FBXExportProperty(double v);
|
||||
explicit FBXExportProperty(int64_t v);
|
||||
// strings can either be stored as 'R' (raw) or 'S' (string) type
|
||||
explicit FBXExportProperty(const char* c, bool raw = false);
|
||||
explicit FBXExportProperty(const std::string& s, bool raw = false);
|
||||
explicit FBXExportProperty(const std::vector<uint8_t>& r);
|
||||
explicit FBXExportProperty(const std::vector<int32_t>& va);
|
||||
explicit FBXExportProperty(const std::vector<int64_t>& va);
|
||||
explicit FBXExportProperty(const std::vector<double>& va);
|
||||
explicit FBXExportProperty(const std::vector<float>& va);
|
||||
explicit FBXExportProperty(const aiMatrix4x4& vm);
|
||||
|
||||
// this will catch any type not defined above,
|
||||
// so that we don't accidentally convert something we don't want.
|
||||
// for example (const char*) --> (bool)... seriously wtf C++
|
||||
template <class T>
|
||||
explicit FBXExportProperty(T v) : type('X') {
|
||||
static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
|
||||
} // note: no line wrap so it appears verbatim on the compiler error
|
||||
|
||||
// the size of this property node in a binary file, in bytes
|
||||
size_t size();
|
||||
|
||||
// write this property node as binary data to the given stream
|
||||
void DumpBinary(Assimp::StreamWriterLE& s);
|
||||
void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0);
|
||||
void DumpAscii(std::ostream& s, int indent = 0);
|
||||
// note: make sure the ostream is in classic "C" locale
|
||||
|
||||
private:
|
||||
char type;
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
} // Namespace FBX
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#endif // AI_FBXEXPORTPROPERTY_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXExporter.h
|
||||
* Declares the exporter class to write a scene to an fbx file
|
||||
*/
|
||||
#ifndef AI_FBXEXPORTER_H_INC
|
||||
#define AI_FBXEXPORTER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#include "FBXExportNode.h" // FBX::Node
|
||||
#include "FBXCommon.h" // FBX::TransformInheritance
|
||||
|
||||
#include <assimp/types.h>
|
||||
//#include <assimp/material.h>
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <memory> // shared_ptr
|
||||
#include <sstream> // stringstream
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
//struct aiMaterial;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
class IOSystem;
|
||||
class IOStream;
|
||||
class ExportProperties;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Helper class to export a given scene to an FBX file. */
|
||||
// ---------------------------------------------------------------------
|
||||
class FBXExporter
|
||||
{
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
FBXExporter(const aiScene* pScene, const ExportProperties* pProperties);
|
||||
|
||||
// call one of these methods to export
|
||||
void ExportBinary(const char* pFile, IOSystem* pIOSystem);
|
||||
void ExportAscii(const char* pFile, IOSystem* pIOSystem);
|
||||
|
||||
private:
|
||||
bool binary; // whether current export is in binary or ascii format
|
||||
const aiScene* mScene; // the scene to export
|
||||
const ExportProperties* mProperties; // currently unused
|
||||
std::shared_ptr<IOStream> outfile; // file to write to
|
||||
|
||||
std::vector<FBX::Node> connections; // connection storage
|
||||
|
||||
std::vector<int64_t> mesh_uids;
|
||||
std::vector<int64_t> material_uids;
|
||||
std::map<const aiNode*,int64_t> node_uids;
|
||||
|
||||
// this crude unique-ID system is actually fine
|
||||
int64_t last_uid = 999999;
|
||||
int64_t generate_uid() { return ++last_uid; }
|
||||
|
||||
// binary files have a specific header and footer,
|
||||
// in addition to the actual data
|
||||
void WriteBinaryHeader();
|
||||
void WriteBinaryFooter();
|
||||
|
||||
// ascii files have a comment at the top
|
||||
void WriteAsciiHeader();
|
||||
|
||||
// WriteAllNodes does the actual export.
|
||||
// It just calls all the Write<Section> methods below in order.
|
||||
void WriteAllNodes();
|
||||
|
||||
// Methods to write individual sections.
|
||||
// The order here matches the order inside an FBX file.
|
||||
// Each method corresponds to a top-level FBX section,
|
||||
// except WriteHeader which also includes some binary-only sections
|
||||
// and WriteFooter which is binary data only.
|
||||
void WriteHeaderExtension();
|
||||
// WriteFileId(); // binary-only, included in WriteHeader
|
||||
// WriteCreationTime(); // binary-only, included in WriteHeader
|
||||
// WriteCreator(); // binary-only, included in WriteHeader
|
||||
void WriteGlobalSettings();
|
||||
void WriteDocuments();
|
||||
void WriteReferences();
|
||||
void WriteDefinitions();
|
||||
void WriteObjects();
|
||||
void WriteConnections();
|
||||
// WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
|
||||
|
||||
// helpers
|
||||
void WriteAsciiSectionHeader(const std::string& title);
|
||||
void WriteModelNodes(
|
||||
Assimp::StreamWriterLE& s,
|
||||
const aiNode* node,
|
||||
int64_t parent_uid,
|
||||
const std::unordered_set<const aiNode*>& limbnodes
|
||||
);
|
||||
void WriteModelNodes( // usually don't call this directly
|
||||
StreamWriterLE& s,
|
||||
const aiNode* node,
|
||||
int64_t parent_uid,
|
||||
const std::unordered_set<const aiNode*>& limbnodes,
|
||||
std::vector<std::pair<std::string,aiVector3D>>& transform_chain
|
||||
);
|
||||
void WriteModelNode( // nor this
|
||||
StreamWriterLE& s,
|
||||
bool binary,
|
||||
const aiNode* node,
|
||||
int64_t node_uid,
|
||||
const std::string& type,
|
||||
const std::vector<std::pair<std::string,aiVector3D>>& xfm_chain,
|
||||
FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs
|
||||
);
|
||||
void WriteAnimationCurveNode(
|
||||
StreamWriterLE& outstream,
|
||||
int64_t uid,
|
||||
const std::string& name, // "T", "R", or "S"
|
||||
aiVector3D default_value,
|
||||
std::string property_name, // "Lcl Translation" etc
|
||||
int64_t animation_layer_uid,
|
||||
int64_t node_uid
|
||||
);
|
||||
void WriteAnimationCurve(
|
||||
StreamWriterLE& outstream,
|
||||
double default_value,
|
||||
const std::vector<int64_t>& times,
|
||||
const std::vector<float>& values,
|
||||
int64_t curvenode_id,
|
||||
const std::string& property_link // "d|X", "d|Y", etc
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
#endif // AI_FBXEXPORTER_H_INC
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImportSettings.h
|
||||
* @brief FBX importer runtime configuration
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_IMPORTSETTINGS_H
|
||||
#define INCLUDED_AI_FBX_IMPORTSETTINGS_H
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
|
||||
struct ImportSettings
|
||||
{
|
||||
ImportSettings()
|
||||
: strictMode(true)
|
||||
, readAllLayers(true)
|
||||
, readAllMaterials(false)
|
||||
, readMaterials(true)
|
||||
, readTextures(true)
|
||||
, readCameras(true)
|
||||
, readLights(true)
|
||||
, readAnimations(true)
|
||||
, readWeights(true)
|
||||
, preservePivots(true)
|
||||
, optimizeEmptyAnimationCurves(true)
|
||||
, useLegacyEmbeddedTextureNaming(false)
|
||||
, removeEmptyBones( true )
|
||||
, convertToMeters( false ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated. Strict mode is off by default. */
|
||||
bool strictMode;
|
||||
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers. The default
|
||||
* value for this option is true.*/
|
||||
bool readAllLayers;
|
||||
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed .
|
||||
* This bit is ignored unless readMaterials=true*/
|
||||
bool readAllMaterials;
|
||||
|
||||
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material. The default value is true.*/
|
||||
bool readMaterials;
|
||||
|
||||
/** import embedded textures? Default value is true.*/
|
||||
bool readTextures;
|
||||
|
||||
/** import cameras? Default value is true.*/
|
||||
bool readCameras;
|
||||
|
||||
/** import light sources? Default value is true.*/
|
||||
bool readLights;
|
||||
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported). Default value is true. */
|
||||
bool readAnimations;
|
||||
|
||||
/** read bones (vertex weights and deform info).
|
||||
* Default value is true. */
|
||||
bool readWeights;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower. The default value
|
||||
* is true.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots;
|
||||
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.
|
||||
* The default value is true. */
|
||||
bool optimizeEmptyAnimationCurves;
|
||||
|
||||
/** use legacy naming for embedded textures eg: (*0, *1, *2)
|
||||
*/
|
||||
bool useLegacyEmbeddedTextureNaming;
|
||||
|
||||
/** Empty bones shall be removed
|
||||
*/
|
||||
bool removeEmptyBones;
|
||||
|
||||
/** Set to true to perform a conversion from cm to meter after the import
|
||||
*/
|
||||
bool convertToMeters;
|
||||
};
|
||||
|
||||
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
r
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImporter.cpp
|
||||
* @brief Implementation of the FBX importer.
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXImporter.h"
|
||||
|
||||
#include "FBXConverter.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXUtil.h"
|
||||
|
||||
#include <assimp/MemoryIOWrapper.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
template <>
|
||||
const char *LogFunctions<FBXImporter>::Prefix() {
|
||||
static auto prefix = "FBX: ";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
using namespace Assimp::FBX;
|
||||
|
||||
namespace {
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Autodesk FBX Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"fbx"
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by #Importer
|
||||
FBXImporter::FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FBXImporter::~FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == std::string(desc.mFileExtensions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
|
||||
const char *tokens[] = { "fbx" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// List all extensions handled by this loader
|
||||
const aiImporterDesc *FBXImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
|
||||
// read entire file into memory - no streaming for this, fbx
|
||||
// files can grow large, but the assimp output data structure
|
||||
// then becomes very large, too. Assimp doesn't support
|
||||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize() + 1);
|
||||
stream->Read(&*contents.begin(), 1, contents.size() - 1);
|
||||
contents[contents.size() - 1] = 0;
|
||||
const char *const begin = &*contents.begin();
|
||||
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens, begin, contents.size());
|
||||
} else {
|
||||
Tokenize(tokens, begin);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser, settings);
|
||||
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
|
||||
// Set FBX file scale is relative to CM must be converted to M for
|
||||
// assimp universal format (M)
|
||||
SetFileScale(size_relative_to_cm * 0.01f);
|
||||
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImporter.h
|
||||
* @brief Declaration of the FBX main importer class
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_IMPORTER_H
|
||||
#define INCLUDED_AI_FBX_IMPORTER_H
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/LogAux.h>
|
||||
|
||||
#include "FBXImportSettings.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
/** Load the Autodesk FBX file format.
|
||||
|
||||
See http://en.wikipedia.org/wiki/FBX
|
||||
*/
|
||||
// -------------------------------------------------------------------------------------------
|
||||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter>
|
||||
{
|
||||
public:
|
||||
FBXImporter();
|
||||
virtual ~FBXImporter();
|
||||
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
|
||||
private:
|
||||
FBX::ImportSettings settings;
|
||||
}; // !class FBXImporter
|
||||
|
||||
} // end of namespace Assimp
|
||||
#endif // !INCLUDED_AI_FBX_IMPORTER_H
|
||||
|
|
@ -1,405 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMaterial.cpp
|
||||
* @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
#include <assimp/ByteSwapper.h>
|
||||
|
||||
#include <algorithm> // std::transform
|
||||
#include "FBXUtil.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const ShadingModel = sc["ShadingModel"];
|
||||
const Element* const MultiLayer = sc["MultiLayer"];
|
||||
|
||||
if(MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
|
||||
}
|
||||
|
||||
if(ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not specified, assuming phong",&element);
|
||||
shading = "phong";
|
||||
}
|
||||
|
||||
std::string templateName;
|
||||
|
||||
// lower-case shading because Blender (for example) writes "Phong"
|
||||
std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower);
|
||||
if(shading == "phong") {
|
||||
templateName = "Material.FbxSurfacePhong";
|
||||
}
|
||||
else if(shading == "lambert") {
|
||||
templateName = "Material.FbxSurfaceLambert";
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not recognized: " + shading,&element);
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,templateName,element,sc);
|
||||
|
||||
// resolve texture links
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// texture link to properties, not objects
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
if(!tex) {
|
||||
const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
|
||||
if(!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop,&element);
|
||||
}
|
||||
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
((LayeredTexture*)layeredTexture)->fillTexture(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop,&element);
|
||||
}
|
||||
|
||||
textures[prop] = tex;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
, uvScaling(1.0f,1.0f)
|
||||
, media(0)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Type = sc["Type"];
|
||||
const Element* const FileName = sc["FileName"];
|
||||
const Element* const RelativeFilename = sc["RelativeFilename"];
|
||||
const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
|
||||
const Element* const ModelUVScaling = sc["ModelUVScaling"];
|
||||
const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
|
||||
const Element* const Cropping = sc["Cropping"];
|
||||
|
||||
if(Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(*Type,0));
|
||||
}
|
||||
|
||||
if(FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
|
||||
}
|
||||
|
||||
if(RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
|
||||
}
|
||||
|
||||
if(ModelUVTranslation) {
|
||||
uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
|
||||
);
|
||||
}
|
||||
|
||||
if(ModelUVScaling) {
|
||||
uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
|
||||
);
|
||||
}
|
||||
|
||||
if(Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
|
||||
}
|
||||
else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
|
||||
if(Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
|
||||
|
||||
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
|
||||
bool ok;
|
||||
const aiVector3D& scaling = PropertyGet<aiVector3D>(*props, "Scaling", ok);
|
||||
if (ok) {
|
||||
uvScaling.x = scaling.x;
|
||||
uvScaling.y = scaling.y;
|
||||
}
|
||||
|
||||
const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok);
|
||||
if (ok) {
|
||||
uvTrans.x = trans.x;
|
||||
uvTrans.y = trans.y;
|
||||
}
|
||||
|
||||
// resolve video links
|
||||
if(doc.Settings().readTextures) {
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for(const Connection* con : conns) {
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Video* const video = dynamic_cast<const Video*>(ob);
|
||||
if(video) {
|
||||
media = video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
,blendMode(BlendMode_Modulate)
|
||||
,alpha(1)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const BlendModes = sc["BlendModes"];
|
||||
const Element* const Alphas = sc["Alphas"];
|
||||
|
||||
|
||||
if(BlendModes!=0)
|
||||
{
|
||||
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
|
||||
}
|
||||
if(Alphas!=0)
|
||||
{
|
||||
alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::~LayeredTexture()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LayeredTexture::fillTexture(const Document& doc)
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for(size_t i = 0; i < conns.size();++i)
|
||||
{
|
||||
const Connection* con = conns.at(i);
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
|
||||
textures.push_back(tex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
, contentLength(0)
|
||||
, content(0)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Type = sc["Type"];
|
||||
const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows
|
||||
const Element* const RelativeFilename = sc["RelativeFilename"];
|
||||
const Element* const Content = sc["Content"];
|
||||
|
||||
if(Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(*Type,0));
|
||||
}
|
||||
|
||||
if(FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
|
||||
}
|
||||
|
||||
if(RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
|
||||
}
|
||||
|
||||
if(Content && !Content->Tokens().empty()) {
|
||||
//this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
|
||||
try {
|
||||
const Token& token = GetRequiredToken(*Content, 0);
|
||||
const char* data = token.begin();
|
||||
if (!token.IsBinary()) {
|
||||
if (*data != '"') {
|
||||
DOMError("embedded content is not surrounded by quotation marks", &element);
|
||||
}
|
||||
else {
|
||||
size_t targetLength = 0;
|
||||
auto numTokens = Content->Tokens().size();
|
||||
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
|
||||
{
|
||||
const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
|
||||
size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
|
||||
const char* base64data = dataToken.begin() + 1;
|
||||
const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
|
||||
if (outLength == 0)
|
||||
{
|
||||
DOMError("Corrupted embedded content found", &element);
|
||||
}
|
||||
targetLength += outLength;
|
||||
}
|
||||
if (targetLength == 0)
|
||||
{
|
||||
DOMError("Corrupted embedded content found", &element);
|
||||
}
|
||||
content = new uint8_t[targetLength];
|
||||
contentLength = static_cast<uint64_t>(targetLength);
|
||||
size_t dst_offset = 0;
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
|
||||
{
|
||||
const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
|
||||
size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
|
||||
const char* base64data = dataToken.begin() + 1;
|
||||
dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
|
||||
}
|
||||
if (targetLength != dst_offset)
|
||||
{
|
||||
delete[] content;
|
||||
contentLength = 0;
|
||||
DOMError("Corrupted embedded content found", &element);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (static_cast<size_t>(token.end() - data) < 5) {
|
||||
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
|
||||
}
|
||||
else if (*data != 'R') {
|
||||
DOMWarning("video content is not raw binary data, ignoring", &element);
|
||||
}
|
||||
else {
|
||||
// read number of elements
|
||||
uint32_t len = 0;
|
||||
::memcpy(&len, data + 1, sizeof(len));
|
||||
AI_SWAP4(len);
|
||||
|
||||
contentLength = len;
|
||||
|
||||
content = new uint8_t[len];
|
||||
::memcpy(content, data + 5, len);
|
||||
}
|
||||
} catch (const runtime_error& runtimeError)
|
||||
{
|
||||
//we don't need the content data for contents that has already been loaded
|
||||
ASSIMP_LOG_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
|
||||
runtimeError.what());
|
||||
}
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
|
||||
}
|
||||
|
||||
|
||||
Video::~Video()
|
||||
{
|
||||
if(content) {
|
||||
delete[] content;
|
||||
}
|
||||
}
|
||||
|
||||
} //!FBX
|
||||
} //!Assimp
|
||||
|
||||
#endif
|
|
@ -1,709 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMeshGeometry.cpp
|
||||
* @brief Assimp::FBX::MeshGeometry implementation
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element, name)
|
||||
, skin()
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
for(const Connection* con : conns) {
|
||||
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if(sk) {
|
||||
skin = sk;
|
||||
}
|
||||
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
|
||||
if (bsp) {
|
||||
blendShapes.push_back(bsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::~Geometry()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Skin* Geometry::DeformerSkin() const {
|
||||
return skin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element,name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
||||
}
|
||||
|
||||
// must have Mesh elements:
|
||||
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
|
||||
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
|
||||
|
||||
// optional Mesh elements:
|
||||
const ElementCollection& Layer = sc->GetCollection("Layer");
|
||||
|
||||
std::vector<aiVector3D> tempVerts;
|
||||
ParseVectorDataArray(tempVerts,Vertices);
|
||||
|
||||
if(tempVerts.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||
}
|
||||
|
||||
std::vector<int> tempFaces;
|
||||
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
|
||||
|
||||
if(tempFaces.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||
}
|
||||
|
||||
m_vertices.reserve(tempFaces.size());
|
||||
m_faces.reserve(tempFaces.size() / 3);
|
||||
|
||||
m_mapping_offsets.resize(tempVerts.size());
|
||||
m_mapping_counts.resize(tempVerts.size(),0);
|
||||
m_mappings.resize(tempFaces.size());
|
||||
|
||||
const size_t vertex_count = tempVerts.size();
|
||||
|
||||
// generate output vertices, computing an adjacency table to
|
||||
// preserve the mapping from fbx indices to *this* indexing.
|
||||
unsigned int count = 0;
|
||||
for(int index : tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
if(static_cast<size_t>(absi) >= vertex_count) {
|
||||
DOMError("polygon vertex index out of range",&PolygonVertexIndex);
|
||||
}
|
||||
|
||||
m_vertices.push_back(tempVerts[absi]);
|
||||
++count;
|
||||
|
||||
++m_mapping_counts[absi];
|
||||
|
||||
if (index < 0) {
|
||||
m_faces.push_back(count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int cursor = 0;
|
||||
for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
|
||||
m_mapping_offsets[i] = cursor;
|
||||
cursor += m_mapping_counts[i];
|
||||
|
||||
m_mapping_counts[i] = 0;
|
||||
}
|
||||
|
||||
cursor = 0;
|
||||
for(int index : tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++;
|
||||
}
|
||||
|
||||
// if settings.readAllLayers is true:
|
||||
// * read all layers, try to load as many vertex channels as possible
|
||||
// if settings.readAllLayers is false:
|
||||
// * read only the layer with index 0, but warn about any further layers
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const TokenList& tokens = (*it).second->Tokens();
|
||||
|
||||
const char* err;
|
||||
const int index = ParseTokenAsInt(*tokens[0], err);
|
||||
if(err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
if(doc.Settings().readAllLayers || index == 0) {
|
||||
const Scope& layer = GetRequiredScope(*(*it).second);
|
||||
ReadLayer(layer);
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("ignoring additional geometry layers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::~MeshGeometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
|
||||
return m_tangents;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
|
||||
return m_binormals;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
|
||||
return m_faces;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const {
|
||||
static const std::vector<aiVector2D> empty;
|
||||
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ];
|
||||
}
|
||||
|
||||
std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const {
|
||||
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ];
|
||||
}
|
||||
|
||||
const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const {
|
||||
static const std::vector<aiColor4D> empty;
|
||||
return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ];
|
||||
}
|
||||
|
||||
const MatIndexArray& MeshGeometry::GetMaterialIndices() const {
|
||||
return m_materials;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const {
|
||||
if ( in_index >= m_mapping_counts.size() ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() );
|
||||
count = m_mapping_counts[ in_index ];
|
||||
|
||||
ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() );
|
||||
|
||||
return &m_mappings[ m_mapping_offsets[ in_index ] ];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const {
|
||||
ai_assert( in_index < m_vertices.size() );
|
||||
|
||||
// in the current conversion pattern this will only be needed if
|
||||
// weights are present, so no need to always pre-compute this table
|
||||
if ( m_facesVertexStartIndices.empty() ) {
|
||||
m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 );
|
||||
|
||||
std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 );
|
||||
m_facesVertexStartIndices.pop_back();
|
||||
}
|
||||
|
||||
ai_assert( m_facesVertexStartIndices.size() == m_faces.size() );
|
||||
const std::vector<unsigned int>::iterator it = std::upper_bound(
|
||||
m_facesVertexStartIndices.begin(),
|
||||
m_facesVertexStartIndices.end(),
|
||||
in_index
|
||||
);
|
||||
|
||||
return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadLayer(const Scope& layer)
|
||||
{
|
||||
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
const Scope& elayer = GetRequiredScope(*(*eit).second);
|
||||
|
||||
ReadLayerElement(elayer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
||||
{
|
||||
const Element& Type = GetRequiredElement(layerElement,"Type");
|
||||
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
|
||||
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
|
||||
|
||||
const Scope& top = GetRequiredScope(element);
|
||||
const ElementCollection candidates = top.GetCollection(type);
|
||||
|
||||
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
|
||||
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
|
||||
if(index == typedIndex) {
|
||||
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
|
||||
<< type << ", index: " << typedIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
|
||||
{
|
||||
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"MappingInformationType"),0)
|
||||
);
|
||||
|
||||
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"ReferenceInformationType"),0)
|
||||
);
|
||||
|
||||
if (type == "LayerElementUV") {
|
||||
if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
|
||||
return;
|
||||
}
|
||||
|
||||
const Element* Name = source["Name"];
|
||||
m_uvNames[index] = "";
|
||||
if(Name) {
|
||||
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
|
||||
}
|
||||
|
||||
ReadVertexDataUV(m_uvs[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementMaterial") {
|
||||
if (m_materials.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional material layer");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> temp_materials;
|
||||
|
||||
ReadVertexDataMaterials(temp_materials,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
|
||||
// sometimes, there will be only negative entries. Drop the material
|
||||
// layer in such a case (I guess it means a default material should
|
||||
// be used). This is what the converter would do anyway, and it
|
||||
// avoids losing the material if there are more material layers
|
||||
// coming of which at least one contains actual data (did observe
|
||||
// that with one test file).
|
||||
const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
|
||||
if(count_neg == temp_materials.size()) {
|
||||
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
|
||||
return;
|
||||
}
|
||||
|
||||
std::swap(temp_materials, m_materials);
|
||||
}
|
||||
else if (type == "LayerElementNormal") {
|
||||
if (m_normals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional normal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataNormals(m_normals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementTangent") {
|
||||
if (m_tangents.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional tangent layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataTangents(m_tangents,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementBinormal") {
|
||||
if (m_binormals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional binormal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataBinormals(m_binormals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementColor") {
|
||||
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataColors(m_colors[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Lengthy utility function to read and resolve a FBX vertex data array - that is, the
|
||||
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
|
||||
// tangents ..
|
||||
template <typename T>
|
||||
void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType,
|
||||
const char* dataElementName,
|
||||
const char* indexDataElementName,
|
||||
size_t vertex_count,
|
||||
const std::vector<unsigned int>& mapping_counts,
|
||||
const std::vector<unsigned int>& mapping_offsets,
|
||||
const std::vector<unsigned int>& mappings)
|
||||
{
|
||||
bool isDirect = ReferenceInformationType == "Direct";
|
||||
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
|
||||
|
||||
// fall-back to direct data if there is no index data element
|
||||
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
|
||||
isDirect = true;
|
||||
isIndexToDirect = false;
|
||||
}
|
||||
|
||||
// handle permutations of Mapping and Reference type - it would be nice to
|
||||
// deal with this more elegantly and with less redundancy, but right
|
||||
// now it seems unavoidable.
|
||||
if (MappingInformationType == "ByVertice" && isDirect) {
|
||||
if (!HasElement(source, dataElementName)) {
|
||||
return;
|
||||
}
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
data_out.resize(vertex_count);
|
||||
for (size_t i = 0, e = tempData.size(); i < e; ++i) {
|
||||
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
data_out[mappings[j]] = tempData[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
data_out.resize(vertex_count);
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
|
||||
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
data_out[mappings[j]] = tempData[uvIndices[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
if (tempData.size() != vertex_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< tempData.size() << ", expected " << vertex_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
data_out.swap(tempData);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
data_out.resize(vertex_count);
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
|
||||
if (uvIndices.size() != vertex_count) {
|
||||
FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
|
||||
return;
|
||||
}
|
||||
|
||||
const T empty;
|
||||
unsigned int next = 0;
|
||||
for(int i : uvIndices) {
|
||||
if ( -1 == i ) {
|
||||
data_out[ next++ ] = empty;
|
||||
continue;
|
||||
}
|
||||
if (static_cast<size_t>(i) >= tempData.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
|
||||
data_out[next++] = tempData[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Normals",
|
||||
"NormalsIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"UV",
|
||||
"UVIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Colors",
|
||||
"ColorIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const char *TangentIndexToken = "TangentIndex";
|
||||
static const char *TangentsIndexToken = "TangentsIndex";
|
||||
|
||||
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
|
||||
const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
|
||||
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const std::string BinormalIndexToken = "BinormalIndex";
|
||||
static const std::string BinormalsIndexToken = "BinormalsIndex";
|
||||
|
||||
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
|
||||
const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
|
||||
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const size_t face_count = m_faces.size();
|
||||
if( 0 == face_count )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
// has a slightly different meaning for materials.
|
||||
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||
|
||||
if (MappingInformationType == "AllSame") {
|
||||
// easy - same material for all faces
|
||||
if (materials_out.empty()) {
|
||||
FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
|
||||
return;
|
||||
} else if (materials_out.size() > 1) {
|
||||
FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
|
||||
materials_out.clear();
|
||||
}
|
||||
|
||||
materials_out.resize(m_vertices.size());
|
||||
std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
|
||||
} else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
|
||||
materials_out.resize(face_count);
|
||||
|
||||
if(materials_out.size() != face_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< materials_out.size() << ", expected " << face_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element, name, doc) {
|
||||
const Scope *sc = element.Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
|
||||
const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
|
||||
const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element);
|
||||
ParseVectorDataArray(m_indices, Indexes);
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_normals, Normals);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::~ShapeGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int>& ShapeGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element, name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||
}
|
||||
const Element& Points = GetRequiredElement(*sc, "Points", &element);
|
||||
const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
|
||||
ParseVectorDataArray(m_vertices, Points);
|
||||
ParseVectorDataArray(m_indices, PointsIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::~LineGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& LineGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<int>& LineGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
#endif
|
||||
|
|
@ -1,235 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImporter.h
|
||||
* @brief Declaration of the FBX main importer class
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_MESHGEOMETRY_H
|
||||
#define INCLUDED_AI_FBX_MESHGEOMETRY_H
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
/**
|
||||
* DOM base class for all kinds of FBX geometry
|
||||
*/
|
||||
class Geometry : public Object
|
||||
{
|
||||
public:
|
||||
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||
virtual ~Geometry();
|
||||
|
||||
/** Get the Skin attached to this geometry or NULL */
|
||||
const Skin* DeformerSkin() const;
|
||||
|
||||
/** Get the BlendShape attached to this geometry or NULL */
|
||||
const std::vector<const BlendShape*>& GetBlendShapes() const;
|
||||
|
||||
private:
|
||||
const Skin* skin;
|
||||
std::vector<const BlendShape*> blendShapes;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
||||
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Mesh"
|
||||
*/
|
||||
class MeshGeometry : public Geometry
|
||||
{
|
||||
public:
|
||||
/** The class constructor */
|
||||
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~MeshGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<aiVector3D>& GetVertices() const;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
const std::vector<aiVector3D>& GetNormals() const;
|
||||
|
||||
/** Get a list of all vertex tangents or an empty array
|
||||
* if no tangents are specified */
|
||||
const std::vector<aiVector3D>& GetTangents() const;
|
||||
|
||||
/** Get a list of all vertex bi-normals or an empty array
|
||||
* if no bi-normals are specified */
|
||||
const std::vector<aiVector3D>& GetBinormals() const;
|
||||
|
||||
/** Return list of faces - each entry denotes a face and specifies
|
||||
* how many vertices it has. Vertices are taken from the
|
||||
* vertex data arrays in sequential order. */
|
||||
const std::vector<unsigned int>& GetFaceIndexCounts() const;
|
||||
|
||||
/** Get a UV coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const;
|
||||
|
||||
/** Get a UV coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
std::string GetTextureCoordChannelName( unsigned int index ) const;
|
||||
|
||||
/** Get a vertex color coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const;
|
||||
|
||||
/** Get per-face-vertex material assignments */
|
||||
const MatIndexArray& GetMaterialIndices() const;
|
||||
|
||||
/** Convert from a fbx file vertex index (for example from a #Cluster weight) or NULL
|
||||
* if the vertex index is not valid. */
|
||||
const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const;
|
||||
|
||||
/** Determine the face to which a particular output vertex index belongs.
|
||||
* This mapping is always unique. */
|
||||
unsigned int FaceForVertexIndex( unsigned int in_index ) const;
|
||||
private:
|
||||
void ReadLayer( const Scope& layer );
|
||||
void ReadLayerElement( const Scope& layerElement );
|
||||
void ReadVertexData( const std::string& type, int index, const Scope& source );
|
||||
|
||||
void ReadVertexDataUV( std::vector<aiVector2D>& uv_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
void ReadVertexDataNormals( std::vector<aiVector3D>& normals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
void ReadVertexDataColors( std::vector<aiColor4D>& colors_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
void ReadVertexDataTangents( std::vector<aiVector3D>& tangents_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
void ReadVertexDataBinormals( std::vector<aiVector3D>& binormals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
void ReadVertexDataMaterials( MatIndexArray& materials_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType );
|
||||
|
||||
private:
|
||||
// cached data arrays
|
||||
MatIndexArray m_materials;
|
||||
std::vector<aiVector3D> m_vertices;
|
||||
std::vector<unsigned int> m_faces;
|
||||
mutable std::vector<unsigned int> m_facesVertexStartIndices;
|
||||
std::vector<aiVector3D> m_tangents;
|
||||
std::vector<aiVector3D> m_binormals;
|
||||
std::vector<aiVector3D> m_normals;
|
||||
|
||||
std::string m_uvNames[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
||||
std::vector<aiVector2D> m_uvs[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
||||
std::vector<aiColor4D> m_colors[ AI_MAX_NUMBER_OF_COLOR_SETS ];
|
||||
|
||||
std::vector<unsigned int> m_mapping_counts;
|
||||
std::vector<unsigned int> m_mapping_offsets;
|
||||
std::vector<unsigned int> m_mappings;
|
||||
};
|
||||
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Shape"
|
||||
*/
|
||||
class ShapeGeometry : public Geometry
|
||||
{
|
||||
public:
|
||||
/** The class constructor */
|
||||
ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~ShapeGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<aiVector3D>& GetVertices() const;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
const std::vector<aiVector3D>& GetNormals() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<unsigned int>& GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<aiVector3D> m_vertices;
|
||||
std::vector<aiVector3D> m_normals;
|
||||
std::vector<unsigned int> m_indices;
|
||||
};
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Line"
|
||||
*/
|
||||
class LineGeometry : public Geometry
|
||||
{
|
||||
public:
|
||||
/** The class constructor */
|
||||
LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~LineGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<aiVector3D>& GetVertices() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<int>& GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<aiVector3D> m_vertices;
|
||||
std::vector<int> m_indices;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INCLUDED_AI_FBX_MESHGEOMETRY_H
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXModel.cpp
|
||||
* @brief Assimp::FBX::Model implementation
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
, shading("Y")
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const Shading = sc["Shading"];
|
||||
const Element* const Culling = sc["Culling"];
|
||||
|
||||
if(Shading) {
|
||||
shading = GetRequiredToken(*Shading,0).StringContents();
|
||||
}
|
||||
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
|
||||
ResolveLinks(element,doc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::~Model()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const Element& element, const Document& doc)
|
||||
{
|
||||
const char* const arr[] = {"Geometry","Material","NodeAttribute"};
|
||||
|
||||
// resolve material
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
|
||||
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
for(const Connection* con : conns) {
|
||||
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Material* const mat = dynamic_cast<const Material*>(ob);
|
||||
if(mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
|
||||
if(geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
|
||||
const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
|
||||
if(att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Model::IsNull() const
|
||||
{
|
||||
const std::vector<const NodeAttribute*>& attrs = GetAttributes();
|
||||
for(const NodeAttribute* att : attrs) {
|
||||
|
||||
const Null* null_tag = dynamic_cast<const Null*>(att);
|
||||
if(null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} //!FBX
|
||||
} //!Assimp
|
||||
|
||||
#endif
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
, props()
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
|
||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||
// the property table is by design absent and no warning should be generated
|
||||
// for it.
|
||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::~NodeAttribute()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const CameraId = sc["CameraId"];
|
||||
const Element* const CameraName = sc["CameraName"];
|
||||
const Element* const CameraIndexName = sc["CameraIndexName"];
|
||||
|
||||
if(CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
|
||||
}
|
||||
|
||||
if(CameraName) {
|
||||
cameraName = GetRequiredToken(*CameraName,0).StringContents();
|
||||
}
|
||||
|
||||
if(CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::~CameraSwitcher()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::~Camera()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::~Light()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::~Null()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::~LimbNode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,235 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXParser.h
|
||||
* @brief FBX parsing code
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_PARSER_H
|
||||
#define INCLUDED_AI_FBX_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <assimp/LogAux.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef std::vector< Scope* > ScopeList;
|
||||
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
|
||||
|
||||
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
# define new_Scope new Scope
|
||||
# define new_Element new Element
|
||||
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* AnimationCurve: 23, "AnimCurve::", "" {
|
||||
* [..]
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Element(const Token& key_token, Parser& parser);
|
||||
~Element();
|
||||
|
||||
const Scope* Compound() const {
|
||||
return compound.get();
|
||||
}
|
||||
|
||||
const Token& KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
|
||||
const TokenList& Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
const Token& key_token;
|
||||
TokenList tokens;
|
||||
std::unique_ptr<Scope> compound;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
* of not necessarily unique #Element instances.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* GlobalSettings: {
|
||||
* Version: 1000
|
||||
* Properties70:
|
||||
* [...]
|
||||
* }
|
||||
* @endverbatim */
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
Scope(Parser& parser, bool topLevel = false);
|
||||
~Scope();
|
||||
|
||||
const Element* operator[] (const std::string& index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? NULL : (*it).second;
|
||||
}
|
||||
|
||||
const Element* FindElementCaseInsensitive(const std::string& elementName) const {
|
||||
const char* elementNameCStr = elementName.c_str();
|
||||
for (auto element = elements.begin(); element != elements.end(); ++element)
|
||||
{
|
||||
if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) {
|
||||
return element->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ElementCollection GetCollection(const std::string& index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
|
||||
const ElementMap& Elements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementMap elements;
|
||||
};
|
||||
|
||||
/** FBX parsing class, takes a list of input tokens and generates a hierarchy
|
||||
* of nested #Scope instances, representing the fbx DOM.*/
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser (const TokenList& tokens,bool is_binary);
|
||||
~Parser();
|
||||
|
||||
const Scope& GetRootScope() const {
|
||||
return *root.get();
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
||||
TokenPtr AdvanceToNextToken();
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
|
||||
private:
|
||||
const TokenList& tokens;
|
||||
|
||||
TokenPtr last, current;
|
||||
TokenList::const_iterator cursor;
|
||||
std::unique_ptr<Scope> root;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
||||
|
||||
/* token parsing - this happens when building the DOM out of the parse-tree*/
|
||||
uint64_t ParseTokenAsID(const Token& t, const char*& err_out);
|
||||
size_t ParseTokenAsDim(const Token& t, const char*& err_out);
|
||||
|
||||
float ParseTokenAsFloat(const Token& t, const char*& err_out);
|
||||
int ParseTokenAsInt(const Token& t, const char*& err_out);
|
||||
int64_t ParseTokenAsInt64(const Token& t, const char*& err_out);
|
||||
std::string ParseTokenAsString(const Token& t, const char*& err_out);
|
||||
|
||||
/* wrapper around ParseTokenAsXXX() with DOMError handling */
|
||||
uint64_t ParseTokenAsID(const Token& t);
|
||||
size_t ParseTokenAsDim(const Token& t);
|
||||
float ParseTokenAsFloat(const Token& t);
|
||||
int ParseTokenAsInt(const Token& t);
|
||||
int64_t ParseTokenAsInt64(const Token& t);
|
||||
std::string ParseTokenAsString(const Token& t);
|
||||
|
||||
/* read data arrays */
|
||||
void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<int>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<float>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
||||
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
|
||||
void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
|
||||
|
||||
bool HasElement( const Scope& sc, const std::string& index );
|
||||
|
||||
// extract a required element from a scope, abort if the element cannot be found
|
||||
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
|
||||
|
||||
// extract required compound scope
|
||||
const Scope& GetRequiredScope(const Element& el);
|
||||
// get token at a particular index
|
||||
const Token& GetRequiredToken(const Element& el, unsigned int index);
|
||||
|
||||
// read a 4x4 matrix from an array of 16 floats
|
||||
aiMatrix4x4 ReadMatrix(const Element& element);
|
||||
|
||||
} // ! FBX
|
||||
} // ! Assimp
|
||||
|
||||
#endif // ! INCLUDED_AI_FBX_PARSER_H
|
|
@ -1,235 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.cpp
|
||||
* @brief Implementation of the FBX dynamic properties system
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::Property()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::~Property()
|
||||
{
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
|
||||
Property* ReadTypedProperty(const Element& element)
|
||||
{
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
|
||||
const TokenList& tok = element.Tokens();
|
||||
ai_assert(tok.size() >= 5);
|
||||
|
||||
const std::string& s = ParseTokenAsString(*tok[1]);
|
||||
const char* const cs = s.c_str();
|
||||
if (!strcmp(cs,"KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
|
||||
}
|
||||
else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"Vector3D") ||
|
||||
!strcmp(cs,"ColorRGB") ||
|
||||
!strcmp(cs,"Vector") ||
|
||||
!strcmp(cs,"Color") ||
|
||||
!strcmp(cs,"Lcl Translation") ||
|
||||
!strcmp(cs,"Lcl Rotation") ||
|
||||
!strcmp(cs,"Lcl Scaling")
|
||||
) {
|
||||
return new TypedProperty<aiVector3D>(aiVector3D(
|
||||
ParseTokenAsFloat(*tok[4]),
|
||||
ParseTokenAsFloat(*tok[5]),
|
||||
ParseTokenAsFloat(*tok[6]))
|
||||
);
|
||||
}
|
||||
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// peek into an element and check if it contains a FBX property, if so return its name.
|
||||
std::string PeekPropertyName(const Element& element)
|
||||
{
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList& tok = element.Tokens();
|
||||
if(tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ParseTokenAsString(*tok[0]);
|
||||
}
|
||||
|
||||
} //! anon
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable()
|
||||
: templateProps()
|
||||
, element()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps)
|
||||
: templateProps(templateProps)
|
||||
, element(&element)
|
||||
{
|
||||
const Scope& scope = GetRequiredScope(element);
|
||||
for(const ElementMap::value_type& v : scope.Elements()) {
|
||||
if(v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table",v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& name = PeekPropertyName(*v.second);
|
||||
if(!name.length()) {
|
||||
DOMWarning("could not read property name",v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::~PropertyTable()
|
||||
{
|
||||
for(PropertyMap::value_type& v : props) {
|
||||
delete v.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Property* PropertyTable::Get(const std::string& name) const
|
||||
{
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if(lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(*(*lit).second);
|
||||
it = props.find(name);
|
||||
|
||||
ai_assert(it != props.end());
|
||||
}
|
||||
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
if(templateProps) {
|
||||
return templateProps->Get(name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
DirectPropertyMap PropertyTable::GetUnparsedProperties() const
|
||||
{
|
||||
DirectPropertyMap result;
|
||||
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
for(const LazyPropertyMap::value_type& element : lazyProps) {
|
||||
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) continue;
|
||||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*element.second));
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) continue;
|
||||
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} //! FBX
|
||||
} //! Assimp
|
||||
|
||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.h
|
||||
* @brief FBX dynamic properties
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_PROPERTIES_H
|
||||
#define INCLUDED_AI_FBX_PROPERTIES_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
// Forward declarations
|
||||
class Element;
|
||||
|
||||
/** Represents a dynamic property. Type info added by deriving classes,
|
||||
* see #TypedProperty.
|
||||
Example:
|
||||
@verbatim
|
||||
P: "ShininessExponent", "double", "Number", "",0.5
|
||||
@endvebatim
|
||||
*/
|
||||
class Property {
|
||||
protected:
|
||||
Property();
|
||||
|
||||
public:
|
||||
virtual ~Property();
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
const T* As() const {
|
||||
return dynamic_cast<const T*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class TypedProperty : public Property {
|
||||
public:
|
||||
explicit TypedProperty(const T& value)
|
||||
: value(value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
const T& Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
|
||||
typedef std::fbx_unordered_map<std::string,std::shared_ptr<Property> > DirectPropertyMap;
|
||||
typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap;
|
||||
typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap;
|
||||
|
||||
/**
|
||||
* Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
|
||||
*/
|
||||
class PropertyTable {
|
||||
public:
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps);
|
||||
~PropertyTable();
|
||||
|
||||
const Property* Get(const std::string& name) const;
|
||||
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
const Element* GetElement() const {
|
||||
return element;
|
||||
}
|
||||
|
||||
const PropertyTable* TemplateProps() const {
|
||||
return templateProps.get();
|
||||
}
|
||||
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
|
||||
private:
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
const std::shared_ptr<const PropertyTable> templateProps;
|
||||
const Element* const element;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
|
||||
const Property* const prop = in.Get(name);
|
||||
if( nullptr == prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if( nullptr == tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
|
||||
const Property* prop = in.Get(name);
|
||||
if( nullptr == prop) {
|
||||
if ( ! useTemplate ) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
const PropertyTable* templ = in.TemplateProps();
|
||||
if ( nullptr == templ ) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
prop = templ->Get(name);
|
||||
if ( nullptr == prop ) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if( nullptr == tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
} //! FBX
|
||||
} //! Assimp
|
||||
|
||||
#endif // INCLUDED_AI_FBX_PROPERTIES_H
|
|
@ -1,248 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.cpp
|
||||
* @brief Implementation of the FBX broadphase lexer
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
// tab width for logging columns
|
||||
#define ASSIMP_FBX_TAB_WIDTH 4
|
||||
|
||||
#include <assimp/ParsingUtils.h>
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXUtil.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column)
|
||||
:
|
||||
#ifdef DEBUG
|
||||
contents(sbegin, static_cast<size_t>(send-sbegin)),
|
||||
#endif
|
||||
sbegin(sbegin)
|
||||
, send(send)
|
||||
, type(type)
|
||||
, line(line)
|
||||
, column(column)
|
||||
{
|
||||
ai_assert(sbegin);
|
||||
ai_assert(send);
|
||||
|
||||
// tokens must be of non-zero length
|
||||
ai_assert(static_cast<size_t>(send-sbegin) > 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::~Token()
|
||||
{
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
|
||||
{
|
||||
throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column));
|
||||
}
|
||||
|
||||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
bool must_have_token = false)
|
||||
{
|
||||
if (start && end) {
|
||||
// sanity check:
|
||||
// tokens should have no whitespace outside quoted text and [start,end] should
|
||||
// properly delimit the valid range.
|
||||
bool in_double_quotes = false;
|
||||
for (const char* c = start; c != end + 1; ++c) {
|
||||
if (*c == '\"') {
|
||||
in_double_quotes = !in_double_quotes;
|
||||
}
|
||||
|
||||
if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
|
||||
TokenizeError("unexpected whitespace in token", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
TokenizeError("non-terminated double quotes", line, column);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(start,end + 1,type,line,column));
|
||||
}
|
||||
else if (must_have_token) {
|
||||
TokenizeError("unexpected character, expected data token", line, column);
|
||||
}
|
||||
|
||||
start = end = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList& output_tokens, const char* input)
|
||||
{
|
||||
ai_assert(input);
|
||||
|
||||
// line and column numbers numbers are one-based
|
||||
unsigned int line = 1;
|
||||
unsigned int column = 1;
|
||||
|
||||
bool comment = false;
|
||||
bool in_double_quotes = false;
|
||||
bool pending_data_token = false;
|
||||
|
||||
const char* token_begin = NULL, *token_end = NULL;
|
||||
for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) {
|
||||
const char c = *cur;
|
||||
|
||||
if (IsLineEnd(c)) {
|
||||
comment = false;
|
||||
|
||||
column = 0;
|
||||
++line;
|
||||
}
|
||||
|
||||
if(comment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(in_double_quotes) {
|
||||
if (c == '\"') {
|
||||
in_double_quotes = false;
|
||||
token_end = cur;
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
pending_data_token = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '\"':
|
||||
if (token_begin) {
|
||||
TokenizeError("unexpected double-quote", line, column);
|
||||
}
|
||||
token_begin = cur;
|
||||
in_double_quotes = true;
|
||||
continue;
|
||||
|
||||
case ';':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
comment = true;
|
||||
continue;
|
||||
|
||||
case '{':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case ',':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true);
|
||||
}
|
||||
else {
|
||||
TokenizeError("unexpected colon", line, column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsSpaceOrNewLine(c)) {
|
||||
|
||||
if (token_begin) {
|
||||
// peek ahead and check if the next token is a colon in which
|
||||
// case this counts as KEY token.
|
||||
TokenType type = TokenType_DATA;
|
||||
for (const char* peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) {
|
||||
if (*peek == ':') {
|
||||
type = TokenType_KEY;
|
||||
cur = peek;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,type);
|
||||
}
|
||||
|
||||
pending_data_token = false;
|
||||
}
|
||||
else {
|
||||
token_end = cur;
|
||||
if (!token_begin) {
|
||||
token_begin = cur;
|
||||
}
|
||||
|
||||
pending_data_token = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.h
|
||||
* @brief FBX lexer
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_TOKENIZER_H
|
||||
#define INCLUDED_AI_FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
/** Rough classification for text FBX tokens used for constructing the
|
||||
* basic scope hierarchy. */
|
||||
enum TokenType
|
||||
{
|
||||
// {
|
||||
TokenType_OPEN_BRACKET = 0,
|
||||
|
||||
// }
|
||||
TokenType_CLOSE_BRACKET,
|
||||
|
||||
// '"blablubb"', '2', '*14' - very general token class,
|
||||
// further processing happens at a later stage.
|
||||
TokenType_DATA,
|
||||
|
||||
//
|
||||
TokenType_BINARY_DATA,
|
||||
|
||||
// ,
|
||||
TokenType_COMMA,
|
||||
|
||||
// blubb:
|
||||
TokenType_KEY
|
||||
};
|
||||
|
||||
|
||||
/** Represents a single token in a FBX file. Tokens are
|
||||
* classified by the #TokenType enumerated types.
|
||||
*
|
||||
* Offers iterator protocol. Tokens are immutable. */
|
||||
class Token
|
||||
{
|
||||
private:
|
||||
static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
|
||||
|
||||
public:
|
||||
/** construct a textual token */
|
||||
Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column);
|
||||
|
||||
/** construct a binary token */
|
||||
Token(const char* sbegin, const char* send, TokenType type, size_t offset);
|
||||
|
||||
~Token();
|
||||
|
||||
public:
|
||||
std::string StringContents() const {
|
||||
return std::string(begin(),end());
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return column == BINARY_MARKER;
|
||||
}
|
||||
|
||||
const char* begin() const {
|
||||
return sbegin;
|
||||
}
|
||||
|
||||
const char* end() const {
|
||||
return send;
|
||||
}
|
||||
|
||||
TokenType Type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
size_t Offset() const {
|
||||
ai_assert(IsBinary());
|
||||
return offset;
|
||||
}
|
||||
|
||||
unsigned int Line() const {
|
||||
ai_assert(!IsBinary());
|
||||
return static_cast<unsigned int>(line);
|
||||
}
|
||||
|
||||
unsigned int Column() const {
|
||||
ai_assert(!IsBinary());
|
||||
return column;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef DEBUG
|
||||
// full string copy for the sole purpose that it nicely appears
|
||||
// in msvc's debugger window.
|
||||
const std::string contents;
|
||||
#endif
|
||||
|
||||
|
||||
const char* const sbegin;
|
||||
const char* const send;
|
||||
const TokenType type;
|
||||
|
||||
union {
|
||||
size_t line;
|
||||
size_t offset;
|
||||
};
|
||||
const unsigned int column;
|
||||
};
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef const Token* TokenPtr;
|
||||
typedef std::vector< TokenPtr > TokenList;
|
||||
|
||||
#define new_Token new Token
|
||||
|
||||
|
||||
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
|
||||
*
|
||||
* Skips over comments and generates line and column numbers.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void Tokenize(TokenList& output_tokens, const char* input);
|
||||
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
*
|
||||
* Emits a token list suitable for direct parsing.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
|
||||
|
||||
|
||||
} // ! FBX
|
||||
} // ! Assimp
|
||||
|
||||
#endif // ! INCLUDED_AI_FBX_PARSER_H
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.cpp
|
||||
* @brief Implementation of internal FBX utility functions
|
||||
*/
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
namespace Util {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char* TokenTypeString(TokenType t)
|
||||
{
|
||||
switch(t) {
|
||||
case TokenType_OPEN_BRACKET:
|
||||
return "TOK_OPEN_BRACKET";
|
||||
|
||||
case TokenType_CLOSE_BRACKET:
|
||||
return "TOK_CLOSE_BRACKET";
|
||||
|
||||
case TokenType_DATA:
|
||||
return "TOK_DATA";
|
||||
|
||||
case TokenType_COMMA:
|
||||
return "TOK_COMMA";
|
||||
|
||||
case TokenType_KEY:
|
||||
return "TOK_KEY";
|
||||
|
||||
case TokenType_BINARY_DATA:
|
||||
return "TOK_BINARY_DATA";
|
||||
}
|
||||
|
||||
ai_assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset)
|
||||
{
|
||||
return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column)
|
||||
{
|
||||
return static_cast<std::string>( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok)
|
||||
{
|
||||
if(tok->IsBinary()) {
|
||||
return static_cast<std::string>( (Formatter::format() << prefix <<
|
||||
" (" << TokenTypeString(tok->Type()) <<
|
||||
", offset 0x" << std::hex << tok->Offset() << ") " <<
|
||||
text) );
|
||||
}
|
||||
|
||||
return static_cast<std::string>( (Formatter::format() << prefix <<
|
||||
" (" << TokenTypeString(tok->Type()) <<
|
||||
", line " << tok->Line() <<
|
||||
", col " << tok->Column() << ") " <<
|
||||
text) );
|
||||
}
|
||||
|
||||
// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
static const uint8_t base64DecodeTable[128] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
|
||||
uint8_t DecodeBase64(char ch)
|
||||
{
|
||||
const auto idx = static_cast<uint8_t>(ch);
|
||||
if (idx > 127)
|
||||
return 255;
|
||||
return base64DecodeTable[idx];
|
||||
}
|
||||
|
||||
size_t ComputeDecodedSizeBase64(const char* in, size_t inLength)
|
||||
{
|
||||
if (inLength < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
|
||||
const size_t full_length = (inLength * 3) >> 2; // div by 4
|
||||
if (full_length < equals)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return full_length - equals;
|
||||
}
|
||||
|
||||
size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength)
|
||||
{
|
||||
if (maxOutLength == 0 || inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
|
||||
size_t dst_offset = 0;
|
||||
int val = 0, valb = -8;
|
||||
for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
|
||||
{
|
||||
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
|
||||
if (table_value == 255)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
val = (val << 6) + table_value;
|
||||
valb += 6;
|
||||
if (valb >= 0)
|
||||
{
|
||||
out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
|
||||
valb -= 8;
|
||||
val &= 0xFFF;
|
||||
}
|
||||
}
|
||||
return dst_offset;
|
||||
}
|
||||
|
||||
static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
char EncodeBase64(char byte)
|
||||
{
|
||||
return to_base64_string[(size_t)byte];
|
||||
}
|
||||
|
||||
/** Encodes a block of 4 bytes to base64 encoding
|
||||
*
|
||||
* @param bytes Bytes to encode.
|
||||
* @param out_string String to write encoded values to.
|
||||
* @param string_pos Position in out_string.*/
|
||||
void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos)
|
||||
{
|
||||
char b0 = (bytes[0] & 0xFC) >> 2;
|
||||
char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
|
||||
char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
|
||||
char b3 = (bytes[2] & 0x3F);
|
||||
|
||||
out_string[string_pos + 0] = EncodeBase64(b0);
|
||||
out_string[string_pos + 1] = EncodeBase64(b1);
|
||||
out_string[string_pos + 2] = EncodeBase64(b2);
|
||||
out_string[string_pos + 3] = EncodeBase64(b3);
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const char* data, size_t length)
|
||||
{
|
||||
// calculate extra bytes needed to get a multiple of 3
|
||||
size_t extraBytes = 3 - length % 3;
|
||||
|
||||
// number of base64 bytes
|
||||
size_t encodedBytes = 4 * (length + extraBytes) / 3;
|
||||
|
||||
std::string encoded_string(encodedBytes, '=');
|
||||
|
||||
// read blocks of 3 bytes
|
||||
for (size_t ib3 = 0; ib3 < length / 3; ib3++)
|
||||
{
|
||||
const size_t iByte = ib3 * 3;
|
||||
const size_t iEncodedByte = ib3 * 4;
|
||||
const char* currData = &data[iByte];
|
||||
|
||||
EncodeByteBlock(currData, encoded_string, iEncodedByte);
|
||||
}
|
||||
|
||||
// if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
|
||||
if (extraBytes > 0)
|
||||
{
|
||||
char finalBytes[4] = { 0,0,0,0 };
|
||||
memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
|
||||
|
||||
const size_t iEncodedByte = encodedBytes - 4;
|
||||
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
|
||||
|
||||
// add '=' at the end
|
||||
for (size_t i = 0; i < 4 * extraBytes / 3; i++)
|
||||
encoded_string[encodedBytes - i - 1] = '=';
|
||||
}
|
||||
return encoded_string;
|
||||
}
|
||||
|
||||
} // !Util
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.h
|
||||
* @brief FBX utility functions for internal use
|
||||
*/
|
||||
#ifndef INCLUDED_AI_FBX_UTIL_H
|
||||
#define INCLUDED_AI_FBX_UTIL_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
|
||||
namespace Util {
|
||||
|
||||
|
||||
/** helper for std::for_each to delete all heap-allocated items in a container */
|
||||
template<typename T>
|
||||
struct delete_fun
|
||||
{
|
||||
void operator()(const volatile T* del) {
|
||||
delete del;
|
||||
}
|
||||
};
|
||||
|
||||
/** Get a string representation for a #TokenType. */
|
||||
const char* TokenTypeString(TokenType t);
|
||||
|
||||
|
||||
|
||||
/** Format log/error messages using a given offset in the source binary file
|
||||
*
|
||||
* @param prefix Message prefix to be preprended to the location info.
|
||||
* @param text Message text
|
||||
* @param line Line index, 1-based
|
||||
* @param column Column index, 1-based
|
||||
* @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
|
||||
std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
|
||||
|
||||
|
||||
/** Format log/error messages using a given line location in the source file.
|
||||
*
|
||||
* @param prefix Message prefix to be preprended to the location info.
|
||||
* @param text Message text
|
||||
* @param line Line index, 1-based
|
||||
* @param column Column index, 1-based
|
||||
* @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/
|
||||
std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column);
|
||||
|
||||
|
||||
/** Format log/error messages using a given cursor token.
|
||||
*
|
||||
* @param prefix Message prefix to be preprended to the location info.
|
||||
* @param text Message text
|
||||
* @param tok Token where parsing/processing stopped
|
||||
* @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/
|
||||
std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok);
|
||||
|
||||
/** Decode a single Base64-encoded character.
|
||||
*
|
||||
* @param ch Character to decode (from base64 to binary).
|
||||
* @return decoded byte value*/
|
||||
uint8_t DecodeBase64(char ch);
|
||||
|
||||
/** Compute decoded size of a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
|
||||
|
||||
/** Decode a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @param out Pointer where we will store the decoded data.
|
||||
* @param maxOutLength Size of output buffer.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength);
|
||||
|
||||
char EncodeBase64(char byte);
|
||||
|
||||
/** Encode bytes in base64-encoding
|
||||
*
|
||||
* @param data Binary data to encode.
|
||||
* @param inLength Number of bytes to encode.
|
||||
* @return base64-encoded string*/
|
||||
std::string EncodeBase64(const char* data, size_t length);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ! INCLUDED_AI_FBX_UTIL_H
|
|
@ -1,632 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file MaterialSystem.cpp
|
||||
* @brief Implementation of the material system of the library
|
||||
*/
|
||||
|
||||
#include <assimp/Hash.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include "MaterialSystem.h"
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a specific property from a material
|
||||
aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
const aiMaterialProperty** pPropOut)
|
||||
{
|
||||
ai_assert( pMat != NULL );
|
||||
ai_assert( pKey != NULL );
|
||||
ai_assert( pPropOut != NULL );
|
||||
|
||||
/* Just search for a property with exactly this name ..
|
||||
* could be improved by hashing, but it's possibly
|
||||
* no worth the effort (we're bound to C structures,
|
||||
* thus std::map or derivates are not applicable. */
|
||||
for ( unsigned int i = 0; i < pMat->mNumProperties; ++i ) {
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
|
||||
if (prop /* just for safety ... */
|
||||
&& 0 == strcmp( prop->mKey.data, pKey )
|
||||
&& (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */
|
||||
&& (UINT_MAX == index || prop->mIndex == index))
|
||||
{
|
||||
*pPropOut = pMat->mProperties[i];
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
*pPropOut = NULL;
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get an array of floating-point values from the material.
|
||||
aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
ai_real* pOut,
|
||||
unsigned int* pMax)
|
||||
{
|
||||
ai_assert( pOut != nullptr );
|
||||
ai_assert( pMat != nullptr );
|
||||
|
||||
const aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop);
|
||||
if ( nullptr == prop) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// data is given in floats, convert to ai_real
|
||||
unsigned int iWrite = 0;
|
||||
if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
|
||||
iWrite = prop->mDataLength / sizeof(float);
|
||||
if (pMax) {
|
||||
iWrite = std::min(*pMax,iWrite); ;
|
||||
}
|
||||
|
||||
for (unsigned int a = 0; a < iWrite; ++a) {
|
||||
pOut[ a ] = static_cast<ai_real> ( reinterpret_cast<float*>(prop->mData)[a] );
|
||||
}
|
||||
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
// data is given in doubles, convert to float
|
||||
else if( aiPTI_Double == prop->mType) {
|
||||
iWrite = prop->mDataLength / sizeof(double);
|
||||
if (pMax) {
|
||||
iWrite = std::min(*pMax,iWrite); ;
|
||||
}
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = static_cast<ai_real> ( reinterpret_cast<double*>(prop->mData)[a] );
|
||||
}
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
// data is given in ints, convert to float
|
||||
else if( aiPTI_Integer == prop->mType) {
|
||||
iWrite = prop->mDataLength / sizeof(int32_t);
|
||||
if (pMax) {
|
||||
iWrite = std::min(*pMax,iWrite); ;
|
||||
}
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = static_cast<ai_real> ( reinterpret_cast<int32_t*>(prop->mData)[a] );
|
||||
}
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
// a string ... read floats separated by spaces
|
||||
else {
|
||||
if (pMax) {
|
||||
iWrite = *pMax;
|
||||
}
|
||||
// strings are zero-terminated with a 32 bit length prefix, so this is safe
|
||||
const char *cur = prop->mData + 4;
|
||||
ai_assert( prop->mDataLength >= 5 );
|
||||
ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
|
||||
for ( unsigned int a = 0; ;++a) {
|
||||
cur = fast_atoreal_move<ai_real>(cur,pOut[a]);
|
||||
if ( a==iWrite-1 ) {
|
||||
break;
|
||||
}
|
||||
if ( !IsSpace(*cur) ) {
|
||||
ASSIMP_LOG_ERROR("Material property" + std::string(pKey) +
|
||||
" is a string; failed to parse a float array out of it.");
|
||||
return AI_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get an array if integers from the material
|
||||
aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
int* pOut,
|
||||
unsigned int* pMax)
|
||||
{
|
||||
ai_assert( pOut != NULL );
|
||||
ai_assert( pMat != NULL );
|
||||
|
||||
const aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop);
|
||||
if (!prop) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// data is given in ints, simply copy it
|
||||
unsigned int iWrite = 0;
|
||||
if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
|
||||
iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
|
||||
if (pMax) {
|
||||
iWrite = std::min(*pMax,iWrite);
|
||||
}
|
||||
if (1 == prop->mDataLength) {
|
||||
// bool type, 1 byte
|
||||
*pOut = static_cast<int>(*prop->mData);
|
||||
}
|
||||
else {
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = static_cast<int>(reinterpret_cast<int32_t*>(prop->mData)[a]);
|
||||
}
|
||||
}
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
// data is given in floats convert to int
|
||||
else if( aiPTI_Float == prop->mType) {
|
||||
iWrite = prop->mDataLength / sizeof(float);
|
||||
if (pMax) {
|
||||
iWrite = std::min(*pMax,iWrite); ;
|
||||
}
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = static_cast<int>(reinterpret_cast<float*>(prop->mData)[a]);
|
||||
}
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
// it is a string ... no way to read something out of this
|
||||
else {
|
||||
if (pMax) {
|
||||
iWrite = *pMax;
|
||||
}
|
||||
// strings are zero-terminated with a 32 bit length prefix, so this is safe
|
||||
const char *cur = prop->mData+4;
|
||||
ai_assert( prop->mDataLength >= 5 );
|
||||
ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
|
||||
for (unsigned int a = 0; ;++a) {
|
||||
pOut[a] = strtol10(cur,&cur);
|
||||
if(a==iWrite-1) {
|
||||
break;
|
||||
}
|
||||
if(!IsSpace(*cur)) {
|
||||
ASSIMP_LOG_ERROR("Material property" + std::string(pKey) +
|
||||
" is a string; failed to parse an integer array out of it.");
|
||||
return AI_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pMax) {
|
||||
*pMax = iWrite;
|
||||
}
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a color (3 or 4 floats) from the material
|
||||
aiReturn aiGetMaterialColor(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiColor4D* pOut)
|
||||
{
|
||||
unsigned int iMax = 4;
|
||||
const aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
|
||||
|
||||
// if no alpha channel is defined: set it to 1.0
|
||||
if (3 == iMax) {
|
||||
pOut->a = 1.0;
|
||||
}
|
||||
|
||||
return eRet;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a aiUVTransform (4 floats) from the material
|
||||
aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiUVTransform* pOut)
|
||||
{
|
||||
unsigned int iMax = 4;
|
||||
return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a string from the material
|
||||
aiReturn aiGetMaterialString(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiString* pOut)
|
||||
{
|
||||
ai_assert (pOut != NULL);
|
||||
|
||||
const aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop);
|
||||
if (!prop) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
if( aiPTI_String == prop->mType) {
|
||||
ai_assert(prop->mDataLength>=5);
|
||||
|
||||
// The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
|
||||
pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t*>(prop->mData));
|
||||
|
||||
ai_assert( pOut->length+1+4==prop->mDataLength );
|
||||
ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
|
||||
memcpy(pOut->data,prop->mData+4,pOut->length+1);
|
||||
}
|
||||
else {
|
||||
// TODO - implement lexical cast as well
|
||||
ASSIMP_LOG_ERROR("Material property" + std::string(pKey) +
|
||||
" was found, but is no string" );
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the number of textures on a particular texture stack
|
||||
unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat,
|
||||
C_ENUM aiTextureType type)
|
||||
{
|
||||
ai_assert (pMat != NULL);
|
||||
|
||||
// Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again)
|
||||
unsigned int max = 0;
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
|
||||
if ( prop /* just a sanity check ... */
|
||||
&& 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE )
|
||||
&& prop->mSemantic == type) {
|
||||
|
||||
max = std::max(max,prop->mIndex+1);
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
|
||||
aiTextureType type,
|
||||
unsigned int index,
|
||||
C_STRUCT aiString* path,
|
||||
aiTextureMapping* _mapping /*= NULL*/,
|
||||
unsigned int* uvindex /*= NULL*/,
|
||||
ai_real* blend /*= NULL*/,
|
||||
aiTextureOp* op /*= NULL*/,
|
||||
aiTextureMapMode* mapmode /*= NULL*/,
|
||||
unsigned int* flags /*= NULL*/
|
||||
)
|
||||
{
|
||||
ai_assert( NULL != mat );
|
||||
ai_assert( NULL != path );
|
||||
|
||||
// Get the path to the texture
|
||||
if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path)) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// Determine mapping type
|
||||
int mapping_ = static_cast<int>(aiTextureMapping_UV);
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_);
|
||||
aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
|
||||
if (_mapping)
|
||||
*_mapping = mapping;
|
||||
|
||||
// Get UV index
|
||||
if (aiTextureMapping_UV == mapping && uvindex) {
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex);
|
||||
}
|
||||
// Get blend factor
|
||||
if (blend) {
|
||||
aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend);
|
||||
}
|
||||
// Get texture operation
|
||||
if (op){
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op);
|
||||
}
|
||||
// Get texture mapping modes
|
||||
if (mapmode) {
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]);
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]);
|
||||
}
|
||||
// Get texture flags
|
||||
if (flags){
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags);
|
||||
}
|
||||
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static const unsigned int DefaultNumAllocated = 5;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construction. Actually the one and only way to get an aiMaterial instance
|
||||
aiMaterial::aiMaterial()
|
||||
: mProperties( nullptr )
|
||||
, mNumProperties( 0 )
|
||||
, mNumAllocated( DefaultNumAllocated ) {
|
||||
// Allocate 5 entries by default
|
||||
mProperties = new aiMaterialProperty*[ DefaultNumAllocated ];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMaterial::~aiMaterial()
|
||||
{
|
||||
Clear();
|
||||
|
||||
delete[] mProperties;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiString aiMaterial::GetName() {
|
||||
aiString name;
|
||||
Get(AI_MATKEY_NAME, name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void aiMaterial::Clear()
|
||||
{
|
||||
for ( unsigned int i = 0; i < mNumProperties; ++i ) {
|
||||
// delete this entry
|
||||
delete mProperties[ i ];
|
||||
AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
|
||||
}
|
||||
mNumProperties = 0;
|
||||
|
||||
// The array remains allocated, we just invalidated its contents
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiMaterial::RemoveProperty ( const char* pKey,unsigned int type, unsigned int index )
|
||||
{
|
||||
ai_assert( nullptr != pKey );
|
||||
|
||||
for (unsigned int i = 0; i < mNumProperties;++i) {
|
||||
aiMaterialProperty* prop = mProperties[i];
|
||||
|
||||
if (prop && !strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index)
|
||||
{
|
||||
// Delete this entry
|
||||
delete mProperties[i];
|
||||
|
||||
// collapse the array behind --.
|
||||
--mNumProperties;
|
||||
for (unsigned int a = i; a < mNumProperties;++a) {
|
||||
mProperties[a] = mProperties[a+1];
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
|
||||
unsigned int pSizeInBytes,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiPropertyTypeInfo pType
|
||||
)
|
||||
{
|
||||
ai_assert( pInput != NULL );
|
||||
ai_assert( pKey != NULL );
|
||||
ai_assert( 0 != pSizeInBytes );
|
||||
|
||||
if ( 0 == pSizeInBytes ) {
|
||||
|
||||
}
|
||||
|
||||
// first search the list whether there is already an entry with this key
|
||||
unsigned int iOutIndex( UINT_MAX );
|
||||
for ( unsigned int i = 0; i < mNumProperties; ++i ) {
|
||||
aiMaterialProperty *prop( mProperties[ i ] );
|
||||
|
||||
if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index){
|
||||
|
||||
delete mProperties[i];
|
||||
iOutIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new material property
|
||||
aiMaterialProperty* pcNew = new aiMaterialProperty();
|
||||
|
||||
// .. and fill it
|
||||
pcNew->mType = pType;
|
||||
pcNew->mSemantic = type;
|
||||
pcNew->mIndex = index;
|
||||
|
||||
pcNew->mDataLength = pSizeInBytes;
|
||||
pcNew->mData = new char[pSizeInBytes];
|
||||
memcpy (pcNew->mData,pInput,pSizeInBytes);
|
||||
|
||||
pcNew->mKey.length = ::strlen(pKey);
|
||||
ai_assert ( MAXLEN > pcNew->mKey.length);
|
||||
strcpy( pcNew->mKey.data, pKey );
|
||||
|
||||
if (UINT_MAX != iOutIndex) {
|
||||
mProperties[iOutIndex] = pcNew;
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// resize the array ... double the storage allocated
|
||||
if (mNumProperties == mNumAllocated) {
|
||||
const unsigned int iOld = mNumAllocated;
|
||||
mNumAllocated *= 2;
|
||||
|
||||
aiMaterialProperty** ppTemp;
|
||||
try {
|
||||
ppTemp = new aiMaterialProperty*[mNumAllocated];
|
||||
} catch (std::bad_alloc&) {
|
||||
delete pcNew;
|
||||
return AI_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
// just copy all items over; then replace the old array
|
||||
memcpy (ppTemp,mProperties,iOld * sizeof(void*));
|
||||
|
||||
delete[] mProperties;
|
||||
mProperties = ppTemp;
|
||||
}
|
||||
// push back ...
|
||||
mProperties[mNumProperties++] = pcNew;
|
||||
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiMaterial::AddProperty (const aiString* pInput,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index)
|
||||
{
|
||||
ai_assert(sizeof(ai_uint32)==4);
|
||||
return AddBinaryProperty(pInput,
|
||||
static_cast<unsigned int>(pInput->length+1+4),
|
||||
pKey,
|
||||
type,
|
||||
index,
|
||||
aiPTI_String);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t Assimp::ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/)
|
||||
{
|
||||
uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
|
||||
for ( unsigned int i = 0; i < mat->mNumProperties; ++i ) {
|
||||
aiMaterialProperty* prop;
|
||||
|
||||
// Exclude all properties whose first character is '?' from the hash
|
||||
// See doc for aiMaterialProperty.
|
||||
if ((prop = mat->mProperties[i]) && (includeMatName || prop->mKey.data[0] != '?')) {
|
||||
|
||||
hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
|
||||
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
|
||||
|
||||
// Combine the semantic and the index with the hash
|
||||
hash = SuperFastHash((const char*)&prop->mSemantic,sizeof(unsigned int),hash);
|
||||
hash = SuperFastHash((const char*)&prop->mIndex,sizeof(unsigned int),hash);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void aiMaterial::CopyPropertyList(aiMaterial* pcDest,
|
||||
const aiMaterial* pcSrc
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != pcDest);
|
||||
ai_assert(NULL != pcSrc);
|
||||
|
||||
unsigned int iOldNum = pcDest->mNumProperties;
|
||||
pcDest->mNumAllocated += pcSrc->mNumAllocated;
|
||||
pcDest->mNumProperties += pcSrc->mNumProperties;
|
||||
|
||||
aiMaterialProperty** pcOld = pcDest->mProperties;
|
||||
pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated];
|
||||
|
||||
if (iOldNum && pcOld) {
|
||||
for (unsigned int i = 0; i < iOldNum;++i) {
|
||||
pcDest->mProperties[i] = pcOld[i];
|
||||
}
|
||||
}
|
||||
|
||||
if ( pcOld ) {
|
||||
delete[] pcOld;
|
||||
}
|
||||
|
||||
for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) {
|
||||
aiMaterialProperty* propSrc = pcSrc->mProperties[i];
|
||||
|
||||
// search whether we have already a property with this name -> if yes, overwrite it
|
||||
aiMaterialProperty* prop;
|
||||
for ( unsigned int q = 0; q < iOldNum; ++q ) {
|
||||
prop = pcDest->mProperties[q];
|
||||
if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic
|
||||
&& prop->mIndex == propSrc->mIndex) {
|
||||
delete prop;
|
||||
|
||||
// collapse the whole array ...
|
||||
memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q);
|
||||
i--;
|
||||
pcDest->mNumProperties--;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the output property and copy the source property
|
||||
prop = pcDest->mProperties[i] = new aiMaterialProperty();
|
||||
prop->mKey = propSrc->mKey;
|
||||
prop->mDataLength = propSrc->mDataLength;
|
||||
prop->mType = propSrc->mType;
|
||||
prop->mSemantic = propSrc->mSemantic;
|
||||
prop->mIndex = propSrc->mIndex;
|
||||
|
||||
prop->mData = new char[propSrc->mDataLength];
|
||||
memcpy(prop->mData,propSrc->mData,prop->mDataLength);
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file MaterialSystem.h
|
||||
* Now that #MaterialHelper is gone, this file only contains some
|
||||
* internal material utility functions.
|
||||
*/
|
||||
#ifndef AI_MATERIALSYSTEM_H_INC
|
||||
#define AI_MATERIALSYSTEM_H_INC
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct aiMaterial;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
/** Computes a hash (hopefully unique) from all material properties
|
||||
* The hash value reflects the current property state, so if you add any
|
||||
* property and call this method again, the resulting hash value will be
|
||||
* different. The hash is not persistent across different builds and platforms.
|
||||
*
|
||||
* @param includeMatName Set to 'true' to take all properties with
|
||||
* '?' as initial character in their name into account.
|
||||
* Currently #AI_MATKEY_NAME is the only example.
|
||||
* @return 32 Bit jash value for the material
|
||||
*/
|
||||
uint32_t ComputeMaterialHash(const aiMaterial* mat, bool includeMatName = false);
|
||||
|
||||
|
||||
} // ! namespace Assimp
|
||||
|
||||
#endif //!! AI_MATERIALSYSTEM_H_INC
|
|
@ -1,268 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#include "ArmaturePopulate.h"
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate::ArmaturePopulate() : BaseProcess()
|
||||
{}
|
||||
|
||||
/// The class destructor.
|
||||
ArmaturePopulate::~ArmaturePopulate()
|
||||
{}
|
||||
|
||||
bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_PopulateArmatureData) != 0;
|
||||
}
|
||||
|
||||
void ArmaturePopulate::SetupProperties(const Importer *pImp) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArmaturePopulate::Execute(aiScene *out) {
|
||||
|
||||
// Now convert all bone positions to the correct mOffsetMatrix
|
||||
std::vector<aiBone *> bones;
|
||||
std::vector<aiNode *> nodes;
|
||||
std::map<aiBone *, aiNode *> bone_stack;
|
||||
BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
|
||||
BuildNodeList(out->mRootNode, nodes);
|
||||
|
||||
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("Bone stack size: ", bone_stack.size());
|
||||
|
||||
for (std::pair<aiBone *, aiNode *> kvp : bone_stack) {
|
||||
aiBone *bone = kvp.first;
|
||||
aiNode *bone_node = kvp.second;
|
||||
ASSIMP_LOG_DEBUG_F("active node lookup: ", bone->mName.C_Str());
|
||||
// lcl transform grab - done in generate_nodes :)
|
||||
|
||||
// bone->mOffsetMatrix = bone_node->mTransformation;
|
||||
aiNode *armature = GetArmatureRoot(bone_node, bones);
|
||||
|
||||
ai_assert(armature);
|
||||
|
||||
// set up bone armature id
|
||||
bone->mArmature = armature;
|
||||
|
||||
// set this bone node to be referenced properly
|
||||
ai_assert(bone_node);
|
||||
bone->mNode = bone_node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Reprocess all nodes to calculate bone transforms properly based on the REAL
|
||||
* mOffsetMatrix not the local. */
|
||||
/* Before this would use mesh transforms which is wrong for bone transforms */
|
||||
/* Before this would work for simple character skeletons but not complex meshes
|
||||
* with multiple origins */
|
||||
/* Source: sketch fab log cutter fbx */
|
||||
void ArmaturePopulate::BuildBoneList(aiNode *current_node,
|
||||
const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones) {
|
||||
ai_assert(scene);
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
// check for bones
|
||||
for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) {
|
||||
ai_assert(child->mMeshes);
|
||||
unsigned int mesh_index = child->mMeshes[meshId];
|
||||
aiMesh *mesh = scene->mMeshes[mesh_index];
|
||||
ai_assert(mesh);
|
||||
|
||||
for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) {
|
||||
aiBone *bone = mesh->mBones[boneId];
|
||||
ai_assert(bone);
|
||||
|
||||
// duplicate meshes exist with the same bones sometimes :)
|
||||
// so this must be detected
|
||||
if (std::find(bones.begin(), bones.end(), bone) == bones.end()) {
|
||||
// add the element once
|
||||
bones.push_back(bone);
|
||||
}
|
||||
}
|
||||
|
||||
// find mesh and get bones
|
||||
// then do recursive lookup for bones in root node hierarchy
|
||||
}
|
||||
|
||||
BuildBoneList(child, root_node, scene, bones);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare flat node list which can be used for non recursive lookups later */
|
||||
void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
ai_assert(current_node);
|
||||
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
nodes.push_back(child);
|
||||
|
||||
BuildNodeList(child, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
/* A bone stack allows us to have multiple armatures, with the same bone names
|
||||
* A bone stack allows us also to retrieve bones true transform even with
|
||||
* duplicate names :)
|
||||
*/
|
||||
void ArmaturePopulate::BuildBoneStack(aiNode *current_node,
|
||||
const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack) {
|
||||
ai_assert(scene);
|
||||
ai_assert(root_node);
|
||||
ai_assert(!node_stack.empty());
|
||||
|
||||
for (aiBone *bone : bones) {
|
||||
ai_assert(bone);
|
||||
aiNode *node = GetNodeFromStack(bone->mName, node_stack);
|
||||
if (node == nullptr) {
|
||||
node_stack.clear();
|
||||
BuildNodeList(root_node, node_stack);
|
||||
ASSIMP_LOG_DEBUG_F("Resetting bone stack: nullptr element ", bone->mName.C_Str());
|
||||
|
||||
node = GetNodeFromStack(bone->mName, node_stack);
|
||||
|
||||
if (!node) {
|
||||
ASSIMP_LOG_ERROR("serious import issue node for bone was not detected");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str());
|
||||
|
||||
bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Returns the armature root node */
|
||||
/* This is required to be detected for a bone initially, it will recurse up
|
||||
* until it cannot find another bone and return the node No known failure
|
||||
* points. (yet)
|
||||
*/
|
||||
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list) {
|
||||
while (bone_node) {
|
||||
if (!IsBoneNode(bone_node->mName, bone_list)) {
|
||||
ASSIMP_LOG_DEBUG_F("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
|
||||
return bone_node;
|
||||
}
|
||||
|
||||
bone_node = bone_node->mParent;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Simple IsBoneNode check if this could be a bone */
|
||||
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones) {
|
||||
for (aiBone *bone : bones) {
|
||||
if (bone->mName == bone_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Pop this node by name from the stack if found */
|
||||
/* Used in multiple armature situations with duplicate node / bone names */
|
||||
/* Known flaw: cannot have nodes with bone names, will be fixed in later release
|
||||
*/
|
||||
/* (serious to be fixed) Known flaw: nodes which have more than one bone could
|
||||
* be prematurely dropped from stack */
|
||||
aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
std::vector<aiNode *>::iterator iter;
|
||||
aiNode *found = nullptr;
|
||||
for (iter = nodes.begin(); iter < nodes.end(); ++iter) {
|
||||
aiNode *element = *iter;
|
||||
ai_assert(element);
|
||||
// node valid and node name matches
|
||||
if (element->mName == node_name) {
|
||||
found = element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != nullptr) {
|
||||
ASSIMP_LOG_INFO_F("Removed node from stack: ", found->mName.C_Str());
|
||||
// now pop the element from the node list
|
||||
nodes.erase(iter);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// unique names can cause this problem
|
||||
ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // Namespace Assimp
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ARMATURE_POPULATE_H_
|
||||
#define ARMATURE_POPULATE_H_
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
struct aiNode;
|
||||
struct aiBone;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Armature Populate: This is a post process designed
|
||||
* To save you time when importing models into your game engines
|
||||
* This was originally designed only for fbx but will work with other formats
|
||||
* it is intended to auto populate aiBone data with armature and the aiNode
|
||||
* This is very useful when dealing with skinned meshes
|
||||
* or when dealing with many different skeletons
|
||||
* It's off by default but recommend that you try it and use it
|
||||
* It should reduce down any glue code you have in your
|
||||
* importers
|
||||
* You can contact RevoluPowered <gordon@gordonite.tech>
|
||||
* For more info about this
|
||||
*/
|
||||
class ASSIMP_API ArmaturePopulate : public BaseProcess {
|
||||
public:
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate();
|
||||
|
||||
/// The class destructor.
|
||||
virtual ~ArmaturePopulate();
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual bool IsActive( unsigned int pFlags ) const;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void SetupProperties( const Importer* pImp );
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void Execute( aiScene* pScene );
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack);
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
|
||||
#endif // SCALE_PROCESS_H_
|
|
@ -1,319 +0,0 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Implementation of the post processing step to calculate
|
||||
* tangents and bitangents for all imported meshes
|
||||
*/
|
||||
|
||||
// internal headers
|
||||
#include "CalcTangentsProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/qnan.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
CalcTangentsProcess::CalcTangentsProcess()
|
||||
: configMaxAngle( AI_DEG_TO_RAD(45.f) )
|
||||
, configSourceUV( 0 ) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
CalcTangentsProcess::~CalcTangentsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_CalcTangentSpace) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
ai_assert( NULL != pImp );
|
||||
|
||||
// get the current value of the property
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
|
||||
configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
|
||||
configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
|
||||
|
||||
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void CalcTangentsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ai_assert( NULL != pScene );
|
||||
|
||||
ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
|
||||
|
||||
bool bHas = false;
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
|
||||
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
|
||||
}
|
||||
|
||||
if ( bHas ) {
|
||||
ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Calculates tangents and bi-tangents for the given mesh
|
||||
bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
||||
{
|
||||
// we assume that the mesh is still in the verbose vertex format where each face has its own set
|
||||
// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
|
||||
// assert() it here.
|
||||
// assert( must be verbose, dammit);
|
||||
|
||||
if (pMesh->mTangents) // this implies that mBitangents is also there
|
||||
return false;
|
||||
|
||||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
|
||||
{
|
||||
ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
|
||||
if( pMesh->mNormals == NULL)
|
||||
{
|
||||
ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
|
||||
return false;
|
||||
}
|
||||
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
|
||||
{
|
||||
ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
|
||||
return false;
|
||||
}
|
||||
|
||||
const float angleEpsilon = 0.9999f;
|
||||
|
||||
std::vector<bool> vertexDone( pMesh->mNumVertices, false);
|
||||
const float qnan = get_qnan();
|
||||
|
||||
// create space for the tangents and bitangents
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
const aiVector3D* meshPos = pMesh->mVertices;
|
||||
const aiVector3D* meshNorm = pMesh->mNormals;
|
||||
const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
|
||||
aiVector3D* meshTang = pMesh->mTangents;
|
||||
aiVector3D* meshBitang = pMesh->mBitangents;
|
||||
|
||||
// calculate the tangent and bitangent for every face
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3)
|
||||
{
|
||||
// There are less than three indices, thus the tangent vector
|
||||
// is not defined. We are finished with these vertices now,
|
||||
// their tangent vectors are set to qnan.
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
{
|
||||
unsigned int idx = face.mIndices[i];
|
||||
vertexDone [idx] = true;
|
||||
meshTang [idx] = aiVector3D(qnan);
|
||||
meshBitang [idx] = aiVector3D(qnan);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// triangle or polygon... we always use only the first three indices. A polygon
|
||||
// is supposed to be planar anyways....
|
||||
// FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
|
||||
const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
|
||||
|
||||
// position differences p1->p2 and p1->p3
|
||||
aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
|
||||
|
||||
// texture offset p1->p2 and p1->p3
|
||||
float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
|
||||
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
|
||||
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
||||
// when t1, t2, t3 in same position in UV space, just use default UV direction.
|
||||
if ( sx * ty == sy * tx ) {
|
||||
sx = 0.0; sy = 1.0;
|
||||
tx = 1.0; ty = 0.0;
|
||||
}
|
||||
|
||||
// tangent points in the direction where to positive X axis of the texture coord's would point in model space
|
||||
// bitangent's points along the positive Y axis of the texture coord's, respectively
|
||||
aiVector3D tangent, bitangent;
|
||||
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
|
||||
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
|
||||
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
|
||||
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
|
||||
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
|
||||
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
|
||||
|
||||
// store for every vertex of that face
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
|
||||
unsigned int p = face.mIndices[b];
|
||||
|
||||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.NormalizeSafe(); localBitangent.NormalizeSafe();
|
||||
|
||||
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
|
||||
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
|
||||
bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z);
|
||||
if (invalid_tangent != invalid_bitangent) {
|
||||
if (invalid_tangent) {
|
||||
localTangent = meshNorm[p] ^ localBitangent;
|
||||
localTangent.NormalizeSafe();
|
||||
} else {
|
||||
localBitangent = localTangent ^ meshNorm[p];
|
||||
localBitangent.NormalizeSafe();
|
||||
}
|
||||
}
|
||||
|
||||
// and write it into the mesh.
|
||||
meshTang[ p ] = localTangent;
|
||||
meshBitang[ p ] = localBitangent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create a helper to quickly find locally close vertices among the vertex array
|
||||
// FIX: check whether we can reuse the SpatialSort of a previous step
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
float posEpsilon;
|
||||
if (shared)
|
||||
{
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf)
|
||||
{
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilon = blubb.second;;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder)
|
||||
{
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilon = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
std::vector<unsigned int> verticesFound;
|
||||
|
||||
const float fLimit = std::cos(configMaxAngle);
|
||||
std::vector<unsigned int> closeVertices;
|
||||
|
||||
// in the second pass we now smooth out all tangents and bitangents at the same local position
|
||||
// if they are not too far off.
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
{
|
||||
if( vertexDone[a])
|
||||
continue;
|
||||
|
||||
const aiVector3D& origPos = pMesh->mVertices[a];
|
||||
const aiVector3D& origNorm = pMesh->mNormals[a];
|
||||
const aiVector3D& origTang = pMesh->mTangents[a];
|
||||
const aiVector3D& origBitang = pMesh->mBitangents[a];
|
||||
closeVertices.resize( 0 );
|
||||
|
||||
// find all vertices close to that position
|
||||
vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
|
||||
|
||||
closeVertices.reserve (verticesFound.size()+5);
|
||||
closeVertices.push_back( a);
|
||||
|
||||
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++)
|
||||
{
|
||||
unsigned int idx = verticesFound[b];
|
||||
if( vertexDone[idx])
|
||||
continue;
|
||||
if( meshNorm[idx] * origNorm < angleEpsilon)
|
||||
continue;
|
||||
if( meshTang[idx] * origTang < fLimit)
|
||||
continue;
|
||||
if( meshBitang[idx] * origBitang < fLimit)
|
||||
continue;
|
||||
|
||||
// it's similar enough -> add it to the smoothing group
|
||||
closeVertices.push_back( idx);
|
||||
vertexDone[idx] = true;
|
||||
}
|
||||
|
||||
// smooth the tangents and bitangents of all vertices that were found to be close enough
|
||||
aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
smoothTangent += meshTang[ closeVertices[b] ];
|
||||
smoothBitangent += meshBitang[ closeVertices[b] ];
|
||||
}
|
||||
smoothTangent.Normalize();
|
||||
smoothBitangent.Normalize();
|
||||
|
||||
// and write it back into all affected tangents
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
meshTang[ closeVertices[b] ] = smoothTangent;
|
||||
meshBitang[ closeVertices[b] ] = smoothBitangent;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/** @file Defines a post processing step to calculate tangents and
|
||||
bi-tangents on all imported meshes.*/
|
||||
#ifndef AI_CALCTANGENTSPROCESS_H_INC
|
||||
#define AI_CALCTANGENTSPROCESS_H_INC
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
|
||||
struct aiMesh;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The CalcTangentsProcess calculates the tangent and bitangent for any vertex
|
||||
* of all meshes. It is expected to be run before the JoinVerticesProcess runs
|
||||
* because the joining of vertices also considers tangents and bitangents for
|
||||
* uniqueness.
|
||||
*/
|
||||
class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
|
||||
CalcTangentsProcess();
|
||||
~CalcTangentsProcess();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
* A bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
|
||||
// setter for configMaxAngle
|
||||
inline void SetMaxSmoothAngle(float f)
|
||||
{
|
||||
configMaxAngle =f;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Calculates tangents and bitangents for a specific mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
* @param meshIndex Index of the mesh
|
||||
*/
|
||||
bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
float configMaxAngle;
|
||||
unsigned int configSourceUV;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_CALCTANGENTSPROCESS_H_INC
|
|
@ -1,506 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file GenUVCoords step */
|
||||
|
||||
|
||||
#include "ComputeUVMappingProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace {
|
||||
|
||||
const static aiVector3D base_axis_y(0.0,1.0,0.0);
|
||||
const static aiVector3D base_axis_x(1.0,0.0,0.0);
|
||||
const static aiVector3D base_axis_z(0.0,0.0,1.0);
|
||||
const static ai_real angle_epsilon = ai_real( 0.95 );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ComputeUVMappingProcess::ComputeUVMappingProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
ComputeUVMappingProcess::~ComputeUVMappingProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_GenUVCoords) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a ray intersects a plane and find the intersection point
|
||||
inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
||||
const aiVector3D& planeNormal, aiVector3D& pos)
|
||||
{
|
||||
const ai_real b = planeNormal * (planePos - ray.pos);
|
||||
ai_real h = ray.dir * planeNormal;
|
||||
if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0)
|
||||
return false;
|
||||
|
||||
pos = ray.pos + (ray.dir * h);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find the first empty UV channel in a mesh
|
||||
inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
||||
{
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
||||
if (!mesh->mTextureCoords[m])return m;
|
||||
|
||||
ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found");
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Try to remove UV seams
|
||||
void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
||||
{
|
||||
// TODO: just a very rough algorithm. I think it could be done
|
||||
// much easier, but I don't know how and am currently too tired to
|
||||
// to think about a better solution.
|
||||
|
||||
const static ai_real LOWER_LIMIT = ai_real( 0.1 );
|
||||
const static ai_real UPPER_LIMIT = ai_real( 0.9 );
|
||||
|
||||
const static ai_real LOWER_EPSILON = ai_real( 10e-3 );
|
||||
const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 );
|
||||
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
|
||||
unsigned int small = face.mNumIndices, large = small;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
|
||||
// Check whether this face lies on a UV seam. We can just guess,
|
||||
// but the assumption that a face with at least one very small
|
||||
// on the one side and one very large U coord on the other side
|
||||
// lies on a UV seam should work for most cases.
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
small = n;
|
||||
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
zero = true;
|
||||
else round_to_zero = true;
|
||||
}
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
||||
{
|
||||
large = n;
|
||||
|
||||
// If we have a U value very close to 1 we can't
|
||||
// round the others to 1, too.
|
||||
if (out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
one = true;
|
||||
}
|
||||
}
|
||||
if (small != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
// If the u value is over the upper limit and no other u
|
||||
// value of that face is 0, round it to 0
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
||||
out[face.mIndices[n]].x = 0.0;
|
||||
|
||||
// If the u value is below the lower limit and no other u
|
||||
// value of that face is 1, round it to 1
|
||||
else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
|
||||
out[face.mIndices[n]].x = 1.0;
|
||||
|
||||
// The face contains both 0 and 1 as UV coords. This can occur
|
||||
// for faces which have an edge that lies directly on the seam.
|
||||
// Due to numerical inaccuracies one U coord becomes 0, the
|
||||
// other 1. But we do still have a third UV coord to determine
|
||||
// to which side we must round to.
|
||||
else if (one && zero)
|
||||
{
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
out[face.mIndices[n]].x = 0.0;
|
||||
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
out[face.mIndices[n]].x = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
|
||||
// For each point get a normalized projection vector in the sphere,
|
||||
// get its longitude and latitude and map them to their respective
|
||||
// UV axes. Problems occur around the poles ... unsolvable.
|
||||
//
|
||||
// The spherical coordinate system looks like this:
|
||||
// x = cos(lon)*cos(lat)
|
||||
// y = sin(lon)*cos(lat)
|
||||
// z = sin(lat)
|
||||
//
|
||||
// Thus we can derive:
|
||||
// lat = arcsin (z)
|
||||
// lon = arctan (y/x)
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.x - min.x;
|
||||
|
||||
// If the main axis is 'z', the z coordinate of a point 'p' is mapped
|
||||
// directly to the texture V axis. The other axis is derived from
|
||||
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
||||
// 'c' is the center point of the mesh.
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.x - min.x) / diff;
|
||||
uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.y - min.y;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.z - min.z;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.z - min.z) / diff;
|
||||
uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
const ai_real diff = max.y - min.y;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
|
||||
const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
ai_real diffu,diffv;
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.z - min.z;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else
|
||||
{
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// shouldn't be necessary to remove UV seams ...
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
|
||||
{
|
||||
ASSIMP_LOG_ERROR("Mapping type currently not implemented");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
|
||||
char buffer[1024];
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
|
||||
std::list<MappingInfo> mappingStack;
|
||||
|
||||
/* Iterate through all materials and search for non-UV mapped textures
|
||||
*/
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
mappingStack.clear();
|
||||
aiMaterial* mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
||||
{
|
||||
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
|
||||
TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
|
||||
MappingTypeToString(mapping));
|
||||
|
||||
ASSIMP_LOG_INFO(buffer);
|
||||
}
|
||||
|
||||
if (aiTextureMapping_OTHER == mapping)
|
||||
continue;
|
||||
|
||||
MappingInfo info (mapping);
|
||||
|
||||
// Get further properties - currently only the major axis
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
||||
{
|
||||
aiMaterialProperty* prop2 = mat->mProperties[a2];
|
||||
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
|
||||
continue;
|
||||
|
||||
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) {
|
||||
info.axis = *((aiVector3D*)prop2->mData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int idx( 99999999 );
|
||||
|
||||
// Check whether we have this mapping mode already
|
||||
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
||||
if (mappingStack.end() != it)
|
||||
{
|
||||
idx = (*it).uv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
unsigned int outIdx = 0;
|
||||
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
|
||||
!mesh->mNumVertices)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate output storage
|
||||
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
switch (mapping)
|
||||
{
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh,p);
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
if (m && idx != outIdx)
|
||||
{
|
||||
ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
}
|
||||
idx = outIdx;
|
||||
}
|
||||
info.uv = idx;
|
||||
mappingStack.push_back(info);
|
||||
}
|
||||
|
||||
// Update the material property list
|
||||
mapping = aiTextureMapping_UV;
|
||||
((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Defines a post processing step to compute UV coordinates
|
||||
from abstract mappings, such as box or spherical*/
|
||||
#ifndef AI_COMPUTEUVMAPPING_H_INC
|
||||
#define AI_COMPUTEUVMAPPING_H_INC
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/types.h>
|
||||
|
||||
class ComputeUVMappingTest;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** ComputeUVMappingProcess - converts special mappings, such as spherical,
|
||||
* cylindrical or boxed to proper UV coordinates for rendering.
|
||||
*/
|
||||
class ComputeUVMappingProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
ComputeUVMappingProcess();
|
||||
~ComputeUVMappingProcess();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
* @param pFlags The processing flags the importer was called with. A bitwise
|
||||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes spherical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cylindrical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes planar UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cubic UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
|
||||
|
||||
private:
|
||||
|
||||
// temporary structure to describe a mapping
|
||||
struct MappingInfo
|
||||
{
|
||||
explicit MappingInfo(aiTextureMapping _type)
|
||||
: type (_type)
|
||||
, axis (0.f,1.f,0.f)
|
||||
, uv (0u)
|
||||
{}
|
||||
|
||||
aiTextureMapping type;
|
||||
aiVector3D axis;
|
||||
unsigned int uv;
|
||||
|
||||
bool operator== (const MappingInfo& other)
|
||||
{
|
||||
return type == other.type && axis == other.axis;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_COMPUTEUVMAPPING_H_INC
|
|
@ -1,414 +0,0 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file MakeLeftHandedProcess.cpp
|
||||
* @brief Implementation of the post processing step to convert all
|
||||
* imported data to a left-handed coordinate system.
|
||||
*
|
||||
* Face order & UV flip are also implemented here, for the sake of a
|
||||
* better location.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConvertToLHProcess.h"
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename aiMeshType>
|
||||
void flipUVs(aiMeshType* pMesh) {
|
||||
if (pMesh == nullptr) { return; }
|
||||
// mirror texture y coordinate
|
||||
for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) {
|
||||
if (!pMesh->HasTextureCoords(tcIdx)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned int vIdx = 0; vIdx < pMesh->mNumVertices; vIdx++) {
|
||||
pMesh->mTextureCoords[tcIdx][vIdx].y = 1.0f - pMesh->mTextureCoords[tcIdx][vIdx].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
MakeLeftHandedProcess::MakeLeftHandedProcess()
|
||||
: BaseProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
MakeLeftHandedProcess::~MakeLeftHandedProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_MakeLeftHanded);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void MakeLeftHandedProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
// Check for an existent root node to proceed
|
||||
ai_assert(pScene->mRootNode != NULL);
|
||||
ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin");
|
||||
|
||||
// recursively convert all the nodes
|
||||
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
||||
|
||||
// process the meshes accordingly
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
|
||||
ProcessMesh( pScene->mMeshes[ a ] );
|
||||
}
|
||||
|
||||
// process the materials accordingly
|
||||
for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
|
||||
ProcessMaterial( pScene->mMaterials[ a ] );
|
||||
}
|
||||
|
||||
// transform all animation channels as well
|
||||
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
||||
{
|
||||
aiAnimation* anim = pScene->mAnimations[a];
|
||||
for( unsigned int b = 0; b < anim->mNumChannels; b++)
|
||||
{
|
||||
aiNodeAnim* nodeAnim = anim->mChannels[b];
|
||||
ProcessAnimation( nodeAnim);
|
||||
}
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively converts a node, all of its children and all of its meshes
|
||||
void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
|
||||
{
|
||||
// mirror all base vectors at the local Z axis
|
||||
pNode->mTransformation.c1 = -pNode->mTransformation.c1;
|
||||
pNode->mTransformation.c2 = -pNode->mTransformation.c2;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.c4 = -pNode->mTransformation.c4;
|
||||
|
||||
// now invert the Z axis again to keep the matrix determinant positive.
|
||||
// The local meshes will be inverted accordingly so that the result should look just fine again.
|
||||
pNode->mTransformation.a3 = -pNode->mTransformation.a3;
|
||||
pNode->mTransformation.b3 = -pNode->mTransformation.b3;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
|
||||
|
||||
// continue for all children
|
||||
for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
|
||||
ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
|
||||
if ( nullptr == pMesh ) {
|
||||
ASSIMP_LOG_ERROR( "Nullptr to mesh found." );
|
||||
return;
|
||||
}
|
||||
// mirror positions, normals and stuff along the Z axis
|
||||
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
||||
{
|
||||
pMesh->mVertices[a].z *= -1.0f;
|
||||
if (pMesh->HasNormals()) {
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
}
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
pMesh->mTangents[a].z *= -1.0f;
|
||||
pMesh->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// mirror anim meshes positions, normals and stuff along the Z axis
|
||||
for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m)
|
||||
{
|
||||
for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a)
|
||||
{
|
||||
pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f;
|
||||
if (pMesh->mAnimMeshes[m]->HasNormals()) {
|
||||
pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f;
|
||||
}
|
||||
if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents())
|
||||
{
|
||||
pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f;
|
||||
pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mirror offset matrices of all bones
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
|
||||
bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
|
||||
bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
|
||||
bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
|
||||
bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
|
||||
bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
|
||||
}
|
||||
|
||||
// mirror bitangents as well as they're derived from the texture coords
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mBitangents[a] *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
|
||||
if ( nullptr == _mat ) {
|
||||
ASSIMP_LOG_ERROR( "Nullptr to aiMaterial found." );
|
||||
return;
|
||||
}
|
||||
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
|
||||
// Mapping axis for UV mappings?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
||||
aiVector3D* pff = (aiVector3D*)prop->mData;
|
||||
pff->z *= -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts the given animation to LH coordinates.
|
||||
void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
|
||||
{
|
||||
// position keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
|
||||
pAnim->mPositionKeys[a].mValue.z *= -1.0f;
|
||||
|
||||
// rotation keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
|
||||
{
|
||||
/* That's the safe version, but the float errors add up. So we try the short version instead
|
||||
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
|
||||
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
|
||||
rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
|
||||
aiQuaternion rotquat( rotmat);
|
||||
pAnim->mRotationKeys[a].mValue = rotquat;
|
||||
*/
|
||||
pAnim->mRotationKeys[a].mValue.x *= -1.0f;
|
||||
pAnim->mRotationKeys[a].mValue.y *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
// # FlipUVsProcess
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FlipUVsProcess::FlipUVsProcess()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FlipUVsProcess::~FlipUVsProcess()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipUVsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_FlipUVs);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipUVsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("FlipUVsProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
ProcessMaterial(pScene->mMaterials[i]);
|
||||
ASSIMP_LOG_DEBUG("FlipUVsProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material
|
||||
void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
|
||||
{
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if( !prop ) {
|
||||
ASSIMP_LOG_DEBUG( "Property is null" );
|
||||
continue;
|
||||
}
|
||||
|
||||
// UV transformation key?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */
|
||||
aiUVTransform* uv = (aiUVTransform*)prop->mData;
|
||||
|
||||
// just flip it, that's everything
|
||||
uv->mTranslation.y *= -1.f;
|
||||
uv->mRotation *= -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
flipUVs(pMesh);
|
||||
for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) {
|
||||
flipUVs(pMesh->mAnimMeshes[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
||||
// # FlipWindingOrderProcess
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FlipWindingOrderProcess::FlipWindingOrderProcess()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FlipWindingOrderProcess::~FlipWindingOrderProcess()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_FlipWindingOrder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipWindingOrderProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
// invert the order of all faces in this mesh
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
for (unsigned int b = 0; b < face.mNumIndices / 2; b++) {
|
||||
std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]);
|
||||
}
|
||||
}
|
||||
|
||||
// invert the order of all components in this mesh anim meshes
|
||||
for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) {
|
||||
aiAnimMesh* animMesh = pMesh->mAnimMeshes[m];
|
||||
unsigned int numVertices = animMesh->mNumVertices;
|
||||
if (animMesh->HasPositions()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
if (animMesh->HasNormals()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
|
||||
if (animMesh->HasTextureCoords(i)) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animMesh->HasTangentsAndBitangents()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]);
|
||||
std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) {
|
||||
if (animMesh->HasVertexColors(v)) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file MakeLeftHandedProcess.h
|
||||
* @brief Defines a bunch of post-processing steps to handle
|
||||
* coordinate system conversions.
|
||||
*
|
||||
* - LH to RH
|
||||
* - UV origin upper-left to lower-left
|
||||
* - face order cw to ccw
|
||||
*/
|
||||
#ifndef AI_CONVERTTOLHPROCESS_H_INC
|
||||
#define AI_CONVERTTOLHPROCESS_H_INC
|
||||
|
||||
#include <assimp/types.h>
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
|
||||
struct aiMesh;
|
||||
struct aiNodeAnim;
|
||||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
/** @brief The MakeLeftHandedProcess converts all imported data to a left-handed
|
||||
* coordinate system.
|
||||
*
|
||||
* This implies a mirroring of the Z axis of the coordinate system. But to keep
|
||||
* transformation matrices free from reflections we shift the reflection to other
|
||||
* places. We mirror the meshes and adapt the rotations.
|
||||
*
|
||||
* @note RH-LH and LH-RH is the same, so this class can be used for both
|
||||
*/
|
||||
class MakeLeftHandedProcess : public BaseProcess
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
MakeLeftHandedProcess();
|
||||
~MakeLeftHandedProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Recursively converts a node and all of its children
|
||||
*/
|
||||
void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single mesh to left handed coordinates.
|
||||
* This means that positions, normals and tangents are mirrored at
|
||||
* the local Z axis and the order of all faces are inverted.
|
||||
* @param pMesh The mesh to convert.
|
||||
*/
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single material to left-handed coordinates
|
||||
* @param pMat Material to convert
|
||||
*/
|
||||
void ProcessMaterial( aiMaterial* pMat);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts the given animation to LH coordinates.
|
||||
* The rotation and translation keys are transformed, the scale keys
|
||||
* work in local space and can therefore be left untouched.
|
||||
* @param pAnim The bone animation to transform
|
||||
*/
|
||||
void ProcessAnimation( aiNodeAnim* pAnim);
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Postprocessing step to flip the face order of the imported data
|
||||
*/
|
||||
class FlipWindingOrderProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipWindingOrderProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~FlipWindingOrderProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Postprocessing step to flip the UV coordinate system of the import data
|
||||
*/
|
||||
class FlipUVsProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipUVsProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~FlipUVsProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
void ProcessMaterial( aiMaterial* mat);
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_CONVERTTOLHPROCESS_H_INC
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue