diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 84e3123fe..e0c2bec9e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,2 @@ patreon: assimp custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4 -open_collective: assimp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7072537f1..9da3735ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,7 +353,7 @@ ELSE() ENDIF() # Only generate this target if no higher-level project already has -IF (NOT TARGET uninstall) +IF (NOT TARGET uninstall AND ASSIMP_INSTALL) # add make uninstall capability CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") diff --git a/cmake-modules/FindRT.cmake b/cmake-modules/FindRT.cmake index 17d5df81d..c397acabd 100644 --- a/cmake-modules/FindRT.cmake +++ b/cmake-modules/FindRT.cmake @@ -16,5 +16,5 @@ set(RT_LIBRARIES ${RT_LIBRARY}) # handle the QUIETLY and REQUIRED arguments and set # RT_FOUND to TRUE if all listed variables are TRUE include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY) +find_package_handle_standard_args(RT DEFAULT_MSG RT_LIBRARY) mark_as_advanced(RT_LIBRARY) diff --git a/cmake/assimp-hunter-config.cmake.in b/cmake/assimp-hunter-config.cmake.in index ecd9b988b..b5283f4fb 100644 --- a/cmake/assimp-hunter-config.cmake.in +++ b/cmake/assimp-hunter-config.cmake.in @@ -8,6 +8,7 @@ find_package(openddlparser CONFIG REQUIRED) find_package(poly2tri CONFIG REQUIRED) find_package(polyclipping CONFIG REQUIRED) find_package(zip CONFIG REQUIRED) +find_package(pugixml CONFIG REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") check_required_components("@PROJECT_NAME@") diff --git a/code/AssetLib/Collada/ColladaHelper.cpp b/code/AssetLib/Collada/ColladaHelper.cpp index 50d70e640..0a779e04e 100644 --- a/code/AssetLib/Collada/ColladaHelper.cpp +++ b/code/AssetLib/Collada/ColladaHelper.cpp @@ -1,5 +1,3 @@ -/** Helper structures for the Collada loader */ - /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -40,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +/** Helper structures for the Collada loader */ #include "ColladaHelper.h" diff --git a/code/AssetLib/Collada/ColladaHelper.h b/code/AssetLib/Collada/ColladaHelper.h index bc93203aa..bfd57918e 100644 --- a/code/AssetLib/Collada/ColladaHelper.h +++ b/code/AssetLib/Collada/ColladaHelper.h @@ -1,12 +1,9 @@ -/** Helper structures for the Collada loader */ - /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,12 +39,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +/** Helper structures for the Collada loader */ + #ifndef AI_COLLADAHELPER_H_INC #define AI_COLLADAHELPER_H_INC #include #include #include + #include #include #include @@ -58,14 +58,14 @@ struct aiMaterial; namespace Assimp { namespace Collada { -/** Collada file versions which evolved during the years ... */ +/// Collada file versions which evolved during the years ... enum FormatVersion { FV_1_5_n, FV_1_4_n, FV_1_3_n }; -/** Transformation types that can be applied to a node */ +/// Transformation types that can be applied to a node enum TransformType { TF_LOOKAT, TF_ROTATE, @@ -75,7 +75,7 @@ enum TransformType { TF_MATRIX }; -/** Different types of input data to a vertex or face */ +/// Different types of input data to a vertex or face enum InputType { IT_Invalid, IT_Vertex, // special type for per-index data referring to the element carrying the per-vertex data. @@ -87,38 +87,39 @@ enum InputType { IT_Bitangent }; -/** Supported controller types */ +/// Supported controller types enum ControllerType { Skin, Morph }; -/** Supported morph methods */ +/// Supported morph methods enum MorphMethod { Normalized, Relative }; -/** Common metadata keys as */ -typedef std::pair MetaKeyPair; -typedef std::vector MetaKeyPairVector; +/// Common metadata keys as +using MetaKeyPair = std::pair; +using MetaKeyPairVector = std::vector; -// Collada as lower_case (native) +/// Collada as lower_case (native) const MetaKeyPairVector &GetColladaAssimpMetaKeys(); + // Collada as CamelCase (used by Assimp for consistency) const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); -/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */ +/// Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" void ToCamelCase(std::string &text); -/** Contains all data for one of the different transformation types */ +/// Contains all data for one of the different transformation types struct Transform { std::string mID; ///< SID of the transform step, by which anim channels address their target node TransformType mType; ai_real f[16]; ///< Interpretation of data depends on the type of the transformation }; -/** A collada camera. */ +/// A collada camera. struct Camera { Camera() : mOrtho(false), @@ -128,22 +129,22 @@ struct Camera { mZNear(0.1f), mZFar(1000.f) {} - // Name of camera + /// Name of camera std::string mName; - // True if it is an orthografic camera + /// True if it is an orthographic camera bool mOrtho; - //! Horizontal field of view in degrees + /// Horizontal field of view in degrees ai_real mHorFov; - //! Vertical field of view in degrees + /// Vertical field of view in degrees ai_real mVerFov; - //! Screen aspect + /// Screen aspect ai_real mAspect; - //! Near& far z + /// Near& far z ai_real mZNear, mZFar; }; @@ -162,27 +163,27 @@ struct Light { mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), mIntensity(1.f) {} - //! Type of the light source aiLightSourceType + ambient + /// Type of the light source aiLightSourceType + ambient unsigned int mType; - //! Color of the light + /// Color of the light aiColor3D mColor; - //! Light attenuation + /// Light attenuation ai_real mAttConstant, mAttLinear, mAttQuadratic; - //! Spot light falloff + /// Spot light falloff ai_real mFalloffAngle; ai_real mFalloffExponent; // ----------------------------------------------------- // FCOLLADA extension from here - //! ... related stuff from maja and max extensions + /// ... related stuff from maja and max extensions ai_real mPenumbraAngle; ai_real mOuterAngle; - //! Common light intensity + /// Common light intensity ai_real mIntensity; }; @@ -192,30 +193,29 @@ struct InputSemanticMapEntry { mSet(0), mType(IT_Invalid) {} - //! Index of set, optional + /// Index of set, optional unsigned int mSet; - //! Type of referenced vertex input + /// Type of referenced vertex input InputType mType; }; -/** Table to map from effect to vertex input semantics */ +/// Table to map from effect to vertex input semantics struct SemanticMappingTable { - //! Name of material + /// Name of material std::string mMatName; - //! List of semantic map commands, grouped by effect semantic name + /// List of semantic map commands, grouped by effect semantic name std::map mMap; - //! For std::find + /// For std::find bool operator==(const std::string &s) const { return s == mMatName; } }; -/** A reference to a mesh inside a node, including materials assigned to the various subgroups. - * The ID refers to either a mesh or a controller which specifies the mesh - */ +/// A reference to a mesh inside a node, including materials assigned to the various subgroups. +/// The ID refers to either a mesh or a controller which specifies the mesh struct MeshInstance { ///< ID of the mesh or controller to be instanced std::string mMeshOrController; @@ -224,25 +224,25 @@ struct MeshInstance { std::map mMaterials; }; -/** A reference to a camera inside a node*/ +/// A reference to a camera inside a node struct CameraInstance { ///< ID of the camera std::string mCamera; }; -/** A reference to a light inside a node*/ +/// A reference to a light inside a node struct LightInstance { ///< ID of the camera std::string mLight; }; -/** A reference to a node inside a node*/ +/// A reference to a node inside a node struct NodeInstance { ///< ID of the node std::string mNode; }; -/** A node in a scene hierarchy */ +/// A node in a scene hierarchy struct Node { std::string mName; std::string mID; @@ -250,52 +250,53 @@ struct Node { Node *mParent; std::vector mChildren; - /** Operations in order to calculate the resulting transformation to parent. */ + /// Operations in order to calculate the resulting transformation to parent. std::vector mTransforms; - /** Meshes at this node */ + /// Meshes at this node std::vector mMeshes; - /** Lights at this node */ + /// Lights at this node std::vector mLights; - /** Cameras at this node */ + /// Cameras at this node std::vector mCameras; - /** Node instances at this node */ + /// Node instances at this node std::vector mNodeInstances; - /** Root-nodes: Name of primary camera, if any */ + /// Root-nodes: Name of primary camera, if any std::string mPrimaryCamera; - //! Constructor. Begin with a zero parent + /// Constructor. Begin with a zero parent Node() : mParent(nullptr) { // empty } - //! Destructor: delete all children subsequently + /// Destructor: delete all children subsequently ~Node() { - for (std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) + for (std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) { delete *it; + } } }; -/** Data source array: either floats or strings */ +/// Data source array: either floats or strings struct Data { bool mIsStringArray; std::vector mValues; std::vector mStrings; }; -/** Accessor to a data array */ +/// Accessor to a data array struct Accessor { size_t mCount; // in number of objects size_t mSize; // size of an object, in elements (floats or strings, mostly 1) size_t mOffset; // in number of values size_t mStride; // Stride in number of values std::vector mParams; // names of the data streams in the accessors. Empty string tells to ignore. - size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on. + size_t mSubOffset[4]; // Sub-offset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on. // For example, SubOffset[0] denotes which of the values inside the object is the vector X component. std::string mSource; // URL of the source array mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else @@ -310,12 +311,12 @@ struct Accessor { } }; -/** A single face in a mesh */ +/// A single face in a mesh struct Face { std::vector mIndices; }; -/** An input channel for mesh data, referring to a single accessor */ +/// An input channel for mesh data, referring to a single accessor struct InputChannel { InputType mType; // Type of the data size_t mIndex; // Optional index, if multiple sets of the same data type are given @@ -331,18 +332,19 @@ struct InputChannel { } }; -/** Subset of a mesh with a certain material */ +/// Subset of a mesh with a certain material struct SubMesh { std::string mMaterial; ///< subgroup identifier - size_t mNumFaces; ///< number of faces in this submesh + size_t mNumFaces; ///< number of faces in this sub-mesh }; -/** Contains data for a single mesh */ +/// Contains data for a single mesh struct Mesh { Mesh(const std::string &id) : mId(id) { - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { mNumUVComponents[i] = 2; + } } const std::string mId; @@ -373,11 +375,11 @@ struct Mesh { // necessary for bone weight assignment std::vector mFacePosIndices; - // Submeshes in this mesh, each with a given material + // Sub-meshes in this mesh, each with a given material std::vector mSubMeshes; }; -/** Which type of primitives the ReadPrimitives() function is going to read */ +/// Which type of primitives the ReadPrimitives() function is going to read enum PrimitiveType { Prim_Invalid, Prim_Lines, @@ -389,7 +391,7 @@ enum PrimitiveType { Prim_Polygon }; -/** A skeleton controller to deform a mesh with the use of joints */ +/// A skeleton controller to deform a mesh with the use of joints struct Controller { // controller type ControllerType mType; @@ -424,25 +426,25 @@ struct Controller { std::string mMorphWeight; }; -/** A collada material. Pretty much the only member is a reference to an effect. */ +/// A collada material. Pretty much the only member is a reference to an effect. struct Material { std::string mName; std::string mEffect; }; -/** Type of the effect param */ +/// Type of the effect param enum ParamType { Param_Sampler, Param_Surface }; -/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */ +/// A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them struct EffectParam { ParamType mType; std::string mReference; // to which other thing the param is referring to. }; -/** Shading type supported by the standard effect spec of Collada */ +/// Shading type supported by the standard effect spec of Collada enum ShadeType { Shade_Invalid, Shade_Constant, @@ -451,7 +453,7 @@ enum ShadeType { Shade_Blinn }; -/** Represents a texture sampler in collada */ +/// Represents a texture sampler in collada struct Sampler { Sampler() : mWrapU(true), @@ -463,77 +465,66 @@ struct Sampler { mWeighting(1.f), mMixWithPrevious(1.f) {} - /** Name of image reference - */ + /// Name of image reference std::string mName; - /** Wrap U? - */ + /// Wrap U? bool mWrapU; - /** Wrap V? - */ + /// Wrap V? bool mWrapV; - /** Mirror U? - */ + /// Mirror U? bool mMirrorU; - /** Mirror V? - */ + /// Mirror V? bool mMirrorV; - /** Blend mode - */ + /// Blend mode aiTextureOp mOp; - /** UV transformation - */ + /// UV transformation aiUVTransform mTransform; - /** Name of source UV channel - */ + /// Name of source UV channel std::string mUVChannel; - /** Resolved UV channel index or UINT_MAX if not known - */ + /// Resolved UV channel index or UINT_MAX if not known unsigned int mUVId; // OKINO/MAX3D extensions from here // ------------------------------------------------------- - /** Weighting factor - */ + /// Weighting factor ai_real mWeighting; - /** Mixing factor from OKINO - */ + /// Mixing factor from OKINO ai_real mMixWithPrevious; }; -/** A collada effect. Can contain about anything according to the Collada spec, - but we limit our version to a reasonable subset. */ +/// A collada effect. Can contain about anything according to the Collada spec, +/// but we limit our version to a reasonable subset. struct Effect { - // Shading mode + /// Shading mode ShadeType mShadeType; - // Colors + /// Colors aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, mTransparent, mReflective; - // Textures + /// Textures Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, mTexTransparent, mTexBump, mTexReflective; - // Scalar factory + /// Scalar factory ai_real mShininess, mRefractIndex, mReflectivity; ai_real mTransparency; bool mHasTransparency; bool mRGBTransparency; bool mInvertTransparency; - // local params referring to each other by their SID - typedef std::map ParamLibrary; + /// local params referring to each other by their SID + using ParamLibrary = std::map; ParamLibrary mParams; // MAX3D extensions @@ -561,65 +552,64 @@ struct Effect { } }; -/** An image, meaning texture */ +/// An image, meaning texture struct Image { std::string mFileName; - /** Embedded image data */ + /// Embedded image data std::vector mImageData; - /** File format hint of embedded image data */ + /// File format hint of embedded image data std::string mEmbeddedFormat; }; -/** An animation channel. */ +/// An animation channel. struct AnimationChannel { - /** URL of the data to animate. Could be about anything, but we support only the - * "NodeID/TransformID.SubElement" notation - */ + /// URL of the data to animate. Could be about anything, but we support only the + /// "NodeID/TransformID.SubElement" notation std::string mTarget; - /** Source URL of the time values. Collada calls them "input". Meh. */ + /// Source URL of the time values. Collada calls them "input". Meh. std::string mSourceTimes; - /** Source URL of the value values. Collada calls them "output". */ + /// Source URL of the value values. Collada calls them "output". std::string mSourceValues; - /** Source URL of the IN_TANGENT semantic values. */ + /// Source URL of the IN_TANGENT semantic values. std::string mInTanValues; - /** Source URL of the OUT_TANGENT semantic values. */ + /// Source URL of the OUT_TANGENT semantic values. std::string mOutTanValues; - /** Source URL of the INTERPOLATION semantic values. */ + /// Source URL of the INTERPOLATION semantic values. std::string mInterpolationValues; }; -/** An animation. Container for 0-x animation channels or 0-x animations */ +/// An animation. Container for 0-x animation channels or 0-x animations struct Animation { - /** Anim name */ + /// Anim name std::string mName; - /** the animation channels, if any */ + /// the animation channels, if any std::vector mChannels; - /** the sub-animations, if any */ + /// the sub-animations, if any std::vector mSubAnims; - /** Destructor */ + /// Destructor ~Animation() { - for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) + for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { delete *it; + } } - /** Collect all channels in the animation hierarchy into a single channel list. */ + /// Collect all channels in the animation hierarchy into a single channel list. void CollectChannelsRecursively(std::vector &channels) { channels.insert(channels.end(), mChannels.begin(), mChannels.end()); for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { Animation *pAnim = (*it); - pAnim->CollectChannelsRecursively(channels); } } - /** Combine all single-channel animations' channel into the same (parent) animation channel list. */ + /// Combine all single-channel animations' channel into the same (parent) animation channel list. void CombineSingleChannelAnimations() { CombineSingleChannelAnimationsRecursively(this); } @@ -658,9 +648,9 @@ struct Animation { } }; -/** Description of a collada animation channel which has been determined to affect the current node */ +/// Description of a collada animation channel which has been determined to affect the current node struct ChannelEntry { - const Collada::AnimationChannel *mChannel; ///> the source channel + const Collada::AnimationChannel *mChannel; ///< the source channel std::string mTargetId; std::string mTransformId; // the ID of the transformation step of the node which is influenced size_t mTransformIndex; // Index into the node's transform chain to apply the channel to diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 4beaf8431..99cb8c305 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -55,12 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include -#include -#include #include #include -#include + #include namespace Assimp { @@ -331,13 +328,15 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col // Resolve UV channels void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) { std::map::const_iterator it = table.mMap.find(sampler.mUVChannel); - if (it != table.mMap.end()) { - if (it->second.mType != Collada::IT_Texcoord) { - ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping"); - } - - sampler.mUVId = it->second.mSet; + if (it == table.mMap.end()) { + return; } + + if (it->second.mType != Collada::IT_Texcoord) { + ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping"); + } + + sampler.mUVId = it->second.mSet; } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 42aebdb6d..d84f76340 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaParser.h" #include #include -#include #include #include #include @@ -56,14 +55,47 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include -#include -#include - using namespace Assimp; using namespace Assimp::Collada; using namespace Assimp::Formatter; +static void ReportWarning(const char *msg, ...) { + ai_assert(nullptr != msg); + + va_list args; + va_start(args, msg); + + char szBuffer[3000]; + const int iLen = vsprintf(szBuffer, msg, args); + ai_assert(iLen > 0); + + va_end(args); + ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer, iLen)); +} + +static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) { + for (size_t i = 0; i < key_renaming.size(); ++i) { + if (key_renaming[i].first == collada_key) { + found_index = i; + return true; + } + } + found_index = std::numeric_limits::max(); + + return false; +} + +static void readUrlAttribute(XmlNode &node, std::string &url) { + url.clear(); + if (!XmlParser::getStdStrAttribute(node, "url", url)) { + return; + } + if (url[0] != '#') { + throw DeadlyImportError("Unknown reference format"); + } + url = url.c_str() + 1; +} + // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : @@ -137,10 +169,12 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : // ------------------------------------------------------------------------------------------------ // Destructor, private as well ColladaParser::~ColladaParser() { - for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) + for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) { delete it->second; - for (MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) + } + for (MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) { delete it->second; + } } // ------------------------------------------------------------------------------------------------ @@ -254,35 +288,35 @@ void ColladaParser::ReadContents(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads the structure of the file void ColladaParser::ReadStructure(XmlNode &node) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string name = std::string(currentNode.name()); - ASSIMP_LOG_DEBUG("last name" + name); - if (name == "asset") + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = std::string(currentNode.name()); + if (currentName == "asset") { ReadAssetInfo(currentNode); - else if (name == "library_animations") + } else if (currentName == "library_animations") { ReadAnimationLibrary(currentNode); - else if (name == "library_animation_clips") + } else if (currentName == "library_animation_clips") { ReadAnimationClipLibrary(currentNode); - else if (name == "library_controllers") + } else if (currentName == "library_controllers") { ReadControllerLibrary(currentNode); - else if (name == "library_images") + } else if (currentName == "library_images") { ReadImageLibrary(currentNode); - else if (name == "library_materials") + } else if (currentName == "library_materials") { ReadMaterialLibrary(currentNode); - else if (name == "library_effects") + } else if (currentName == "library_effects") { ReadEffectLibrary(currentNode); - else if (name == "library_geometries") + } else if (currentName == "library_geometries") { ReadGeometryLibrary(currentNode); - else if (name == "library_visual_scenes") + } else if (currentName == "library_visual_scenes") { ReadSceneLibrary(currentNode); - else if (name == "library_lights") + } else if (currentName == "library_lights") { ReadLightLibrary(currentNode); - else if (name == "library_cameras") + } else if (currentName == "library_cameras") { ReadCameraLibrary(currentNode); - else if (name == "library_nodes") + } else if (currentName == "library_nodes") { ReadSceneNode(currentNode, nullptr); /* some hacking to reuse this piece of code */ - else if (name == "scene") + } else if (currentName == "scene") { ReadScene(currentNode); + } } PostProcessRootAnimations(); @@ -296,17 +330,16 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string name = currentNode.name(); - if (name == "unit") { - pugi::xml_attribute attr = currentNode.attribute("meter"); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "unit") { mUnitSize = 1.f; - if (attr) { - mUnitSize = static_cast(attr.as_double()); - } - } else if (name == "up_axis") { + XmlParser::getFloatAttribute(node, "meter", mUnitSize); + } else if (currentName == "up_axis") { std::string v; - XmlParser::getValueAsString(currentNode, v); + if (!XmlParser::getValueAsString(currentNode, v)) { + continue; + } if (v == "X_UP") { mUpDirection = UP_X; } else if (v == "Z_UP") { @@ -314,9 +347,9 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) { } else { mUpDirection = UP_Y; } - } else if (name == "contributor") { - for (XmlNode currentChldNode : currentNode.children()) { - ReadMetaDataItem(currentChldNode, mAssetMetaData); + } else if (currentName == "contributor") { + for (XmlNode currentChildNode : currentNode.children()) { + ReadMetaDataItem(currentChildNode, mAssetMetaData); } } else { ReadMetaDataItem(currentNode, mAssetMetaData); @@ -324,43 +357,32 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) { } } -static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) { - for (size_t i = 0; i < key_renaming.size(); ++i) { - if (key_renaming[i].first == collada_key) { - found_index = i; - return true; - } - } - found_index = std::numeric_limits::max(); - - return false; -} - // ------------------------------------------------------------------------------------------------ // Reads a single string metadata item void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) { const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase(); - const std::string name = node.name(); if (name.empty()) { return; } std::string v; - if (XmlParser::getValueAsString(node, v)) { - trim(v); - aiString aistr; - aistr.Set(v); + if (!XmlParser::getValueAsString(node, v)) { + return; + } - std::string camel_key_str(name); - ToCamelCase(camel_key_str); + trim(v); + aiString aistr; + aistr.Set(v); - size_t found_index; - if (FindCommonKey(camel_key_str, key_renaming, found_index)) { - metadata.emplace(key_renaming[found_index].second, aistr); - } else { - metadata.emplace(camel_key_str, aistr); - } + std::string camel_key_str(name); + ToCamelCase(camel_key_str); + + size_t found_index; + if (FindCommonKey(camel_key_str, key_renaming, found_index)) { + metadata.emplace(key_renaming[found_index].second, aistr); + } else { + metadata.emplace(camel_key_str, aistr); } } @@ -372,14 +394,8 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) { } std::string animName; - pugi::xml_attribute nameAttr = node.attribute("name"); - if (nameAttr) { - animName = nameAttr.as_string(); - } else { - pugi::xml_attribute idAttr = node.attribute("id"); - if (idAttr) { - animName = idAttr.as_string(); - } else { + if (!XmlParser::getStdStrAttribute(node, "name", animName)) { + if (!XmlParser::getStdStrAttribute( node, "id", animName )) { animName = std::string("animation_") + to_string(mAnimationClipLibrary.size()); } } @@ -387,17 +403,12 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) { std::pair> clip; clip.first = animName; - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "instance_animation") { - pugi::xml_attribute url = currentNode.attribute("url"); - if (url) { - const std::string urlName = url.as_string(); - if (urlName[0] != '#') { - throw DeadlyImportError("Unknown reference format"); - } - clip.second.push_back(url.as_string()); - } + std::string url; + readUrlAttribute(node, url); + clip.second.push_back(url); } if (clip.second.size() > 0) { @@ -467,8 +478,8 @@ void ColladaParser::ReadAnimationLibrary(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "animation") { ReadAnimation(currentNode, &mAnims); } @@ -484,17 +495,14 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { // an element may be a container for grouping sub-elements or an animation channel // this is the channel collection by ID, in case it has channels - typedef std::map ChannelMap; + using ChannelMap = std::map ; ChannelMap channels; // this is the anim container in case we're a container Animation *anim = nullptr; // optional name given as an attribute std::string animName; - pugi::xml_attribute nameAttr = node.attribute("name"); - if (nameAttr) { - animName = nameAttr.as_string(); - } else { + if (!XmlParser::getStdStrAttribute(node, "name", animName)) { animName = "animation"; } @@ -504,8 +512,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { animID = idAttr.as_string(); } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "animation") { if (!anim) { anim = new Animation; @@ -518,23 +526,21 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { } else if (currentName == "source") { ReadSource(currentNode); } else if (currentName == "sampler") { - pugi::xml_attribute sampler_id = currentNode.attribute("id"); - if (sampler_id) { - std::string id = sampler_id.as_string(); - ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first; - + std::string id; + if (XmlParser::getStdStrAttribute(currentNode, "id", id)) { // have it read into a channel + ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first; ReadAnimationSampler(currentNode, newChannel->second); } else if (currentName == "channel") { - pugi::xml_attribute target = currentNode.attribute("target"); - pugi::xml_attribute source = currentNode.attribute("source"); - std::string source_name = source.as_string(); + std::string source_name, target; + XmlParser::getStdStrAttribute(currentNode, "source", source_name); + XmlParser::getStdStrAttribute(currentNode, "target", target); if (source_name[0] == '#') { source_name = source_name.substr(1, source_name.size() - 1); } ChannelMap::iterator cit = channels.find(source_name); if (cit != channels.end()) { - cit->second.mTarget = target.as_string(); + cit->second.mTarget = target; } } } @@ -561,8 +567,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { // ------------------------------------------------------------------------------------------------ // Reads an animation sampler into the given anim channel void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "input") { if (XmlParser::hasAttribute(currentNode, "semantic")) { std::string semantic, sourceAttr; @@ -575,16 +581,17 @@ void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChanne } source++; - if (semantic == "INPUT") + if (semantic == "INPUT") { pChannel.mSourceTimes = source; - else if (semantic == "OUTPUT") + } else if (semantic == "OUTPUT") { pChannel.mSourceValues = source; - else if (semantic == "IN_TANGENT") + } else if (semantic == "IN_TANGENT") { pChannel.mInTanValues = source; - else if (semantic == "OUT_TANGENT") + } else if (semantic == "OUT_TANGENT") { pChannel.mOutTanValues = source; - else if (semantic == "INTERPOLATION") + } else if (semantic == "INTERPOLATION") { pChannel.mInterpolationValues = source; + } } } } @@ -602,7 +609,6 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) { const std::string ¤tName = currentNode.name(); if (currentName != "controller") { continue; - ; } std::string id = node.attribute("id").as_string(); mControllerLibrary[id] = Controller(); @@ -616,7 +622,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll // initial values pController.mType = Skin; pController.mMethod = Normalized; - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "morph") { pController.mType = Morph; @@ -668,8 +674,8 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll // ------------------------------------------------------------------------------------------------ // Reads the joint definitions for the given controller void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "input") { const char *attrSemantic = currentNode.attribute("semantic").as_string(); const char *attrSource = currentNode.attribute("source").as_string(); @@ -696,8 +702,8 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC int vertexCount=0; XmlParser::getIntAttribute(node, "count", vertexCount); - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "input") { InputChannel channel; @@ -761,9 +767,9 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string name = currentNode.name(); - if (name == "image") { + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "image") { std::string id = currentNode.attribute("id").as_string(); mImageLibrary[id] = Image(); @@ -776,7 +782,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads an image entry into the given image void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string currentName = currentNode.name(); if (currentName == "image") { // Ignore @@ -796,23 +802,6 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { if (!pImage.mFileName.length()) { pImage.mFileName = "unknown_texture"; } - } else if (mFormat == FV_1_5_n) { - // make sure we skip over mip and array initializations, which - // we don't support, but which could confuse the loader if - // they're not skipped. - //int v = currentNode.attribute("ref").as_int(); - /* if (v y) { - ASSIMP_LOG_WARN("Collada: Ignoring texture array index"); - continue; - }*/ - - //v = currentNode.attribute("mip_index").as_int(); - /*if (attrib != -1 && v > 0) { - ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer"); - continue; - }*/ - - // TODO: correctly jump over cube and volume maps? } } else if (mFormat == FV_1_5_n) { std::string value; @@ -859,8 +848,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) { } std::map names; - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { std::string id = currentNode.attribute("id").as_string(); std::string name = currentNode.attribute("name").as_string(); mMaterialLibrary[id] = Material(); @@ -889,11 +877,13 @@ void ColladaParser::ReadLightLibrary(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "light") { - std::string id = currentNode.attribute("id").as_string(); - ReadLight(currentNode, mLightLibrary[id] = Light()); + std::string id; + if (XmlParser::getStdStrAttribute(currentNode, "id", id)) { + ReadLight(currentNode, mLightLibrary[id] = Light()); + } } } } @@ -905,18 +895,24 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "camera") { - std::string id = currentNode.attribute("id").as_string(); + std::string id; + if (!XmlParser::getStdStrAttribute(currentNode, "id", id)) { + continue; + } // create an entry and store it in the library under its ID Camera &cam = mCameraLibrary[id]; - std::string name = currentNode.attribute("name").as_string(); + std::string name; + if (!XmlParser::getStdStrAttribute(currentNode, "name", name)) { + continue; + } if (!name.empty()) { cam.mName = name; } - ReadCamera(currentNode, cam); + ReadCamera(currentNode, cam); } } } @@ -924,14 +920,12 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads a material entry into the given material void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) { - for (XmlNode currentNode : node.children()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "instance_effect") { - const char *url = currentNode.attribute("url").as_string(); - if (url[0] != '#') { - throw DeadlyImportError("Unknown reference format"); - } - pMaterial.mEffect = url + 1; + std::string url; + readUrlAttribute(currentNode, url); + pMaterial.mEffect = url.c_str(); } } } @@ -1030,7 +1024,7 @@ void ColladaParser::ReadEffectLibrary(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "effect") { // read ID. Do I have to repeat my ranting about "optional" attributes? @@ -1049,7 +1043,7 @@ void ColladaParser::ReadEffectLibrary(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads an effect entry into the given effect void ColladaParser::ReadEffect(XmlNode &node, Collada::Effect &pEffect) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "profile_COMMON") { ReadEffectProfileCommon(currentNode, pEffect); @@ -1254,8 +1248,6 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p } else if (currentName == "technique") { std::string profile; XmlParser::getStdStrAttribute(currentNode, "profile", profile); - //const int _profile = GetAttribute("profile"); - //const char *profile = mReader->getAttributeValue(_profile); // Some extensions are quite useful ... ReadSamplerProperties processes // several extensions in MAYA, OKINO and MAX3D profiles. @@ -1284,10 +1276,10 @@ void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam) if (node.empty()) { return; } + XmlNodeIterator xmlIt(node); xmlIt.collectChildrenPreOrder(node); XmlNode currentNode; - while (xmlIt.getNext(currentNode)) { const std::string ¤tName = currentNode.name(); if (currentName == "surface") { @@ -1313,6 +1305,11 @@ void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam) } pParam.mType = Param_Sampler; pParam.mReference = url.c_str() + 1; + } else if (currentName == "source") { + const char *source = currentNode.child_value(); + if (nullptr != source) { + pParam.mReference = source; + } } } } @@ -1323,7 +1320,7 @@ void ColladaParser::ReadGeometryLibrary(XmlNode &node) { if (node.empty()) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "geometry") { // read ID. Another entry which is "optional" by design but obligatory in reality @@ -1352,7 +1349,7 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) { if (node.empty()) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "mesh") { ReadMesh(currentNode, pMesh); @@ -1376,7 +1373,9 @@ void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) { ReadSource(currentNode); } else if (currentName == "vertices") { ReadVertexData(currentNode, pMesh); - } else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" || currentName == "polygons" || currentName == "polylist" || currentName == "trifans" || currentName == "tristrips") { + } else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" || + currentName == "polygons" || currentName == "polylist" || currentName == "trifans" || + currentName == "tristrips") { ReadIndexData(currentNode, pMesh); } } @@ -1534,16 +1533,11 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) { acc.mSubOffset[1] = acc.mParams.size(); else if (name == "P") acc.mSubOffset[2] = acc.mParams.size(); - // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size(); - /* 4D uv coordinates are not supported in Assimp */ - /* Generic extra data, interpreted as UV data, too*/ else if (name == "U") acc.mSubOffset[0] = acc.mParams.size(); else if (name == "V") acc.mSubOffset[1] = acc.mParams.size(); - //else - // DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." ); } if (XmlParser::hasAttribute(currentNode, "type")) { // read data type @@ -1568,7 +1562,7 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) { void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) { // extract the ID of the element. Not that we care, but to catch strange referencing schemes we should warn about XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID); - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "input") { ReadInputChannel(currentNode, pMesh.mPerVertexData); @@ -1726,20 +1720,20 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector element."); } - } else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) { throw DeadlyImportError("Expected different index count in

element."); } @@ -2023,7 +2016,7 @@ void ColladaParser::ReadSceneLibrary(XmlNode &node) { return; } - for (XmlNode currentNode : node.children()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "visual_scene") { // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? @@ -2190,11 +2183,8 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform // ------------------------------------------------------------------------------------------------ // Processes bind_vertex_input and bind elements void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl) { - //XmlNodeIterator xmlIt(node); - //xmlIt.collectChildrenPreOrder(node); - //XmlNode currentNode; std::string name = node.name(); - for (XmlNode currentNode : node.children()) { + for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); if (currentName == "bind_vertex_input") { Collada::InputSemanticMapEntry vn; @@ -2289,8 +2279,8 @@ void ColladaParser::ReadScene(XmlNode &node) { return; } - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = currentNode.name(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); if (currentName == "instance_visual_scene") { // should be the first and only occurrence if (mRootNode) { @@ -2314,20 +2304,6 @@ void ColladaParser::ReadScene(XmlNode &node) { } } -void ColladaParser::ReportWarning(const char *msg, ...) { - ai_assert(nullptr != msg); - - va_list args; - va_start(args, msg); - - char szBuffer[3000]; - const int iLen = vsprintf(szBuffer, msg, args); - ai_assert(iLen > 0); - - va_end(args); - ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer, iLen)); -} - // ------------------------------------------------------------------------------------------------ // Calculates the resulting transformation from all the given transform steps aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector &pTransforms) const { diff --git a/code/AssetLib/Collada/ColladaParser.h b/code/AssetLib/Collada/ColladaParser.h index 4b26b179c..5b8526b47 100644 --- a/code/AssetLib/Collada/ColladaParser.h +++ b/code/AssetLib/Collada/ColladaParser.h @@ -243,8 +243,6 @@ protected: void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); protected: - void ReportWarning(const char *msg, ...); - /** Calculates the resulting transformation from all the given transform steps */ aiMatrix4x4 CalculateResultTransform(const std::vector &pTransforms) const; @@ -260,56 +258,55 @@ protected: std::string mFileName; // XML reader, member for everyday use - //irr::io::IrrXMLReader *mReader; XmlParser mXmlParser; /** All data arrays found in the file by ID. Might be referred to by actually everyone. Collada, you are a steaming pile of indirection. */ - typedef std::map DataLibrary; + using DataLibrary = std::map ; DataLibrary mDataLibrary; /** Same for accessors which define how the data in a data array is accessed. */ - typedef std::map AccessorLibrary; + using AccessorLibrary = std::map ; AccessorLibrary mAccessorLibrary; /** Mesh library: mesh by ID */ - typedef std::map MeshLibrary; + using MeshLibrary = std::map; MeshLibrary mMeshLibrary; /** node library: root node of the hierarchy part by ID */ - typedef std::map NodeLibrary; + using NodeLibrary = std::map; NodeLibrary mNodeLibrary; /** Image library: stores texture properties by ID */ - typedef std::map ImageLibrary; + using ImageLibrary = std::map ; ImageLibrary mImageLibrary; /** Effect library: surface attributes by ID */ - typedef std::map EffectLibrary; + using EffectLibrary = std::map ; EffectLibrary mEffectLibrary; /** Material library: surface material by ID */ - typedef std::map MaterialLibrary; + using MaterialLibrary = std::map ; MaterialLibrary mMaterialLibrary; /** Light library: surface light by ID */ - typedef std::map LightLibrary; + using LightLibrary = std::map ; LightLibrary mLightLibrary; /** Camera library: surface material by ID */ - typedef std::map CameraLibrary; + using CameraLibrary = std::map ; CameraLibrary mCameraLibrary; /** Controller library: joint controllers by ID */ - typedef std::map ControllerLibrary; + using ControllerLibrary = std::map ; ControllerLibrary mControllerLibrary; /** Animation library: animation references by ID */ - typedef std::map AnimationLibrary; + using AnimationLibrary = std::map ; AnimationLibrary mAnimationLibrary; /** Animation clip library: clip animation references by ID */ - typedef std::vector>> AnimationClipLibrary; + using AnimationClipLibrary = std::vector>> ; AnimationClipLibrary mAnimationClipLibrary; /** Pointer to the root node. Don't delete, it just points to one of @@ -334,13 +331,6 @@ protected: Collada::FormatVersion mFormat; }; -// ------------------------------------------------------------------------------------------------ -// Check for element match -/*inline bool ColladaParser::IsElement(const char *pName) const { - ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT); - return ::strcmp(mReader->getNodeName(), pName) == 0; -}*/ - // ------------------------------------------------------------------------------------------------ // Finds the item in the given library by its reference, throws if not found template diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index 0ef5943c0..3590b9441 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -598,7 +598,7 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) { } // finally extract output meshes and add them to the scope - typedef std::pair pairt; + typedef std::pair pairt; for (const pairt &p : bymat) { aiMesh *const m = ToOutputMesh(p.second); scope.meshes_linear.push_back(m); diff --git a/code/AssetLib/glTF/glTFAsset.inl b/code/AssetLib/glTF/glTFAsset.inl index 41bdc508a..acda572c3 100644 --- a/code/AssetLib/glTF/glTFAsset.inl +++ b/code/AssetLib/glTF/glTFAsset.inl @@ -1060,7 +1060,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG inline void Camera::Read(Value &obj, Asset & /*r*/) { type = MemberOrDefault(obj, "type", Camera::Perspective); - const char *subobjId = (type == Camera::Orthographic) ? "ortographic" : "perspective"; + const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective"; Value *it = FindObject(obj, subobjId); if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters"); @@ -1071,10 +1071,10 @@ inline void Camera::Read(Value &obj, Asset & /*r*/) { perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); perspective.znear = MemberOrDefault(*it, "znear", 0.01f); } else { - ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); - ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); - ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); - ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); + ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f); + ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f); + ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f); + ortographic.znear = MemberOrDefault(*it, "znear", 0.01f); } } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 972154b5f..b1ba5b67b 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -69,8 +69,8 @@ using namespace glTFCommon; namespace { // generate bi-tangents from normals and tangents according to spec struct Tangent { - aiVector3D xyz; - ai_real w; + aiVector3D xyz; + ai_real w; }; } // namespace @@ -79,1283 +79,1282 @@ struct Tangent { // static const aiImporterDesc desc = { - "glTF2 Importer", - "", - "", - "", - aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, - 0, - 0, - 0, - 0, - "gltf glb" + "glTF2 Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "gltf glb" }; glTF2Importer::glTF2Importer() : - BaseImporter(), - meshOffsets(), - embeddedTexIdxs(), - mScene(nullptr) { - // empty + BaseImporter(), + meshOffsets(), + embeddedTexIdxs(), + mScene(nullptr) { + // empty } glTF2Importer::~glTF2Importer() { - // empty + // empty } const aiImporterDesc *glTF2Importer::GetInfo() const { - return &desc; + return &desc; } bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const { - const std::string &extension = GetExtension(pFile); + const std::string &extension = GetExtension(pFile); - if (extension != "gltf" && extension != "glb") { + if (extension != "gltf" && extension != "glb") { return false; - } + } - if (pIOHandler) { - glTF2::Asset asset(pIOHandler); - asset.Load(pFile, extension == "glb"); - std::string version = asset.asset.version; - return !version.empty() && version[0] == '2'; - } + if (pIOHandler) { + glTF2::Asset asset(pIOHandler); + asset.Load(pFile, extension == "glb"); + std::string version = asset.asset.version; + return !version.empty() && version[0] == '2'; + } - return false; + return false; } static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) { - switch (gltfWrapMode) { - case SamplerWrap::Mirrored_Repeat: - return aiTextureMapMode_Mirror; + switch (gltfWrapMode) { + case SamplerWrap::Mirrored_Repeat: + return aiTextureMapMode_Mirror; - case SamplerWrap::Clamp_To_Edge: - return aiTextureMapMode_Clamp; + case SamplerWrap::Clamp_To_Edge: + return aiTextureMapMode_Clamp; - case SamplerWrap::UNSET: - case SamplerWrap::Repeat: - default: - return aiTextureMapMode_Wrap; - } + case SamplerWrap::UNSET: + case SamplerWrap::Repeat: + default: + return aiTextureMapMode_Wrap; + } } inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) { - aiColor4D col; - CopyValue(prop, col); - mat->AddProperty(&col, 1, pKey, type, idx); + aiColor4D col; + CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); } inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) { - aiColor4D col; - glTFCommon::CopyValue(prop, col); - mat->AddProperty(&col, 1, pKey, type, idx); + aiColor4D col; + glTFCommon::CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); } inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset & /*r*/, glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { - if (prop.texture && prop.texture->source) { - aiString uri(prop.texture->source->uri); + if (prop.texture && prop.texture->source) { + aiString uri(prop.texture->source->uri); - int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; - if (texIdx != -1) { // embedded - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - uri.data[0] = '*'; - uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); - } + int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; + if (texIdx != -1) { // embedded + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + uri.data[0] = '*'; + uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); + } mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); mat->AddProperty(&prop.texCoord, 1, AI_MATKEY_GLTF_TEXTURE_TEXCOORD(texType, texSlot)); - if (prop.textureTransformSupported) { - aiUVTransform transform; - transform.mScaling.x = prop.TextureTransformExt_t.scale[0]; - transform.mScaling.y = prop.TextureTransformExt_t.scale[1]; - transform.mRotation = -prop.TextureTransformExt_t.rotation; // must be negated + if (prop.textureTransformSupported) { + aiUVTransform transform; + transform.mScaling.x = prop.TextureTransformExt_t.scale[0]; + transform.mScaling.y = prop.TextureTransformExt_t.scale[1]; + transform.mRotation = -prop.TextureTransformExt_t.rotation; // must be negated - // A change of coordinates is required to map glTF UV transformations into the space used by - // Assimp. In glTF all UV origins are at 0,1 (top left of texture) in Assimp space. In Assimp - // rotation occurs around the image center (0.5,0.5) where as in glTF rotation is around the - // texture origin. All three can be corrected for solely by a change of the translation since - // the transformations available are shape preserving. Note the importer already flips the V - // coordinate of the actual meshes during import. - const ai_real rcos(cos(-transform.mRotation)); - const ai_real rsin(sin(-transform.mRotation)); - transform.mTranslation.x = (static_cast( 0.5 ) * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0]; - transform.mTranslation.y = ((static_cast( 0.5 ) * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];; + // A change of coordinates is required to map glTF UV transformations into the space used by + // Assimp. In glTF all UV origins are at 0,1 (top left of texture) in Assimp space. In Assimp + // rotation occurs around the image center (0.5,0.5) where as in glTF rotation is around the + // texture origin. All three can be corrected for solely by a change of the translation since + // the transformations available are shape preserving. Note the importer already flips the V + // coordinate of the actual meshes during import. + const ai_real rcos(cos(-transform.mRotation)); + const ai_real rsin(sin(-transform.mRotation)); + transform.mTranslation.x = (static_cast( 0.5 ) * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0]; + transform.mTranslation.y = ((static_cast( 0.5 ) * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];; - mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); - } + mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); + } - if (prop.texture->sampler) { - Ref sampler = prop.texture->sampler; + if (prop.texture->sampler) { + Ref sampler = prop.texture->sampler; - aiString name(sampler->name); - aiString id(sampler->id); + aiString name(sampler->name); + aiString id(sampler->id); - mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot)); - mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot)); + mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot)); + mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot)); - aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS); - aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT); - mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot)); - mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot)); + aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS); + aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT); + mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot)); + mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot)); - if (sampler->magFilter != SamplerMagFilter::UNSET) { - mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot)); - } + if (sampler->magFilter != SamplerMagFilter::UNSET) { + mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot)); + } - if (sampler->minFilter != SamplerMinFilter::UNSET) { - mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); - } - } - } + if (sampler->minFilter != SamplerMinFilter::UNSET) { + mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); + } + } + } } inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::NormalTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { - SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); + SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); - if (prop.texture && prop.texture->source) { - mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot)); - } + if (prop.texture && prop.texture->source) { + mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot)); + } } inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::OcclusionTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) { - SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); + SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot); - if (prop.texture && prop.texture->source) { - mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot)); - } + if (prop.texture && prop.texture->source) { + mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot)); + } } static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, Material &mat) { - aiMaterial *aimat = new aiMaterial(); + aiMaterial *aimat = new aiMaterial(); - if (!mat.name.empty()) { - aiString str(mat.name); + if (!mat.name.empty()) { + aiString str(mat.name); - aimat->AddProperty(&str, AI_MATKEY_NAME); - } + aimat->AddProperty(&str, AI_MATKEY_NAME); + } - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); - aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); - aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); - float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; - roughnessAsShininess *= roughnessAsShininess * 1000; - aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); + float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; + roughnessAsShininess *= roughnessAsShininess * 1000; + aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); - SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); + SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); - aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); + aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); - aiString alphaMode(mat.alphaMode); - aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); - aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); + aiString alphaMode(mat.alphaMode); + aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); + aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); - //pbrSpecularGlossiness - if (mat.pbrSpecularGlossiness.isPresent) { - PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; + //pbrSpecularGlossiness + if (mat.pbrSpecularGlossiness.isPresent) { + PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; - aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); - SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); + aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); + SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); - float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; - aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); - aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); + float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; + aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); + aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); - } - if (mat.unlit) { - aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); - } + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); + } + if (mat.unlit) { + aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); + } - return aimat; + return aimat; } void glTF2Importer::ImportMaterials(glTF2::Asset &r) { - const unsigned int numImportedMaterials = unsigned(r.materials.Size()); - ASSIMP_LOG_DEBUG_F("Importing ", numImportedMaterials, " materials"); - Material defaultMaterial; + const unsigned int numImportedMaterials = unsigned(r.materials.Size()); + ASSIMP_LOG_DEBUG_F("Importing ", numImportedMaterials, " materials"); + Material defaultMaterial; - mScene->mNumMaterials = numImportedMaterials + 1; - mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; - mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); + mScene->mNumMaterials = numImportedMaterials + 1; + mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; + mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); - for (unsigned int i = 0; i < numImportedMaterials; ++i) { - mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]); - } + for (unsigned int i = 0; i < numImportedMaterials; ++i) { + mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]); + } } static inline void SetFaceAndAdvance1(aiFace*& face, unsigned int numVertices, unsigned int a) { - if (a >= numVertices) { - return; - } - face->mNumIndices = 1; - face->mIndices = new unsigned int[1]; - face->mIndices[0] = a; - ++face; + if (a >= numVertices) { + return; + } + face->mNumIndices = 1; + face->mIndices = new unsigned int[1]; + face->mIndices[0] = a; + ++face; } static inline void SetFaceAndAdvance2(aiFace*& face, unsigned int numVertices, unsigned int a, unsigned int b) { - if ((a >= numVertices) || (b >= numVertices)) { - return; - } - face->mNumIndices = 2; - face->mIndices = new unsigned int[2]; - face->mIndices[0] = a; - face->mIndices[1] = b; - ++face; + if ((a >= numVertices) || (b >= numVertices)) { + return; + } + face->mNumIndices = 2; + face->mIndices = new unsigned int[2]; + face->mIndices[0] = a; + face->mIndices[1] = b; + ++face; } static inline void SetFaceAndAdvance3(aiFace*& face, unsigned int numVertices, unsigned int a, unsigned int b, unsigned int c) { - if ((a >= numVertices) || (b >= numVertices) || (c >= numVertices)) { - return; - } - face->mNumIndices = 3; - face->mIndices = new unsigned int[3]; - face->mIndices[0] = a; - face->mIndices[1] = b; - face->mIndices[2] = c; - ++face; + if ((a >= numVertices) || (b >= numVertices) || (c >= numVertices)) { + return; + } + face->mNumIndices = 3; + face->mIndices = new unsigned int[3]; + face->mIndices[0] = a; + face->mIndices[1] = b; + face->mIndices[2] = c; + ++face; } #ifdef ASSIMP_BUILD_DEBUG static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsigned nVerts) { - for (unsigned i = 0; i < nFaces; ++i) { - for (unsigned j = 0; j < faces[i].mNumIndices; ++j) { - unsigned idx = faces[i].mIndices[j]; - if (idx >= nVerts) { - return false; - } - } - } - return true; + for (unsigned i = 0; i < nFaces; ++i) { + for (unsigned j = 0; j < faces[i].mNumIndices; ++j) { + unsigned idx = faces[i].mIndices[j]; + if (idx >= nVerts) { + return false; + } + } + } + return true; } #endif // ASSIMP_BUILD_DEBUG void glTF2Importer::ImportMeshes(glTF2::Asset &r) { - ASSIMP_LOG_DEBUG_F("Importing ", r.meshes.Size(), " meshes"); - std::vector> meshes; + ASSIMP_LOG_DEBUG_F("Importing ", r.meshes.Size(), " meshes"); + std::vector> meshes; - unsigned int k = 0; + unsigned int k = 0; meshOffsets.clear(); - for (unsigned int m = 0; m < r.meshes.Size(); ++m) { - Mesh &mesh = r.meshes[m]; + for (unsigned int m = 0; m < r.meshes.Size(); ++m) { + Mesh &mesh = r.meshes[m]; - meshOffsets.push_back(k); - k += unsigned(mesh.primitives.size()); + meshOffsets.push_back(k); + k += unsigned(mesh.primitives.size()); - for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { - Mesh::Primitive &prim = mesh.primitives[p]; + for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { + Mesh::Primitive &prim = mesh.primitives[p]; - aiMesh *aim = new aiMesh(); - meshes.push_back(std::unique_ptr(aim)); + aiMesh *aim = new aiMesh(); + meshes.push_back(std::unique_ptr(aim)); - aim->mName = mesh.name.empty() ? mesh.id : mesh.name; + aim->mName = mesh.name.empty() ? mesh.id : mesh.name; - if (mesh.primitives.size() > 1) { - ai_uint32 &len = aim->mName.length; - aim->mName.data[len] = '-'; - len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); - } + if (mesh.primitives.size() > 1) { + ai_uint32 &len = aim->mName.length; + aim->mName.data[len] = '-'; + len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); + } - switch (prim.mode) { - case PrimitiveMode_POINTS: - aim->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; + switch (prim.mode) { + case PrimitiveMode_POINTS: + aim->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; - case PrimitiveMode_LINES: - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: - aim->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; + case PrimitiveMode_LINES: + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: + aim->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; - case PrimitiveMode_TRIANGLES: - case PrimitiveMode_TRIANGLE_STRIP: - case PrimitiveMode_TRIANGLE_FAN: - aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - } + case PrimitiveMode_TRIANGLES: + case PrimitiveMode_TRIANGLE_STRIP: + case PrimitiveMode_TRIANGLE_FAN: + aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + } - Mesh::Primitive::Attributes &attr = prim.attributes; + Mesh::Primitive::Attributes &attr = prim.attributes; - if (attr.position.size() > 0 && attr.position[0]) { - aim->mNumVertices = static_cast(attr.position[0]->count); - attr.position[0]->ExtractData(aim->mVertices); - } + if (attr.position.size() > 0 && attr.position[0]) { + aim->mNumVertices = static_cast(attr.position[0]->count); + attr.position[0]->ExtractData(aim->mVertices); + } - if (attr.normal.size() > 0 && attr.normal[0]) { - attr.normal[0]->ExtractData(aim->mNormals); + if (attr.normal.size() > 0 && attr.normal[0]) { + attr.normal[0]->ExtractData(aim->mNormals); - // only extract tangents if normals are present - if (attr.tangent.size() > 0 && attr.tangent[0]) { - // generate bitangents from normals and tangents according to spec - Tangent *tangents = nullptr; + // only extract tangents if normals are present + if (attr.tangent.size() > 0 && attr.tangent[0]) { + // generate bitangents from normals and tangents according to spec + Tangent *tangents = nullptr; - attr.tangent[0]->ExtractData(tangents); + attr.tangent[0]->ExtractData(tangents); - aim->mTangents = new aiVector3D[aim->mNumVertices]; - aim->mBitangents = new aiVector3D[aim->mNumVertices]; + aim->mTangents = new aiVector3D[aim->mNumVertices]; + aim->mBitangents = new aiVector3D[aim->mNumVertices]; - for (unsigned int i = 0; i < aim->mNumVertices; ++i) { - aim->mTangents[i] = tangents[i].xyz; - aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w; - } + for (unsigned int i = 0; i < aim->mNumVertices; ++i) { + aim->mTangents[i] = tangents[i].xyz; + aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w; + } - delete[] tangents; - } - } + delete[] tangents; + } + } - for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) { - if (attr.color[c]->count != aim->mNumVertices) { - DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name + - "\" does not match the vertex count"); - continue; - } - attr.color[c]->ExtractData(aim->mColors[c]); - } - for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { + for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) { + if (attr.color[c]->count != aim->mNumVertices) { + DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name + + "\" does not match the vertex count"); + continue; + } + attr.color[c]->ExtractData(aim->mColors[c]); + } + for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { if (!attr.texcoord[tc]) { DefaultLogger::get()->warn("Texture coordinate accessor not found or non-contiguous texture coordinate sets."); continue; } - if (attr.texcoord[tc]->count != aim->mNumVertices) { - DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name + - "\" does not match the vertex count"); - continue; - } + if (attr.texcoord[tc]->count != aim->mNumVertices) { + DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name + + "\" does not match the vertex count"); + continue; + } - attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); - aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); + attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); + aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); - aiVector3D *values = aim->mTextureCoords[tc]; - for (unsigned int i = 0; i < aim->mNumVertices; ++i) { - values[i].y = 1 - values[i].y; // Flip Y coords - } - } + aiVector3D *values = aim->mTextureCoords[tc]; + for (unsigned int i = 0; i < aim->mNumVertices; ++i) { + values[i].y = 1 - values[i].y; // Flip Y coords + } + } - std::vector &targets = prim.targets; - if (targets.size() > 0) { - aim->mNumAnimMeshes = (unsigned int)targets.size(); - aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes]; - for (size_t i = 0; i < targets.size(); i++) { - aim->mAnimMeshes[i] = aiCreateAnimMesh(aim); - aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]); - Mesh::Primitive::Target &target = targets[i]; + std::vector &targets = prim.targets; + if (targets.size() > 0) { + aim->mNumAnimMeshes = (unsigned int)targets.size(); + aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes]; + for (size_t i = 0; i < targets.size(); i++) { + aim->mAnimMeshes[i] = aiCreateAnimMesh(aim); + aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]); + Mesh::Primitive::Target &target = targets[i]; - if (target.position.size() > 0) { - aiVector3D *positionDiff = nullptr; - target.position[0]->ExtractData(positionDiff); - for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; - } - delete[] positionDiff; - } - if (target.normal.size() > 0) { - aiVector3D *normalDiff = nullptr; - target.normal[0]->ExtractData(normalDiff); - for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; - } - delete[] normalDiff; - } - if (target.tangent.size() > 0) { - Tangent *tangent = nullptr; - attr.tangent[0]->ExtractData(tangent); + if (target.position.size() > 0) { + aiVector3D *positionDiff = nullptr; + target.position[0]->ExtractData(positionDiff); + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; + } + delete[] positionDiff; + } + if (target.normal.size() > 0) { + aiVector3D *normalDiff = nullptr; + target.normal[0]->ExtractData(normalDiff); + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; + } + delete[] normalDiff; + } + if (target.tangent.size() > 0) { + Tangent *tangent = nullptr; + attr.tangent[0]->ExtractData(tangent); - aiVector3D *tangentDiff = nullptr; - target.tangent[0]->ExtractData(tangentDiff); + aiVector3D *tangentDiff = nullptr; + target.tangent[0]->ExtractData(tangentDiff); - for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { - tangent[vertexId].xyz += tangentDiff[vertexId]; - aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; - aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; - } - delete[] tangent; - delete[] tangentDiff; - } - if (mesh.weights.size() > i) { - aiAnimMesh.mWeight = mesh.weights[i]; - } - if (mesh.targetNames.size() > i) { - aiAnimMesh.mName = mesh.targetNames[i]; - } - } - } + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { + tangent[vertexId].xyz += tangentDiff[vertexId]; + aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; + aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; + } + delete[] tangent; + delete[] tangentDiff; + } + if (mesh.weights.size() > i) { + aiAnimMesh.mWeight = mesh.weights[i]; + } + if (mesh.targetNames.size() > i) { + aiAnimMesh.mName = mesh.targetNames[i]; + } + } + } - aiFace *faces = nullptr; - aiFace *facePtr = nullptr; - size_t nFaces = 0; + aiFace *faces = nullptr; + aiFace *facePtr = nullptr; + size_t nFaces = 0; - if (prim.indices) { - size_t count = prim.indices->count; + if (prim.indices) { + size_t count = prim.indices->count; - Accessor::Indexer data = prim.indices->GetIndexer(); - ai_assert(data.IsValid()); + Accessor::Indexer data = prim.indices->GetIndexer(); + ai_assert(data.IsValid()); - switch (prim.mode) { - case PrimitiveMode_POINTS: { - nFaces = count; - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; ++i) { - SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i)); - } - break; - } + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i)); + } + break; + } - case PrimitiveMode_LINES: { - nFaces = count / 2; - if (nFaces * 2 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); - count = nFaces * 2; - } - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 2) { - SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1)); - } - break; - } + case PrimitiveMode_LINES: { + nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1)); + } + break; + } - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: { - nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); - facePtr = faces = new aiFace[nFaces]; - SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1)); - for (unsigned int i = 2; i < count; ++i) { - SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i)); - } - if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop - SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast(count) - 1), faces[0].mIndices[0]); - } - break; - } + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + facePtr = faces = new aiFace[nFaces]; + SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1)); + for (unsigned int i = 2; i < count; ++i) { + SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i)); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast(count) - 1), faces[0].mIndices[0]); + } + break; + } - case PrimitiveMode_TRIANGLES: { - nFaces = count / 3; - if (nFaces * 3 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); - count = nFaces * 3; - } - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 3) { - SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); - } - break; - } - case PrimitiveMode_TRIANGLE_STRIP: { - nFaces = count - 2; - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < nFaces; ++i) { - //The ordering is to ensure that the triangles are all drawn with the same orientation - if ((i + 1) % 2 == 0) { - //For even n, vertices n + 1, n, and n + 2 define triangle n - SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2)); - } else { - //For odd n, vertices n, n+1, and n+2 define triangle n - SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); - } - } - break; - } - case PrimitiveMode_TRIANGLE_FAN: - nFaces = count - 2; - facePtr = faces = new aiFace[nFaces]; - SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); - for (unsigned int i = 1; i < nFaces; ++i) { - SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2)); - } - break; - } - } else { // no indices provided so directly generate from counts + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < nFaces; ++i) { + //The ordering is to ensure that the triangles are all drawn with the same orientation + if ((i + 1) % 2 == 0) { + //For even n, vertices n + 1, n, and n + 2 define triangle n + SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2)); + } else { + //For odd n, vertices n, n+1, and n+2 define triangle n + SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + facePtr = faces = new aiFace[nFaces]; + SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 1; i < nFaces; ++i) { + SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + break; + } + } else { // no indices provided so directly generate from counts - // use the already determined count as it includes checks - unsigned int count = aim->mNumVertices; + // use the already determined count as it includes checks + unsigned int count = aim->mNumVertices; - switch (prim.mode) { - case PrimitiveMode_POINTS: { - nFaces = count; - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; ++i) { - SetFaceAndAdvance1(facePtr, aim->mNumVertices, i); - } - break; - } + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFaceAndAdvance1(facePtr, aim->mNumVertices, i); + } + break; + } - case PrimitiveMode_LINES: { - nFaces = count / 2; - if (nFaces * 2 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); - count = (unsigned int)nFaces * 2; - } - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 2) { - SetFaceAndAdvance2(facePtr, aim->mNumVertices, i, i + 1); - } - break; - } + case PrimitiveMode_LINES: { + nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = (unsigned int)nFaces * 2; + } + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFaceAndAdvance2(facePtr, aim->mNumVertices, i, i + 1); + } + break; + } - case PrimitiveMode_LINE_LOOP: - case PrimitiveMode_LINE_STRIP: { - nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); - facePtr = faces = new aiFace[nFaces]; - SetFaceAndAdvance2(facePtr, aim->mNumVertices, 0, 1); - for (unsigned int i = 2; i < count; ++i) { - SetFaceAndAdvance2(facePtr, aim->mNumVertices, i - 1, i); - } - if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop - SetFaceAndAdvance2(facePtr, aim->mNumVertices, count - 1, 0); - } - break; - } + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + facePtr = faces = new aiFace[nFaces]; + SetFaceAndAdvance2(facePtr, aim->mNumVertices, 0, 1); + for (unsigned int i = 2; i < count; ++i) { + SetFaceAndAdvance2(facePtr, aim->mNumVertices, i - 1, i); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFaceAndAdvance2(facePtr, aim->mNumVertices, count - 1, 0); + } + break; + } - case PrimitiveMode_TRIANGLES: { - nFaces = count / 3; - if (nFaces * 3 != count) { - ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); - count = (unsigned int)nFaces * 3; - } - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < count; i += 3) { - SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2); - } - break; - } - case PrimitiveMode_TRIANGLE_STRIP: { - nFaces = count - 2; - facePtr = faces = new aiFace[nFaces]; - for (unsigned int i = 0; i < nFaces; ++i) { - //The ordering is to ensure that the triangles are all drawn with the same orientation - if ((i + 1) % 2 == 0) { - //For even n, vertices n + 1, n, and n + 2 define triangle n - SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2); - } else { - //For odd n, vertices n, n+1, and n+2 define triangle n - SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2); - } - } - break; - } - case PrimitiveMode_TRIANGLE_FAN: - nFaces = count - 2; - facePtr = faces = new aiFace[nFaces]; - SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, 1, 2); - for (unsigned int i = 1; i < nFaces; ++i) { - SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, i + 1, i + 2); - } - break; - } - } + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = (unsigned int)nFaces * 3; + } + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + facePtr = faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < nFaces; ++i) { + //The ordering is to ensure that the triangles are all drawn with the same orientation + if ((i + 1) % 2 == 0) { + //For even n, vertices n + 1, n, and n + 2 define triangle n + SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2); + } else { + //For odd n, vertices n, n+1, and n+2 define triangle n + SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2); + } + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + facePtr = faces = new aiFace[nFaces]; + SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, 1, 2); + for (unsigned int i = 1; i < nFaces; ++i) { + SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, i + 1, i + 2); + } + break; + } + } - if (faces) { - aim->mFaces = faces; + if (faces) { + aim->mFaces = faces; const unsigned int actualNumFaces = static_cast(facePtr - faces); - if (actualNumFaces < nFaces) { - ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped."); - } - if (actualNumFaces == 0) - { - throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces"); - } - aim->mNumFaces = actualNumFaces; - ai_assert(CheckValidFacesIndices(faces, actualNumFaces, aim->mNumVertices)); - } + if (actualNumFaces < nFaces) { + ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped."); + } + if (actualNumFaces == 0) + { + throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces"); + } + aim->mNumFaces = actualNumFaces; + ai_assert(CheckValidFacesIndices(faces, actualNumFaces, aim->mNumVertices)); + } - if (prim.material) { - aim->mMaterialIndex = prim.material.GetIndex(); - } else { - aim->mMaterialIndex = mScene->mNumMaterials - 1; - } - } - } + if (prim.material) { + aim->mMaterialIndex = prim.material.GetIndex(); + } else { + aim->mMaterialIndex = mScene->mNumMaterials - 1; + } + } + } - meshOffsets.push_back(k); + meshOffsets.push_back(k); - CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); + CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); } void glTF2Importer::ImportCameras(glTF2::Asset &r) { - if (!r.cameras.Size()) return; + if (!r.cameras.Size()) return; const unsigned int numCameras = r.cameras.Size(); - ASSIMP_LOG_DEBUG_F("Importing ", numCameras, " cameras"); - mScene->mNumCameras = numCameras; - mScene->mCameras = new aiCamera *[numCameras]; + ASSIMP_LOG_DEBUG_F("Importing ", numCameras, " cameras"); + mScene->mNumCameras = numCameras; + mScene->mCameras = new aiCamera *[numCameras]; - for (size_t i = 0; i < numCameras; ++i) { - Camera &cam = r.cameras[i]; + for (size_t i = 0; i < numCameras; ++i) { + Camera &cam = r.cameras[i]; - aiCamera *aicam = mScene->mCameras[i] = new aiCamera(); + aiCamera *aicam = mScene->mCameras[i] = new aiCamera(); - // cameras point in -Z by default, rest is specified in node transform - aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f); + // cameras point in -Z by default, rest is specified in node transform + aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f); - if (cam.type == Camera::Perspective) { + if (cam.type == Camera::Perspective) { - aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); - aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; - aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; - } else { - aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; - aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; - aicam->mHorizontalFOV = 0.0; - aicam->mOrthographicWidth = cam.cameraProperties.ortographic.xmag; - aicam->mAspect = 1.0f; - if (0.f != cam.cameraProperties.ortographic.ymag) { - aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; - } - } - } + aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; + aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); + aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; + } else { + aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mOrthographicWidth = cam.cameraProperties.ortographic.xmag; + aicam->mAspect = 1.0f; + if (0.f != cam.cameraProperties.ortographic.ymag) { + aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; + } + } + } } void glTF2Importer::ImportLights(glTF2::Asset &r) { - if (!r.lights.Size()) - return; + if (!r.lights.Size()) + return; const unsigned int numLights = r.lights.Size(); - ASSIMP_LOG_DEBUG_F("Importing ", numLights, " lights"); - mScene->mNumLights = numLights; - mScene->mLights = new aiLight *[numLights]; + ASSIMP_LOG_DEBUG_F("Importing ", numLights, " lights"); + mScene->mNumLights = numLights; + mScene->mLights = new aiLight *[numLights]; - for (size_t i = 0; i < numLights; ++i) { - Light &light = r.lights[i]; + for (size_t i = 0; i < numLights; ++i) { + Light &light = r.lights[i]; - aiLight *ail = mScene->mLights[i] = new aiLight(); + aiLight *ail = mScene->mLights[i] = new aiLight(); - switch (light.type) { - case Light::Directional: - ail->mType = aiLightSource_DIRECTIONAL; - break; - case Light::Point: - ail->mType = aiLightSource_POINT; - break; - case Light::Spot: - ail->mType = aiLightSource_SPOT; - break; - } + switch (light.type) { + case Light::Directional: + ail->mType = aiLightSource_DIRECTIONAL; + break; + case Light::Point: + ail->mType = aiLightSource_POINT; + break; + case Light::Spot: + ail->mType = aiLightSource_SPOT; + break; + } - if (ail->mType != aiLightSource_POINT) { - ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f); - ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - } + if (ail->mType != aiLightSource_POINT) { + ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f); + ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f); + } - vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity }; - CopyValue(colorWithIntensity, ail->mColorAmbient); - CopyValue(colorWithIntensity, ail->mColorDiffuse); - CopyValue(colorWithIntensity, ail->mColorSpecular); + vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity }; + CopyValue(colorWithIntensity, ail->mColorAmbient); + CopyValue(colorWithIntensity, ail->mColorDiffuse); + CopyValue(colorWithIntensity, ail->mColorSpecular); - if (ail->mType == aiLightSource_DIRECTIONAL) { - ail->mAttenuationConstant = 1.0; - ail->mAttenuationLinear = 0.0; - ail->mAttenuationQuadratic = 0.0; - } else { - //in PBR attenuation is calculated using inverse square law which can be expressed - //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters - //this is correct equation for the case when range (see - //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual) - //is not present. When range is not present it is assumed that it is infinite and so numerator is 1. - //When range is present then numerator might be any value in range [0,1] and then assimps equation - //will not suffice. In this case range is added into metadata in ImportNode function - //and its up to implementation to read it when it wants to - ail->mAttenuationConstant = 0.0; - ail->mAttenuationLinear = 0.0; - ail->mAttenuationQuadratic = 1.0; - } + if (ail->mType == aiLightSource_DIRECTIONAL) { + ail->mAttenuationConstant = 1.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 0.0; + } else { + //in PBR attenuation is calculated using inverse square law which can be expressed + //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters + //this is correct equation for the case when range (see + //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual) + //is not present. When range is not present it is assumed that it is infinite and so numerator is 1. + //When range is present then numerator might be any value in range [0,1] and then assimps equation + //will not suffice. In this case range is added into metadata in ImportNode function + //and its up to implementation to read it when it wants to + ail->mAttenuationConstant = 0.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 1.0; + } - if (ail->mType == aiLightSource_SPOT) { - ail->mAngleInnerCone = light.innerConeAngle; - ail->mAngleOuterCone = light.outerConeAngle; - } - } + if (ail->mType == aiLightSource_SPOT) { + ail->mAngleInnerCone = light.innerConeAngle; + ail->mAngleOuterCone = light.outerConeAngle; + } + } } static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) { - if (node.matrix.isPresent) { - CopyValue(node.matrix.value, matrix); - } else { - if (node.translation.isPresent) { - aiVector3D trans; - CopyValue(node.translation.value, trans); - aiMatrix4x4 t; - aiMatrix4x4::Translation(trans, t); - matrix = matrix * t; - } + if (node.matrix.isPresent) { + CopyValue(node.matrix.value, matrix); + } else { + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + aiMatrix4x4 t; + aiMatrix4x4::Translation(trans, t); + matrix = matrix * t; + } - if (node.rotation.isPresent) { - aiQuaternion rot; - CopyValue(node.rotation.value, rot); - matrix = matrix * aiMatrix4x4(rot.GetMatrix()); - } + if (node.rotation.isPresent) { + aiQuaternion rot; + CopyValue(node.rotation.value, rot); + matrix = matrix * aiMatrix4x4(rot.GetMatrix()); + } - if (node.scale.isPresent) { - aiVector3D scal(1.f); - CopyValue(node.scale.value, scal); - aiMatrix4x4 s; - aiMatrix4x4::Scaling(scal, s); - matrix = matrix * s; - } - } + if (node.scale.isPresent) { + aiVector3D scal(1.f); + CopyValue(node.scale.value, scal); + aiMatrix4x4 s; + aiMatrix4x4::Scaling(scal, s); + matrix = matrix * s; + } + } } static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector> &map) { - Mesh::Primitive::Attributes &attr = primitive.attributes; - if (attr.weight.empty() || attr.joint.empty()) { - return; - } - if (attr.weight[0]->count != attr.joint[0]->count) { - return; - } + Mesh::Primitive::Attributes &attr = primitive.attributes; + if (attr.weight.empty() || attr.joint.empty()) { + return; + } + if (attr.weight[0]->count != attr.joint[0]->count) { + return; + } - size_t num_vertices = attr.weight[0]->count; + size_t num_vertices = attr.weight[0]->count; - struct Weights { - float values[4]; - }; - Weights *weights = nullptr; - attr.weight[0]->ExtractData(weights); + struct Weights { + float values[4]; + }; + Weights *weights = nullptr; + attr.weight[0]->ExtractData(weights); - struct Indices8 { - uint8_t values[4]; - }; - struct Indices16 { - uint16_t values[4]; - }; - Indices8 *indices8 = nullptr; - Indices16 *indices16 = nullptr; - if (attr.joint[0]->GetElementSize() == 4) { - attr.joint[0]->ExtractData(indices8); - } else { - attr.joint[0]->ExtractData(indices16); - } - // - if (nullptr == indices8 && nullptr == indices16) { - // Something went completely wrong! - ai_assert(false); - return; - } + struct Indices8 { + uint8_t values[4]; + }; + struct Indices16 { + uint16_t values[4]; + }; + Indices8 *indices8 = nullptr; + Indices16 *indices16 = nullptr; + if (attr.joint[0]->GetElementSize() == 4) { + attr.joint[0]->ExtractData(indices8); + } else { + attr.joint[0]->ExtractData(indices16); + } + // + if (nullptr == indices8 && nullptr == indices16) { + // Something went completely wrong! + ai_assert(false); + return; + } - for (size_t i = 0; i < num_vertices; ++i) { - for (int j = 0; j < 4; ++j) { - const unsigned int bone = (indices8 != nullptr) ? indices8[i].values[j] : indices16[i].values[j]; - const float weight = weights[i].values[j]; - if (weight > 0 && bone < map.size()) { - map[bone].reserve(8); - map[bone].emplace_back(static_cast(i), weight); - } - } - } + for (size_t i = 0; i < num_vertices; ++i) { + for (int j = 0; j < 4; ++j) { + const unsigned int bone = (indices8 != nullptr) ? indices8[i].values[j] : indices16[i].values[j]; + const float weight = weights[i].values[j]; + if (weight > 0 && bone < map.size()) { + map[bone].reserve(8); + map[bone].emplace_back(static_cast(i), weight); + } + } + } - delete[] weights; - delete[] indices8; - delete[] indices16; + delete[] weights; + delete[] indices8; + delete[] indices16; } static std::string GetNodeName(const Node &node) { - return node.name.empty() ? node.id : node.name; + return node.name.empty() ? node.id : node.name; } void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { - if (extension.mStringValue.isPresent) { - metadata->Add(extension.name.c_str(), aiString(extension.mStringValue.value)); - } else if (extension.mDoubleValue.isPresent) { - metadata->Add(extension.name.c_str(), extension.mDoubleValue.value); - } else if (extension.mUint64Value.isPresent) { - metadata->Add(extension.name.c_str(), extension.mUint64Value.value); - } else if (extension.mInt64Value.isPresent) { - metadata->Add(extension.name.c_str(), static_cast(extension.mInt64Value.value)); - } else if (extension.mBoolValue.isPresent) { - metadata->Add(extension.name.c_str(), extension.mBoolValue.value); - } else if (extension.mValues.isPresent) { - aiMetadata val; - for (size_t i = 0; i < extension.mValues.value.size(); ++i) { - ParseExtensions(&val, extension.mValues.value[i]); - } - metadata->Add(extension.name.c_str(), val); - } + if (extension.mStringValue.isPresent) { + metadata->Add(extension.name.c_str(), aiString(extension.mStringValue.value)); + } else if (extension.mDoubleValue.isPresent) { + metadata->Add(extension.name.c_str(), extension.mDoubleValue.value); + } else if (extension.mUint64Value.isPresent) { + metadata->Add(extension.name.c_str(), extension.mUint64Value.value); + } else if (extension.mInt64Value.isPresent) { + metadata->Add(extension.name.c_str(), static_cast(extension.mInt64Value.value)); + } else if (extension.mBoolValue.isPresent) { + metadata->Add(extension.name.c_str(), extension.mBoolValue.value); + } else if (extension.mValues.isPresent) { + aiMetadata val; + for (size_t i = 0; i < extension.mValues.value.size(); ++i) { + ParseExtensions(&val, extension.mValues.value[i]); + } + metadata->Add(extension.name.c_str(), val); + } } aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector &meshOffsets, glTF2::Ref &ptr) { - Node &node = *ptr; + Node &node = *ptr; - aiNode *ainode = new aiNode(GetNodeName(node)); + aiNode *ainode = new aiNode(GetNodeName(node)); - if (!node.children.empty()) { - ainode->mNumChildren = unsigned(node.children.size()); - ainode->mChildren = new aiNode *[ainode->mNumChildren]; + if (!node.children.empty()) { + ainode->mNumChildren = unsigned(node.children.size()); + ainode->mChildren = new aiNode *[ainode->mNumChildren]; - for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { - aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); - child->mParent = ainode; - ainode->mChildren[i] = child; - } - } + for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { + aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); + child->mParent = ainode; + ainode->mChildren[i] = child; + } + } - if (node.extensions) { - ainode->mMetaData = new aiMetadata; - ParseExtensions(ainode->mMetaData, node.extensions); - } + if (node.extensions) { + ainode->mMetaData = new aiMetadata; + ParseExtensions(ainode->mMetaData, node.extensions); + } - GetNodeTransform(ainode->mTransformation, node); + GetNodeTransform(ainode->mTransformation, node); - if (!node.meshes.empty()) { - // GLTF files contain at most 1 mesh per node. - assert(node.meshes.size() == 1); - int mesh_idx = node.meshes[0].GetIndex(); - int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; + if (!node.meshes.empty()) { + // GLTF files contain at most 1 mesh per node. + assert(node.meshes.size() == 1); + int mesh_idx = node.meshes[0].GetIndex(); + int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; - ainode->mNumMeshes = count; - ainode->mMeshes = new unsigned int[count]; + ainode->mNumMeshes = count; + ainode->mMeshes = new unsigned int[count]; - if (node.skin) { - for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { - aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; - unsigned int numBones =static_cast(node.skin->jointNames.size()); + if (node.skin) { + for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { + aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; + unsigned int numBones =static_cast(node.skin->jointNames.size()); - std::vector> weighting(numBones); - BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + std::vector> weighting(numBones); + BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); - unsigned int realNumBones = 0; - for (uint32_t i = 0; i < numBones; ++i) { - if (weighting[i].size() > 0) { - realNumBones++; - } - } + mesh->mNumBones = static_cast(numBones); + mesh->mBones = new aiBone *[mesh->mNumBones]; - mesh->mNumBones = static_cast(realNumBones); - mesh->mBones = new aiBone *[mesh->mNumBones]; + // GLTF and Assimp choose to store bone weights differently. + // GLTF has each vertex specify which bones influence the vertex. + // Assimp has each bone specify which vertices it has influence over. + // To convert this data, we first read over the vertex data and pull + // out the bone-to-vertex mapping. Then, when creating the aiBones, + // we copy the bone-to-vertex mapping into the bone. This is unfortunate + // both because it's somewhat slow and because, for many applications, + // we then need to reconvert the data back into the vertex-to-bone + // mapping which makes things doubly-slow. - // GLTF and Assimp choose to store bone weights differently. - // GLTF has each vertex specify which bones influence the vertex. - // Assimp has each bone specify which vertices it has influence over. - // To convert this data, we first read over the vertex data and pull - // out the bone-to-vertex mapping. Then, when creating the aiBones, - // we copy the bone-to-vertex mapping into the bone. This is unfortunate - // both because it's somewhat slow and because, for many applications, - // we then need to reconvert the data back into the vertex-to-bone - // mapping which makes things doubly-slow. + mat4 *pbindMatrices = nullptr; + node.skin->inverseBindMatrices->ExtractData(pbindMatrices); - mat4 *pbindMatrices = nullptr; - node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + for (uint32_t i = 0; i < numBones; ++i) { + const std::vector &weights = weighting[i]; + aiBone *bone = new aiBone(); - int cb = 0; - for (uint32_t i = 0; i < numBones; ++i) { - const std::vector &weights = weighting[i]; - if (weights.size() > 0) { - aiBone *bone = new aiBone(); + Ref joint = node.skin->jointNames[i]; + if (!joint->name.empty()) { + bone->mName = joint->name; + } else { + // Assimp expects each bone to have a unique name. + static const std::string kDefaultName = "bone_"; + char postfix[10] = { 0 }; + ASSIMP_itoa10(postfix, i); + bone->mName = (kDefaultName + postfix); + } + GetNodeTransform(bone->mOffsetMatrix, *joint); + CopyValue(pbindMatrices[i], bone->mOffsetMatrix); + bone->mNumWeights = static_cast(weights.size()); - Ref joint = node.skin->jointNames[i]; - if (!joint->name.empty()) { - bone->mName = joint->name; - } else { - // Assimp expects each bone to have a unique name. - static const std::string kDefaultName = "bone_"; - char postfix[10] = { 0 }; - ASSIMP_itoa10(postfix, i); - bone->mName = (kDefaultName + postfix); - } - GetNodeTransform(bone->mOffsetMatrix, *joint); - CopyValue(pbindMatrices[i], bone->mOffsetMatrix); - bone->mNumWeights = static_cast(weights.size()); - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); - mesh->mBones[cb++] = bone; - } - } + if (bone->mNumWeights > 0) { + bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + } else { + // Assimp expects all bones to have at least 1 weight. + bone->mWeights = new aiVertexWeight[1]; + bone->mNumWeights = 1; + bone->mWeights->mVertexId = 0; + bone->mWeights->mWeight = 0.f; + } + mesh->mBones[i] = bone; + } - if (pbindMatrices) { - delete[] pbindMatrices; - } - } - } + if (pbindMatrices) { + delete[] pbindMatrices; + } + } + } - int k = 0; - for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { - ainode->mMeshes[k] = j; - } - } + int k = 0; + for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { + ainode->mMeshes[k] = j; + } + } - if (node.camera) { - pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; - if (node.translation.isPresent) { - aiVector3D trans; - CopyValue(node.translation.value, trans); - pScene->mCameras[node.camera.GetIndex()]->mPosition = trans; - } - } + if (node.camera) { + pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + pScene->mCameras[node.camera.GetIndex()]->mPosition = trans; + } + } - if (node.light) { - pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + if (node.light) { + pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; - //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual - //it is added to meta data of parent node, because there is no other place to put it - if (node.light->range.isPresent) { - if (!ainode->mMetaData) { - ainode->mMetaData = aiMetadata::Alloc(1); - ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); - } - else { - ainode->mMetaData->Add("PBR_LightRange", node.light->range.value); - } - } - } + //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual + //it is added to meta data of parent node, because there is no other place to put it + if (node.light->range.isPresent) { + if (!ainode->mMetaData) { + ainode->mMetaData = aiMetadata::Alloc(1); + ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); + } + else { + ainode->mMetaData->Add("PBR_LightRange", node.light->range.value); + } + } + } - return ainode; + return ainode; } void glTF2Importer::ImportNodes(glTF2::Asset &r) { - if (!r.scene) { - throw DeadlyImportError("GLTF: No scene"); - } - ASSIMP_LOG_DEBUG("Importing nodes"); + if (!r.scene) { + throw DeadlyImportError("GLTF: No scene"); + } + ASSIMP_LOG_DEBUG("Importing nodes"); - std::vector> rootNodes = r.scene->nodes; + std::vector> rootNodes = r.scene->nodes; - // The root nodes - unsigned int numRootNodes = unsigned(rootNodes.size()); - if (numRootNodes == 1) { // a single root node: use it - mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); - } else if (numRootNodes > 1) { // more than one root node: create a fake root - aiNode *root = new aiNode("ROOT"); - root->mChildren = new aiNode *[numRootNodes]; - for (unsigned int i = 0; i < numRootNodes; ++i) { - aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); - node->mParent = root; - root->mChildren[root->mNumChildren++] = node; - } - mScene->mRootNode = root; - } else { - mScene->mRootNode = new aiNode("ROOT"); - } + // The root nodes + unsigned int numRootNodes = unsigned(rootNodes.size()); + if (numRootNodes == 1) { // a single root node: use it + mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); + } else if (numRootNodes > 1) { // more than one root node: create a fake root + aiNode *root = new aiNode("ROOT"); + root->mChildren = new aiNode *[numRootNodes]; + for (unsigned int i = 0; i < numRootNodes; ++i) { + aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); + node->mParent = root; + root->mChildren[root->mNumChildren++] = node; + } + mScene->mRootNode = root; + } else { + mScene->mRootNode = new aiNode("ROOT"); + } } struct AnimationSamplers { - AnimationSamplers() : - translation(nullptr), - rotation(nullptr), - scale(nullptr), - weight(nullptr) { - // empty - } + AnimationSamplers() : + translation(nullptr), + rotation(nullptr), + scale(nullptr), + weight(nullptr) { + // empty + } - Animation::Sampler *translation; - Animation::Sampler *rotation; - Animation::Sampler *scale; - Animation::Sampler *weight; + Animation::Sampler *translation; + Animation::Sampler *rotation; + Animation::Sampler *scale; + Animation::Sampler *weight; }; aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { - aiNodeAnim *anim = new aiNodeAnim(); - anim->mNodeName = GetNodeName(node); + aiNodeAnim *anim = new aiNodeAnim(); + anim->mNodeName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + static const float kMillisecondsFromSeconds = 1000.f; - if (samplers.translation) { - float *times = nullptr; - samplers.translation->input->ExtractData(times); - aiVector3D *values = nullptr; - samplers.translation->output->ExtractData(values); - anim->mNumPositionKeys = static_cast(samplers.translation->input->count); - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { - anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mPositionKeys[i].mValue = values[i]; - } - delete[] times; - delete[] values; - } else if (node.translation.isPresent) { - anim->mNumPositionKeys = 1; - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - anim->mPositionKeys->mTime = 0.f; - anim->mPositionKeys->mValue.x = node.translation.value[0]; - anim->mPositionKeys->mValue.y = node.translation.value[1]; - anim->mPositionKeys->mValue.z = node.translation.value[2]; - } + if (samplers.translation) { + float *times = nullptr; + samplers.translation->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.translation->output->ExtractData(values); + anim->mNumPositionKeys = static_cast(samplers.translation->input->count); + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { + anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mPositionKeys[i].mValue = values[i]; + } + delete[] times; + delete[] values; + } else if (node.translation.isPresent) { + anim->mNumPositionKeys = 1; + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + anim->mPositionKeys->mTime = 0.f; + anim->mPositionKeys->mValue.x = node.translation.value[0]; + anim->mPositionKeys->mValue.y = node.translation.value[1]; + anim->mPositionKeys->mValue.z = node.translation.value[2]; + } - if (samplers.rotation) { - float *times = nullptr; - samplers.rotation->input->ExtractData(times); - aiQuaternion *values = nullptr; - samplers.rotation->output->ExtractData(values); - anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { - anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mRotationKeys[i].mValue.x = values[i].w; - anim->mRotationKeys[i].mValue.y = values[i].x; - anim->mRotationKeys[i].mValue.z = values[i].y; - anim->mRotationKeys[i].mValue.w = values[i].z; - } - delete[] times; - delete[] values; - } else if (node.rotation.isPresent) { - anim->mNumRotationKeys = 1; - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - anim->mRotationKeys->mTime = 0.f; - anim->mRotationKeys->mValue.x = node.rotation.value[0]; - anim->mRotationKeys->mValue.y = node.rotation.value[1]; - anim->mRotationKeys->mValue.z = node.rotation.value[2]; - anim->mRotationKeys->mValue.w = node.rotation.value[3]; - } + if (samplers.rotation) { + float *times = nullptr; + samplers.rotation->input->ExtractData(times); + aiQuaternion *values = nullptr; + samplers.rotation->output->ExtractData(values); + anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { + anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mRotationKeys[i].mValue.x = values[i].w; + anim->mRotationKeys[i].mValue.y = values[i].x; + anim->mRotationKeys[i].mValue.z = values[i].y; + anim->mRotationKeys[i].mValue.w = values[i].z; + } + delete[] times; + delete[] values; + } else if (node.rotation.isPresent) { + anim->mNumRotationKeys = 1; + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + anim->mRotationKeys->mTime = 0.f; + anim->mRotationKeys->mValue.x = node.rotation.value[0]; + anim->mRotationKeys->mValue.y = node.rotation.value[1]; + anim->mRotationKeys->mValue.z = node.rotation.value[2]; + anim->mRotationKeys->mValue.w = node.rotation.value[3]; + } - if (samplers.scale) { - float *times = nullptr; - samplers.scale->input->ExtractData(times); - aiVector3D *values = nullptr; - samplers.scale->output->ExtractData(values); - anim->mNumScalingKeys = static_cast(samplers.scale->input->count); - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { - anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mScalingKeys[i].mValue = values[i]; - } - delete[] times; - delete[] values; - } else if (node.scale.isPresent) { - anim->mNumScalingKeys = 1; - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - anim->mScalingKeys->mTime = 0.f; - anim->mScalingKeys->mValue.x = node.scale.value[0]; - anim->mScalingKeys->mValue.y = node.scale.value[1]; - anim->mScalingKeys->mValue.z = node.scale.value[2]; - } + if (samplers.scale) { + float *times = nullptr; + samplers.scale->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.scale->output->ExtractData(values); + anim->mNumScalingKeys = static_cast(samplers.scale->input->count); + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { + anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mScalingKeys[i].mValue = values[i]; + } + delete[] times; + delete[] values; + } else if (node.scale.isPresent) { + anim->mNumScalingKeys = 1; + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + anim->mScalingKeys->mTime = 0.f; + anim->mScalingKeys->mValue.x = node.scale.value[0]; + anim->mScalingKeys->mValue.y = node.scale.value[1]; + anim->mScalingKeys->mValue.z = node.scale.value[2]; + } - return anim; + return anim; } aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { - aiMeshMorphAnim *anim = new aiMeshMorphAnim(); - anim->mName = GetNodeName(node); + aiMeshMorphAnim *anim = new aiMeshMorphAnim(); + anim->mName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + static const float kMillisecondsFromSeconds = 1000.f; - if (nullptr != samplers.weight) { - float *times = nullptr; - samplers.weight->input->ExtractData(times); - float *values = nullptr; - samplers.weight->output->ExtractData(values); - anim->mNumKeys = static_cast(samplers.weight->input->count); + if (nullptr != samplers.weight) { + float *times = nullptr; + samplers.weight->input->ExtractData(times); + float *values = nullptr; + samplers.weight->output->ExtractData(values); + anim->mNumKeys = static_cast(samplers.weight->input->count); - const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys; + const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys; - anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; - unsigned int k = 0u; - for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { - anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mKeys[i].mNumValuesAndWeights = numMorphs; - anim->mKeys[i].mValues = new unsigned int[numMorphs]; - anim->mKeys[i].mWeights = new double[numMorphs]; + anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; + unsigned int k = 0u; + for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { + anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mKeys[i].mNumValuesAndWeights = numMorphs; + anim->mKeys[i].mValues = new unsigned int[numMorphs]; + anim->mKeys[i].mWeights = new double[numMorphs]; - for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { - anim->mKeys[i].mValues[j] = j; - anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k]; - } - } + for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { + anim->mKeys[i].mValues[j] = j; + anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k]; + } + } - delete[] times; - delete[] values; - } + delete[] times; + delete[] values; + } - return anim; + return anim; } std::unordered_map GatherSamplers(Animation &anim) { - std::unordered_map samplers; - for (unsigned int c = 0; c < anim.channels.size(); ++c) { - Animation::Channel &channel = anim.channels[c]; - if (channel.sampler >= static_cast(anim.samplers.size())) { - continue; - } + std::unordered_map samplers; + for (unsigned int c = 0; c < anim.channels.size(); ++c) { + Animation::Channel &channel = anim.channels[c]; + if (channel.sampler >= static_cast(anim.samplers.size())) { + continue; + } - const unsigned int node_index = channel.target.node.GetIndex(); + const unsigned int node_index = channel.target.node.GetIndex(); - AnimationSamplers &sampler = samplers[node_index]; - if (channel.target.path == AnimationPath_TRANSLATION) { - sampler.translation = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_ROTATION) { - sampler.rotation = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_SCALE) { - sampler.scale = &anim.samplers[channel.sampler]; - } else if (channel.target.path == AnimationPath_WEIGHTS) { - sampler.weight = &anim.samplers[channel.sampler]; - } - } + AnimationSamplers &sampler = samplers[node_index]; + if (channel.target.path == AnimationPath_TRANSLATION) { + sampler.translation = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_ROTATION) { + sampler.rotation = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_SCALE) { + sampler.scale = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_WEIGHTS) { + sampler.weight = &anim.samplers[channel.sampler]; + } + } - return samplers; + return samplers; } void glTF2Importer::ImportAnimations(glTF2::Asset &r) { - if (!r.scene) return; + if (!r.scene) return; const unsigned numAnimations = r.animations.Size(); - ASSIMP_LOG_DEBUG_F("Importing ", numAnimations, " animations"); - mScene->mNumAnimations = numAnimations; - if (mScene->mNumAnimations == 0) { - return; - } + ASSIMP_LOG_DEBUG_F("Importing ", numAnimations, " animations"); + mScene->mNumAnimations = numAnimations; + if (mScene->mNumAnimations == 0) { + return; + } mScene->mAnimations = new aiAnimation *[numAnimations]; - for (unsigned int i = 0; i < numAnimations; ++i) { - Animation &anim = r.animations[i]; + for (unsigned int i = 0; i < numAnimations; ++i) { + Animation &anim = r.animations[i]; - aiAnimation *ai_anim = new aiAnimation(); - ai_anim->mName = anim.name; - ai_anim->mDuration = 0; - ai_anim->mTicksPerSecond = 0; + aiAnimation *ai_anim = new aiAnimation(); + ai_anim->mName = anim.name; + ai_anim->mDuration = 0; + ai_anim->mTicksPerSecond = 0; - std::unordered_map samplers = GatherSamplers(anim); + std::unordered_map samplers = GatherSamplers(anim); - uint32_t numChannels = 0u; - uint32_t numMorphMeshChannels = 0u; + uint32_t numChannels = 0u; + uint32_t numMorphMeshChannels = 0u; - for (auto &iter : samplers) { - if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { - ++numChannels; - } - if (nullptr != iter.second.weight) { - ++numMorphMeshChannels; - } - } + for (auto &iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ++numChannels; + } + if (nullptr != iter.second.weight) { + ++numMorphMeshChannels; + } + } - ai_anim->mNumChannels = numChannels; - if (ai_anim->mNumChannels > 0) { - ai_anim->mChannels = new aiNodeAnim *[ai_anim->mNumChannels]; - int j = 0; - for (auto &iter : samplers) { - if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { - ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); - ++j; - } - } - } + ai_anim->mNumChannels = numChannels; + if (ai_anim->mNumChannels > 0) { + ai_anim->mChannels = new aiNodeAnim *[ai_anim->mNumChannels]; + int j = 0; + for (auto &iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } - ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; - if (ai_anim->mNumMorphMeshChannels > 0) { - ai_anim->mMorphMeshChannels = new aiMeshMorphAnim *[ai_anim->mNumMorphMeshChannels]; - int j = 0; - for (auto &iter : samplers) { - if (nullptr != iter.second.weight) { - ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); - ++j; - } - } - } + ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; + if (ai_anim->mNumMorphMeshChannels > 0) { + ai_anim->mMorphMeshChannels = new aiMeshMorphAnim *[ai_anim->mNumMorphMeshChannels]; + int j = 0; + for (auto &iter : samplers) { + if (nullptr != iter.second.weight) { + ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } - // Use the latest keyframe for the duration of the animation - double maxDuration = 0; - unsigned int maxNumberOfKeys = 0; - for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { - auto chan = ai_anim->mChannels[j]; - if (chan->mNumPositionKeys) { - auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1]; - if (lastPosKey.mTime > maxDuration) { - maxDuration = lastPosKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); - } - if (chan->mNumRotationKeys) { - auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; - if (lastRotKey.mTime > maxDuration) { - maxDuration = lastRotKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); - } - if (chan->mNumScalingKeys) { - auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; - if (lastScaleKey.mTime > maxDuration) { - maxDuration = lastScaleKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); - } - } + // Use the latest keyframe for the duration of the animation + double maxDuration = 0; + unsigned int maxNumberOfKeys = 0; + for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { + auto chan = ai_anim->mChannels[j]; + if (chan->mNumPositionKeys) { + auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1]; + if (lastPosKey.mTime > maxDuration) { + maxDuration = lastPosKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); + } + if (chan->mNumRotationKeys) { + auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; + if (lastRotKey.mTime > maxDuration) { + maxDuration = lastRotKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); + } + if (chan->mNumScalingKeys) { + auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; + if (lastScaleKey.mTime > maxDuration) { + maxDuration = lastScaleKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); + } + } - for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { - const auto *const chan = ai_anim->mMorphMeshChannels[j]; + for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { + const auto *const chan = ai_anim->mMorphMeshChannels[j]; - if (0u != chan->mNumKeys) { - const auto &lastKey = chan->mKeys[chan->mNumKeys - 1u]; - if (lastKey.mTime > maxDuration) { - maxDuration = lastKey.mTime; - } - maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); - } - } + if (0u != chan->mNumKeys) { + const auto &lastKey = chan->mKeys[chan->mNumKeys - 1u]; + if (lastKey.mTime > maxDuration) { + maxDuration = lastKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); + } + } - ai_anim->mDuration = maxDuration; - ai_anim->mTicksPerSecond = 1000.0; + ai_anim->mDuration = maxDuration; + ai_anim->mTicksPerSecond = 1000.0; - mScene->mAnimations[i] = ai_anim; - } + mScene->mAnimations[i] = ai_anim; + } } void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { - embeddedTexIdxs.resize(r.images.Size(), -1); + embeddedTexIdxs.resize(r.images.Size(), -1); - int numEmbeddedTexs = 0; - for (size_t i = 0; i < r.images.Size(); ++i) { - if (r.images[i].HasData()) { - numEmbeddedTexs += 1; - } - } + int numEmbeddedTexs = 0; + for (size_t i = 0; i < r.images.Size(); ++i) { + if (r.images[i].HasData()) { + numEmbeddedTexs += 1; + } + } - if (numEmbeddedTexs == 0) - return; + if (numEmbeddedTexs == 0) + return; - ASSIMP_LOG_DEBUG_F("Importing ", numEmbeddedTexs, " embedded textures"); + ASSIMP_LOG_DEBUG_F("Importing ", numEmbeddedTexs, " embedded textures"); - mScene->mTextures = new aiTexture *[numEmbeddedTexs]; + mScene->mTextures = new aiTexture *[numEmbeddedTexs]; - // Add the embedded textures - for (size_t i = 0; i < r.images.Size(); ++i) { - Image &img = r.images[i]; - if (!img.HasData()) { - continue; - } + // Add the embedded textures + for (size_t i = 0; i < r.images.Size(); ++i) { + Image &img = r.images[i]; + if (!img.HasData()) { + continue; + } - int idx = mScene->mNumTextures++; - embeddedTexIdxs[i] = idx; + int idx = mScene->mNumTextures++; + embeddedTexIdxs[i] = idx; - aiTexture *tex = mScene->mTextures[idx] = new aiTexture(); + aiTexture *tex = mScene->mTextures[idx] = new aiTexture(); - size_t length = img.GetDataLength(); - void *data = img.StealData(); + size_t length = img.GetDataLength(); + void *data = img.StealData(); - tex->mFilename = img.name; - tex->mWidth = static_cast(length); - tex->mHeight = 0; - tex->pcData = reinterpret_cast(data); + tex->mFilename = img.name; + tex->mWidth = static_cast(length); + tex->mHeight = 0; + tex->pcData = reinterpret_cast(data); - if (!img.mimeType.empty()) { - const char *ext = strchr(img.mimeType.c_str(), '/') + 1; - if (ext) { - if (strcmp(ext, "jpeg") == 0) { + if (!img.mimeType.empty()) { + const char *ext = strchr(img.mimeType.c_str(), '/') + 1; + if (ext) { + if (strcmp(ext, "jpeg") == 0) { ext = "jpg"; } - size_t len = strlen(ext); - if (len <= 3) { - strcpy(tex->achFormatHint, ext); - } - } - } - } + size_t len = strlen(ext); + if (len <= 3) { + strcpy(tex->achFormatHint, ext); + } + } + } + } } void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) { - ASSIMP_LOG_DEBUG("Importing metadata"); + ASSIMP_LOG_DEBUG("Importing metadata"); ai_assert(mScene->mMetaData == nullptr); const bool hasVersion = !a.asset.version.empty(); const bool hasGenerator = !a.asset.generator.empty(); @@ -1378,37 +1377,37 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO ASSIMP_LOG_DEBUG("Reading GLTF2 file"); - // clean all member arrays - meshOffsets.clear(); - embeddedTexIdxs.clear(); + // clean all member arrays + meshOffsets.clear(); + embeddedTexIdxs.clear(); - this->mScene = pScene; + this->mScene = pScene; - // read the asset file - glTF2::Asset asset(pIOHandler); - asset.Load(pFile, GetExtension(pFile) == "glb"); + // read the asset file + glTF2::Asset asset(pIOHandler); + asset.Load(pFile, GetExtension(pFile) == "glb"); - // - // Copy the data out - // + // + // Copy the data out + // - ImportEmbeddedTextures(asset); - ImportMaterials(asset); + ImportEmbeddedTextures(asset); + ImportMaterials(asset); - ImportMeshes(asset); + ImportMeshes(asset); - ImportCameras(asset); - ImportLights(asset); + ImportCameras(asset); + ImportLights(asset); - ImportNodes(asset); + ImportNodes(asset); - ImportAnimations(asset); + ImportAnimations(asset); ImportCommonMetadata(asset); - if (pScene->mNumMeshes == 0) { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } + if (pScene->mNumMeshes == 0) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } } #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index efeae03b1..b9c4d2bc3 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 3abf4ca20..21942eed4 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -44,22 +44,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define INCLUDED_AI_STRINGUTILS_H #ifdef __GNUC__ -# pragma GCC system_header +#pragma GCC system_header #endif #include -#include #include -#include -#include +#include #include +#include #include +#include #ifdef _MSC_VER -# define AI_SIZEFMT "%Iu" +#define AI_SIZEFMT "%Iu" #else -# define AI_SIZEFMT "%zu" +#define AI_SIZEFMT "%zu" #endif /// @fn ai_snprintf @@ -71,35 +71,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// @return The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned. #if defined(_MSC_VER) && _MSC_VER < 1900 - AI_FORCE_INLINE - int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { - int count(-1); - if (0 != size) { - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - } - if (count == -1) { - count = _vscprintf(format, ap); - } +AI_FORCE_INLINE +int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { + int count(-1); + if (0 != size) { + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + } + if (count == -1) { + count = _vscprintf(format, ap); + } - return count; - } + return count; +} - AI_FORCE_INLINE - int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { - int count; - va_list ap; +AI_FORCE_INLINE +int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { + int count; + va_list ap; - va_start(ap, format); - count = c99_ai_vsnprintf(outBuf, size, format, ap); - va_end(ap); + va_start(ap, format); + count = c99_ai_vsnprintf(outBuf, size, format, ap); + va_end(ap); - return count; - } + return count; +} #elif defined(__MINGW32__) -# define ai_snprintf __mingw_snprintf +#define ai_snprintf __mingw_snprintf #else -# define ai_snprintf snprintf +#define ai_snprintf snprintf #endif /// @fn to_string @@ -107,8 +107,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// @param value The value to write into the std::string. /// @return The value as a std::string template -AI_FORCE_INLINE -std::string to_string( T value ) { +AI_FORCE_INLINE std::string to_string(T value) { std::ostringstream os; os << value; @@ -121,17 +120,17 @@ std::string to_string( T value ) { /// @param end The last character /// @return The float value, 0.0f in cas of an error. AI_FORCE_INLINE -float ai_strtof( const char *begin, const char *end ) { - if ( nullptr == begin ) { +float ai_strtof(const char *begin, const char *end) { + if (nullptr == begin) { return 0.0f; } - float val( 0.0f ); - if ( nullptr == end ) { - val = static_cast< float >( ::atof( begin ) ); + float val(0.0f); + if (nullptr == end) { + val = static_cast(::atof(begin)); } else { - std::string::size_type len( end - begin ); - std::string token( begin, len ); - val = static_cast< float >( ::atof( token.c_str() ) ); + std::string::size_type len(end - begin); + std::string token(begin, len); + val = static_cast(::atof(token.c_str())); } return val; @@ -141,16 +140,15 @@ float ai_strtof( const char *begin, const char *end ) { /// @brief The portable to convert a decimal value into a hexadecimal string. /// @param toConvert Value to convert /// @return The hexadecimal string, is empty in case of an error. -template -AI_FORCE_INLINE -std::string DecimalToHexa( T toConvert ) { +template +AI_FORCE_INLINE std::string DecimalToHexa(T toConvert) { std::string result; std::stringstream ss; ss << std::hex << toConvert; ss >> result; - for ( size_t i = 0; i < result.size(); ++i ) { - result[ i ] = (char) toupper( result[ i ] ); + for (size_t i = 0; i < result.size(); ++i) { + result[i] = (char)toupper(result[i]); } return result; @@ -164,31 +162,32 @@ std::string DecimalToHexa( T toConvert ) { /// @param with_head # /// @return The hexadecimal string, is empty in case of an error. AI_FORCE_INLINE std::string Rgba2Hex(int r, int g, int b, int a, bool with_head) { - std::stringstream ss; - if (with_head) { - ss << "#"; + std::stringstream ss; + if (with_head) { + ss << "#"; } - ss << std::hex << (r << 24 | g << 16 | b << 8 | a); + ss << std::hex << (r << 24 | g << 16 | b << 8 | a); return ss.str(); } // trim from start (in place) -inline void ltrim(std::string &s) { +AI_FORCE_INLINE void ltrim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); } // trim from end (in place) -inline void rtrim(std::string &s) { +AI_FORCE_INLINE void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); - }).base(), s.end()); + }).base(), + s.end()); } // trim from both ends (in place) -inline void trim(std::string &s) { +AI_FORCE_INLINE void trim(std::string &s) { ltrim(s); rtrim(s); } diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index 9dca314de..3d430a278 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -179,7 +179,7 @@ public: return true; } - static inline bool getFloatAttribute( XmlNode &xmlNode, const char *name, float &val ) { + static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val ) { pugi::xml_attribute attr = xmlNode.attribute(name); if (attr.empty()) { return false; @@ -190,6 +190,16 @@ public: } + static inline bool getDoubleAttribute( XmlNode &xmlNode, const char *name, double &val ) { + pugi::xml_attribute attr = xmlNode.attribute(name); + if (attr.empty()) { + return false; + } + + val = attr.as_double(); + return true; + } + static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) { pugi::xml_attribute attr = xmlNode.attribute(name); if (attr.empty()) {