Merge branch 'master' into fix/xcode-compile-20201018

pull/3463/head
John Mai 2020-10-23 14:06:25 +08:00 committed by GitHub
commit cea54d1ac5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1407 additions and 1441 deletions

1
.github/FUNDING.yml vendored
View File

@ -1,3 +1,2 @@
patreon: assimp patreon: assimp
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4 custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
open_collective: assimp

View File

@ -353,7 +353,7 @@ ELSE()
ENDIF() ENDIF()
# Only generate this target if no higher-level project already has # 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 # 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) 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") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

View File

@ -573,7 +573,7 @@ bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &
index_str = index_str.substr(1, std::string::npos); index_str = index_str.substr(1, std::string::npos);
try { try {
index = (unsigned int)strtoul10_64(index_str.c_str()); index = (unsigned int)strtoul10_64<DeadlyExportError>(index_str.c_str());
} catch (std::exception &error) { } catch (std::exception &error) {
throw DeadlyExportError(error.what()); throw DeadlyExportError(error.what());
} }

View File

@ -1,5 +1,3 @@
/** Helper structures for the Collada loader */
/* /*
Open Asset Import Library (assimp) 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" #include "ColladaHelper.h"

View File

@ -1,12 +1,9 @@
/** Helper structures for the Collada loader */
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 #ifndef AI_COLLADAHELPER_H_INC
#define AI_COLLADAHELPER_H_INC #define AI_COLLADAHELPER_H_INC
#include <assimp/light.h> #include <assimp/light.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include <stdint.h> #include <stdint.h>
#include <map> #include <map>
#include <set> #include <set>
@ -58,14 +58,14 @@ struct aiMaterial;
namespace Assimp { namespace Assimp {
namespace Collada { namespace Collada {
/** Collada file versions which evolved during the years ... */ /// Collada file versions which evolved during the years ...
enum FormatVersion { enum FormatVersion {
FV_1_5_n, FV_1_5_n,
FV_1_4_n, FV_1_4_n,
FV_1_3_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 { enum TransformType {
TF_LOOKAT, TF_LOOKAT,
TF_ROTATE, TF_ROTATE,
@ -75,7 +75,7 @@ enum TransformType {
TF_MATRIX TF_MATRIX
}; };
/** Different types of input data to a vertex or face */ /// Different types of input data to a vertex or face
enum InputType { enum InputType {
IT_Invalid, IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data. IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
@ -87,38 +87,39 @@ enum InputType {
IT_Bitangent IT_Bitangent
}; };
/** Supported controller types */ /// Supported controller types
enum ControllerType { enum ControllerType {
Skin, Skin,
Morph Morph
}; };
/** Supported morph methods */ /// Supported morph methods
enum MorphMethod { enum MorphMethod {
Normalized, Normalized,
Relative Relative
}; };
/** Common metadata keys as <Collada, Assimp> */ /// Common metadata keys as <Collada, Assimp>
typedef std::pair<std::string, std::string> MetaKeyPair; using MetaKeyPair = std::pair<std::string, std::string>;
typedef std::vector<MetaKeyPair> MetaKeyPairVector; using MetaKeyPairVector = std::vector<MetaKeyPair>;
// Collada as lower_case (native) /// Collada as lower_case (native)
const MetaKeyPairVector &GetColladaAssimpMetaKeys(); const MetaKeyPairVector &GetColladaAssimpMetaKeys();
// Collada as CamelCase (used by Assimp for consistency) // Collada as CamelCase (used by Assimp for consistency)
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); 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); 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 { struct Transform {
std::string mID; ///< SID of the transform step, by which anim channels address their target node std::string mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType; TransformType mType;
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
}; };
/** A collada camera. */ /// A collada camera.
struct Camera { struct Camera {
Camera() : Camera() :
mOrtho(false), mOrtho(false),
@ -128,22 +129,22 @@ struct Camera {
mZNear(0.1f), mZNear(0.1f),
mZFar(1000.f) {} mZFar(1000.f) {}
// Name of camera /// Name of camera
std::string mName; std::string mName;
// True if it is an orthografic camera /// True if it is an orthographic camera
bool mOrtho; bool mOrtho;
//! Horizontal field of view in degrees /// Horizontal field of view in degrees
ai_real mHorFov; ai_real mHorFov;
//! Vertical field of view in degrees /// Vertical field of view in degrees
ai_real mVerFov; ai_real mVerFov;
//! Screen aspect /// Screen aspect
ai_real mAspect; ai_real mAspect;
//! Near& far z /// Near& far z
ai_real mZNear, mZFar; ai_real mZNear, mZFar;
}; };
@ -162,27 +163,27 @@ struct Light {
mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
mIntensity(1.f) {} mIntensity(1.f) {}
//! Type of the light source aiLightSourceType + ambient /// Type of the light source aiLightSourceType + ambient
unsigned int mType; unsigned int mType;
//! Color of the light /// Color of the light
aiColor3D mColor; aiColor3D mColor;
//! Light attenuation /// Light attenuation
ai_real mAttConstant, mAttLinear, mAttQuadratic; ai_real mAttConstant, mAttLinear, mAttQuadratic;
//! Spot light falloff /// Spot light falloff
ai_real mFalloffAngle; ai_real mFalloffAngle;
ai_real mFalloffExponent; ai_real mFalloffExponent;
// ----------------------------------------------------- // -----------------------------------------------------
// FCOLLADA extension from here // FCOLLADA extension from here
//! ... related stuff from maja and max extensions /// ... related stuff from maja and max extensions
ai_real mPenumbraAngle; ai_real mPenumbraAngle;
ai_real mOuterAngle; ai_real mOuterAngle;
//! Common light intensity /// Common light intensity
ai_real mIntensity; ai_real mIntensity;
}; };
@ -192,30 +193,29 @@ struct InputSemanticMapEntry {
mSet(0), mSet(0),
mType(IT_Invalid) {} mType(IT_Invalid) {}
//! Index of set, optional /// Index of set, optional
unsigned int mSet; unsigned int mSet;
//! Type of referenced vertex input /// Type of referenced vertex input
InputType mType; InputType mType;
}; };
/** Table to map from effect to vertex input semantics */ /// Table to map from effect to vertex input semantics
struct SemanticMappingTable { struct SemanticMappingTable {
//! Name of material /// Name of material
std::string mMatName; 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<std::string, InputSemanticMapEntry> mMap; std::map<std::string, InputSemanticMapEntry> mMap;
//! For std::find /// For std::find
bool operator==(const std::string &s) const { bool operator==(const std::string &s) const {
return s == mMatName; return s == mMatName;
} }
}; };
/** A reference to a mesh inside a node, including materials assigned to the various subgroups. /// 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 /// The ID refers to either a mesh or a controller which specifies the mesh
*/
struct MeshInstance { struct MeshInstance {
///< ID of the mesh or controller to be instanced ///< ID of the mesh or controller to be instanced
std::string mMeshOrController; std::string mMeshOrController;
@ -224,25 +224,25 @@ struct MeshInstance {
std::map<std::string, SemanticMappingTable> mMaterials; std::map<std::string, SemanticMappingTable> mMaterials;
}; };
/** A reference to a camera inside a node*/ /// A reference to a camera inside a node
struct CameraInstance { struct CameraInstance {
///< ID of the camera ///< ID of the camera
std::string mCamera; std::string mCamera;
}; };
/** A reference to a light inside a node*/ /// A reference to a light inside a node
struct LightInstance { struct LightInstance {
///< ID of the camera ///< ID of the camera
std::string mLight; std::string mLight;
}; };
/** A reference to a node inside a node*/ /// A reference to a node inside a node
struct NodeInstance { struct NodeInstance {
///< ID of the node ///< ID of the node
std::string mNode; std::string mNode;
}; };
/** A node in a scene hierarchy */ /// A node in a scene hierarchy
struct Node { struct Node {
std::string mName; std::string mName;
std::string mID; std::string mID;
@ -250,52 +250,53 @@ struct Node {
Node *mParent; Node *mParent;
std::vector<Node *> mChildren; std::vector<Node *> mChildren;
/** Operations in order to calculate the resulting transformation to parent. */ /// Operations in order to calculate the resulting transformation to parent.
std::vector<Transform> mTransforms; std::vector<Transform> mTransforms;
/** Meshes at this node */ /// Meshes at this node
std::vector<MeshInstance> mMeshes; std::vector<MeshInstance> mMeshes;
/** Lights at this node */ /// Lights at this node
std::vector<LightInstance> mLights; std::vector<LightInstance> mLights;
/** Cameras at this node */ /// Cameras at this node
std::vector<CameraInstance> mCameras; std::vector<CameraInstance> mCameras;
/** Node instances at this node */ /// Node instances at this node
std::vector<NodeInstance> mNodeInstances; std::vector<NodeInstance> mNodeInstances;
/** Root-nodes: Name of primary camera, if any */ /// Root-nodes: Name of primary camera, if any
std::string mPrimaryCamera; std::string mPrimaryCamera;
//! Constructor. Begin with a zero parent /// Constructor. Begin with a zero parent
Node() : Node() :
mParent(nullptr) { mParent(nullptr) {
// empty // empty
} }
//! Destructor: delete all children subsequently /// Destructor: delete all children subsequently
~Node() { ~Node() {
for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
delete *it; delete *it;
}
} }
}; };
/** Data source array: either floats or strings */ /// Data source array: either floats or strings
struct Data { struct Data {
bool mIsStringArray; bool mIsStringArray;
std::vector<ai_real> mValues; std::vector<ai_real> mValues;
std::vector<std::string> mStrings; std::vector<std::string> mStrings;
}; };
/** Accessor to a data array */ /// Accessor to a data array
struct Accessor { struct Accessor {
size_t mCount; // in number of objects size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1) size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values size_t mOffset; // in number of values
size_t mStride; // Stride in number of values size_t mStride; // Stride in number of values
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore. std::vector<std::string> 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. // 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 std::string mSource; // URL of the source array
mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else 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 { struct Face {
std::vector<size_t> mIndices; std::vector<size_t> 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 { struct InputChannel {
InputType mType; // Type of the data InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given 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 { struct SubMesh {
std::string mMaterial; ///< subgroup identifier 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 { struct Mesh {
Mesh(const std::string &id) : Mesh(const std::string &id) :
mId(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; mNumUVComponents[i] = 2;
}
} }
const std::string mId; const std::string mId;
@ -373,11 +375,11 @@ struct Mesh {
// necessary for bone weight assignment // necessary for bone weight assignment
std::vector<size_t> mFacePosIndices; std::vector<size_t> mFacePosIndices;
// Submeshes in this mesh, each with a given material // Sub-meshes in this mesh, each with a given material
std::vector<SubMesh> mSubMeshes; std::vector<SubMesh> 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 { enum PrimitiveType {
Prim_Invalid, Prim_Invalid,
Prim_Lines, Prim_Lines,
@ -389,7 +391,7 @@ enum PrimitiveType {
Prim_Polygon 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 { struct Controller {
// controller type // controller type
ControllerType mType; ControllerType mType;
@ -424,25 +426,25 @@ struct Controller {
std::string mMorphWeight; 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 { struct Material {
std::string mName; std::string mName;
std::string mEffect; std::string mEffect;
}; };
/** Type of the effect param */ /// Type of the effect param
enum ParamType { enum ParamType {
Param_Sampler, Param_Sampler,
Param_Surface 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 { struct EffectParam {
ParamType mType; ParamType mType;
std::string mReference; // to which other thing the param is referring to. 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 { enum ShadeType {
Shade_Invalid, Shade_Invalid,
Shade_Constant, Shade_Constant,
@ -451,7 +453,7 @@ enum ShadeType {
Shade_Blinn Shade_Blinn
}; };
/** Represents a texture sampler in collada */ /// Represents a texture sampler in collada
struct Sampler { struct Sampler {
Sampler() : Sampler() :
mWrapU(true), mWrapU(true),
@ -463,77 +465,66 @@ struct Sampler {
mWeighting(1.f), mWeighting(1.f),
mMixWithPrevious(1.f) {} mMixWithPrevious(1.f) {}
/** Name of image reference /// Name of image reference
*/
std::string mName; std::string mName;
/** Wrap U? /// Wrap U?
*/
bool mWrapU; bool mWrapU;
/** Wrap V? /// Wrap V?
*/
bool mWrapV; bool mWrapV;
/** Mirror U? /// Mirror U?
*/
bool mMirrorU; bool mMirrorU;
/** Mirror V? /// Mirror V?
*/
bool mMirrorV; bool mMirrorV;
/** Blend mode /// Blend mode
*/
aiTextureOp mOp; aiTextureOp mOp;
/** UV transformation /// UV transformation
*/
aiUVTransform mTransform; aiUVTransform mTransform;
/** Name of source UV channel /// Name of source UV channel
*/
std::string mUVChannel; 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; unsigned int mUVId;
// OKINO/MAX3D extensions from here // OKINO/MAX3D extensions from here
// ------------------------------------------------------- // -------------------------------------------------------
/** Weighting factor /// Weighting factor
*/
ai_real mWeighting; ai_real mWeighting;
/** Mixing factor from OKINO /// Mixing factor from OKINO
*/
ai_real mMixWithPrevious; ai_real mMixWithPrevious;
}; };
/** A collada effect. Can contain about anything according to the Collada spec, /// A collada effect. Can contain about anything according to the Collada spec,
but we limit our version to a reasonable subset. */ /// but we limit our version to a reasonable subset.
struct Effect { struct Effect {
// Shading mode /// Shading mode
ShadeType mShadeType; ShadeType mShadeType;
// Colors /// Colors
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
mTransparent, mReflective; mTransparent, mReflective;
// Textures /// Textures
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
mTexTransparent, mTexBump, mTexReflective; mTexTransparent, mTexBump, mTexReflective;
// Scalar factory /// Scalar factory
ai_real mShininess, mRefractIndex, mReflectivity; ai_real mShininess, mRefractIndex, mReflectivity;
ai_real mTransparency; ai_real mTransparency;
bool mHasTransparency; bool mHasTransparency;
bool mRGBTransparency; bool mRGBTransparency;
bool mInvertTransparency; bool mInvertTransparency;
// local params referring to each other by their SID /// local params referring to each other by their SID
typedef std::map<std::string, Collada::EffectParam> ParamLibrary; using ParamLibrary = std::map<std::string, Collada::EffectParam>;
ParamLibrary mParams; ParamLibrary mParams;
// MAX3D extensions // MAX3D extensions
@ -561,65 +552,64 @@ struct Effect {
} }
}; };
/** An image, meaning texture */ /// An image, meaning texture
struct Image { struct Image {
std::string mFileName; std::string mFileName;
/** Embedded image data */ /// Embedded image data
std::vector<uint8_t> mImageData; std::vector<uint8_t> mImageData;
/** File format hint of embedded image data */ /// File format hint of embedded image data
std::string mEmbeddedFormat; std::string mEmbeddedFormat;
}; };
/** An animation channel. */ /// An animation channel.
struct AnimationChannel { struct AnimationChannel {
/** URL of the data to animate. Could be about anything, but we support only the /// URL of the data to animate. Could be about anything, but we support only the
* "NodeID/TransformID.SubElement" notation /// "NodeID/TransformID.SubElement" notation
*/
std::string mTarget; 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; 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; std::string mSourceValues;
/** Source URL of the IN_TANGENT semantic values. */ /// Source URL of the IN_TANGENT semantic values.
std::string mInTanValues; std::string mInTanValues;
/** Source URL of the OUT_TANGENT semantic values. */ /// Source URL of the OUT_TANGENT semantic values.
std::string mOutTanValues; std::string mOutTanValues;
/** Source URL of the INTERPOLATION semantic values. */ /// Source URL of the INTERPOLATION semantic values.
std::string mInterpolationValues; 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 { struct Animation {
/** Anim name */ /// Anim name
std::string mName; std::string mName;
/** the animation channels, if any */ /// the animation channels, if any
std::vector<AnimationChannel> mChannels; std::vector<AnimationChannel> mChannels;
/** the sub-animations, if any */ /// the sub-animations, if any
std::vector<Animation *> mSubAnims; std::vector<Animation *> mSubAnims;
/** Destructor */ /// Destructor
~Animation() { ~Animation() {
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
delete *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<AnimationChannel> &channels) { void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
channels.insert(channels.end(), mChannels.begin(), mChannels.end()); channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
Animation *pAnim = (*it); Animation *pAnim = (*it);
pAnim->CollectChannelsRecursively(channels); 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() { void CombineSingleChannelAnimations() {
CombineSingleChannelAnimationsRecursively(this); 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 { struct ChannelEntry {
const Collada::AnimationChannel *mChannel; ///> the source channel const Collada::AnimationChannel *mChannel; ///< the source channel
std::string mTargetId; std::string mTargetId;
std::string mTransformId; // the ID of the transformation step of the node which is influenced 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 size_t mTransformIndex; // Index into the node's transform chain to apply the channel to

View File

@ -55,12 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <math.h>
#include <time.h>
#include <algorithm>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <memory>
#include <numeric> #include <numeric>
namespace Assimp { namespace Assimp {
@ -331,13 +328,15 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
// Resolve UV channels // Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) { void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) { if (it == table.mMap.end()) {
if (it->second.mType != Collada::IT_Texcoord) { return;
ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
}
sampler.mUVId = it->second.mSet;
} }
if (it->second.mType != Collada::IT_Texcoord) {
ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
}
sampler.mUVId = it->second.mSet;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaParser.h" #include "ColladaParser.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/TinyFormatter.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/commonMetaData.h> #include <assimp/commonMetaData.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
@ -56,14 +55,47 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <stdarg.h>
#include <memory>
#include <sstream>
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Collada; using namespace Assimp::Collada;
using namespace Assimp::Formatter; 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<size_t>::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 // Constructor to be privately used by Importer
ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
@ -256,35 +288,35 @@ void ColladaParser::ReadContents(XmlNode &node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the structure of the file // Reads the structure of the file
void ColladaParser::ReadStructure(XmlNode &node) { void ColladaParser::ReadStructure(XmlNode &node) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string name = std::string(currentNode.name()); const std::string &currentName = std::string(currentNode.name());
ASSIMP_LOG_DEBUG("last name" + name); if (currentName == "asset") {
if (name == "asset")
ReadAssetInfo(currentNode); ReadAssetInfo(currentNode);
else if (name == "library_animations") } else if (currentName == "library_animations") {
ReadAnimationLibrary(currentNode); ReadAnimationLibrary(currentNode);
else if (name == "library_animation_clips") } else if (currentName == "library_animation_clips") {
ReadAnimationClipLibrary(currentNode); ReadAnimationClipLibrary(currentNode);
else if (name == "library_controllers") } else if (currentName == "library_controllers") {
ReadControllerLibrary(currentNode); ReadControllerLibrary(currentNode);
else if (name == "library_images") } else if (currentName == "library_images") {
ReadImageLibrary(currentNode); ReadImageLibrary(currentNode);
else if (name == "library_materials") } else if (currentName == "library_materials") {
ReadMaterialLibrary(currentNode); ReadMaterialLibrary(currentNode);
else if (name == "library_effects") } else if (currentName == "library_effects") {
ReadEffectLibrary(currentNode); ReadEffectLibrary(currentNode);
else if (name == "library_geometries") } else if (currentName == "library_geometries") {
ReadGeometryLibrary(currentNode); ReadGeometryLibrary(currentNode);
else if (name == "library_visual_scenes") } else if (currentName == "library_visual_scenes") {
ReadSceneLibrary(currentNode); ReadSceneLibrary(currentNode);
else if (name == "library_lights") } else if (currentName == "library_lights") {
ReadLightLibrary(currentNode); ReadLightLibrary(currentNode);
else if (name == "library_cameras") } else if (currentName == "library_cameras") {
ReadCameraLibrary(currentNode); ReadCameraLibrary(currentNode);
else if (name == "library_nodes") } else if (currentName == "library_nodes") {
ReadSceneNode(currentNode, nullptr); /* some hacking to reuse this piece of code */ ReadSceneNode(currentNode, nullptr); /* some hacking to reuse this piece of code */
else if (name == "scene") } else if (currentName == "scene") {
ReadScene(currentNode); ReadScene(currentNode);
}
} }
PostProcessRootAnimations(); PostProcessRootAnimations();
@ -298,17 +330,16 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string name = currentNode.name(); const std::string &currentName = currentNode.name();
if (name == "unit") { if (currentName == "unit") {
pugi::xml_attribute attr = currentNode.attribute("meter");
mUnitSize = 1.f; mUnitSize = 1.f;
if (attr) { XmlParser::getFloatAttribute(node, "meter", mUnitSize);
mUnitSize = static_cast<ai_real>(attr.as_double()); } else if (currentName == "up_axis") {
}
} else if (name == "up_axis") {
std::string v; std::string v;
XmlParser::getValueAsString(currentNode, v); if (!XmlParser::getValueAsString(currentNode, v)) {
continue;
}
if (v == "X_UP") { if (v == "X_UP") {
mUpDirection = UP_X; mUpDirection = UP_X;
} else if (v == "Z_UP") { } else if (v == "Z_UP") {
@ -316,9 +347,9 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
} else { } else {
mUpDirection = UP_Y; mUpDirection = UP_Y;
} }
} else if (name == "contributor") { } else if (currentName == "contributor") {
for (XmlNode currentChldNode : currentNode.children()) { for (XmlNode currentChildNode : currentNode.children()) {
ReadMetaDataItem(currentChldNode, mAssetMetaData); ReadMetaDataItem(currentChildNode, mAssetMetaData);
} }
} else { } else {
ReadMetaDataItem(currentNode, mAssetMetaData); ReadMetaDataItem(currentNode, mAssetMetaData);
@ -326,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<size_t>::max();
return false;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a single string metadata item // Reads a single string metadata item
void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) { void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) {
const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase(); const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
const std::string name = node.name(); const std::string name = node.name();
if (name.empty()) { if (name.empty()) {
return; return;
} }
std::string v; std::string v;
if (XmlParser::getValueAsString(node, v)) { if (!XmlParser::getValueAsString(node, v)) {
trim(v); return;
aiString aistr; }
aistr.Set(v);
std::string camel_key_str(name); trim(v);
ToCamelCase(camel_key_str); aiString aistr;
aistr.Set(v);
size_t found_index; std::string camel_key_str(name);
if (FindCommonKey(camel_key_str, key_renaming, found_index)) { ToCamelCase(camel_key_str);
metadata.emplace(key_renaming[found_index].second, aistr);
} else { size_t found_index;
metadata.emplace(camel_key_str, aistr); if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
} metadata.emplace(key_renaming[found_index].second, aistr);
} else {
metadata.emplace(camel_key_str, aistr);
} }
} }
@ -374,14 +394,8 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
} }
std::string animName; std::string animName;
pugi::xml_attribute nameAttr = node.attribute("name"); if (!XmlParser::getStdStrAttribute(node, "name", animName)) {
if (nameAttr) { if (!XmlParser::getStdStrAttribute( node, "id", animName )) {
animName = nameAttr.as_string();
} else {
pugi::xml_attribute idAttr = node.attribute("id");
if (idAttr) {
animName = idAttr.as_string();
} else {
animName = std::string("animation_") + to_string(mAnimationClipLibrary.size()); animName = std::string("animation_") + to_string(mAnimationClipLibrary.size());
} }
} }
@ -389,17 +403,12 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
std::pair<std::string, std::vector<std::string>> clip; std::pair<std::string, std::vector<std::string>> clip;
clip.first = animName; clip.first = animName;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "instance_animation") { if (currentName == "instance_animation") {
pugi::xml_attribute url = currentNode.attribute("url"); std::string url;
if (url) { readUrlAttribute(node, url);
const std::string urlName = url.as_string(); clip.second.push_back(url);
if (urlName[0] != '#') {
throw DeadlyImportError("Unknown reference format");
}
clip.second.push_back(url.as_string());
}
} }
if (clip.second.size() > 0) { if (clip.second.size() > 0) {
@ -469,8 +478,8 @@ void ColladaParser::ReadAnimationLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "animation") { if (currentName == "animation") {
ReadAnimation(currentNode, &mAnims); ReadAnimation(currentNode, &mAnims);
} }
@ -486,17 +495,14 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
// an <animation> element may be a container for grouping sub-elements or an animation channel // an <animation> 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 // this is the channel collection by ID, in case it has channels
typedef std::map<std::string, AnimationChannel> ChannelMap; using ChannelMap = std::map<std::string, AnimationChannel> ;
ChannelMap channels; ChannelMap channels;
// this is the anim container in case we're a container // this is the anim container in case we're a container
Animation *anim = nullptr; Animation *anim = nullptr;
// optional name given as an attribute // optional name given as an attribute
std::string animName; std::string animName;
pugi::xml_attribute nameAttr = node.attribute("name"); if (!XmlParser::getStdStrAttribute(node, "name", animName)) {
if (nameAttr) {
animName = nameAttr.as_string();
} else {
animName = "animation"; animName = "animation";
} }
@ -506,8 +512,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
animID = idAttr.as_string(); animID = idAttr.as_string();
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "animation") { if (currentName == "animation") {
if (!anim) { if (!anim) {
anim = new Animation; anim = new Animation;
@ -520,23 +526,21 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
} else if (currentName == "source") { } else if (currentName == "source") {
ReadSource(currentNode); ReadSource(currentNode);
} else if (currentName == "sampler") { } else if (currentName == "sampler") {
pugi::xml_attribute sampler_id = currentNode.attribute("id"); std::string id;
if (sampler_id) { if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
std::string id = sampler_id.as_string();
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
// have it read into a channel // have it read into a channel
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
ReadAnimationSampler(currentNode, newChannel->second); ReadAnimationSampler(currentNode, newChannel->second);
} else if (currentName == "channel") { } else if (currentName == "channel") {
pugi::xml_attribute target = currentNode.attribute("target"); std::string source_name, target;
pugi::xml_attribute source = currentNode.attribute("source"); XmlParser::getStdStrAttribute(currentNode, "source", source_name);
std::string source_name = source.as_string(); XmlParser::getStdStrAttribute(currentNode, "target", target);
if (source_name[0] == '#') { if (source_name[0] == '#') {
source_name = source_name.substr(1, source_name.size() - 1); source_name = source_name.substr(1, source_name.size() - 1);
} }
ChannelMap::iterator cit = channels.find(source_name); ChannelMap::iterator cit = channels.find(source_name);
if (cit != channels.end()) { if (cit != channels.end()) {
cit->second.mTarget = target.as_string(); cit->second.mTarget = target;
} }
} }
} }
@ -563,8 +567,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads an animation sampler into the given anim channel // Reads an animation sampler into the given anim channel
void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel) { void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "input") { if (currentName == "input") {
if (XmlParser::hasAttribute(currentNode, "semantic")) { if (XmlParser::hasAttribute(currentNode, "semantic")) {
std::string semantic, sourceAttr; std::string semantic, sourceAttr;
@ -577,16 +581,17 @@ void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChanne
} }
source++; source++;
if (semantic == "INPUT") if (semantic == "INPUT") {
pChannel.mSourceTimes = source; pChannel.mSourceTimes = source;
else if (semantic == "OUTPUT") } else if (semantic == "OUTPUT") {
pChannel.mSourceValues = source; pChannel.mSourceValues = source;
else if (semantic == "IN_TANGENT") } else if (semantic == "IN_TANGENT") {
pChannel.mInTanValues = source; pChannel.mInTanValues = source;
else if (semantic == "OUT_TANGENT") } else if (semantic == "OUT_TANGENT") {
pChannel.mOutTanValues = source; pChannel.mOutTanValues = source;
else if (semantic == "INTERPOLATION") } else if (semantic == "INTERPOLATION") {
pChannel.mInterpolationValues = source; pChannel.mInterpolationValues = source;
}
} }
} }
} }
@ -604,7 +609,6 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName != "controller") { if (currentName != "controller") {
continue; continue;
;
} }
std::string id = node.attribute("id").as_string(); std::string id = node.attribute("id").as_string();
mControllerLibrary[id] = Controller(); mControllerLibrary[id] = Controller();
@ -618,7 +622,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
// initial values // initial values
pController.mType = Skin; pController.mType = Skin;
pController.mMethod = Normalized; pController.mMethod = Normalized;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "morph") { if (currentName == "morph") {
pController.mType = Morph; pController.mType = Morph;
@ -670,8 +674,8 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the joint definitions for the given controller // Reads the joint definitions for the given controller
void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) { void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "input") { if (currentName == "input") {
const char *attrSemantic = currentNode.attribute("semantic").as_string(); const char *attrSemantic = currentNode.attribute("semantic").as_string();
const char *attrSource = currentNode.attribute("source").as_string(); const char *attrSource = currentNode.attribute("source").as_string();
@ -698,8 +702,8 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
int vertexCount=0; int vertexCount=0;
XmlParser::getIntAttribute(node, "count", vertexCount); XmlParser::getIntAttribute(node, "count", vertexCount);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "input") { if (currentName == "input") {
InputChannel channel; InputChannel channel;
@ -763,9 +767,9 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string name = currentNode.name(); const std::string &currentName = currentNode.name();
if (name == "image") { if (currentName == "image") {
std::string id = currentNode.attribute("id").as_string(); std::string id = currentNode.attribute("id").as_string();
mImageLibrary[id] = Image(); mImageLibrary[id] = Image();
@ -778,7 +782,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads an image entry into the given image // Reads an image entry into the given image
void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == "image") { if (currentName == "image") {
// Ignore // Ignore
@ -798,23 +802,6 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
if (!pImage.mFileName.length()) { if (!pImage.mFileName.length()) {
pImage.mFileName = "unknown_texture"; 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) { } else if (mFormat == FV_1_5_n) {
std::string value; std::string value;
@ -861,8 +848,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
} }
std::map<std::string, int> names; std::map<std::string, int> names;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
std::string id = currentNode.attribute("id").as_string(); std::string id = currentNode.attribute("id").as_string();
std::string name = currentNode.attribute("name").as_string(); std::string name = currentNode.attribute("name").as_string();
mMaterialLibrary[id] = Material(); mMaterialLibrary[id] = Material();
@ -891,11 +877,13 @@ void ColladaParser::ReadLightLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "light") { if (currentName == "light") {
std::string id = currentNode.attribute("id").as_string(); std::string id;
ReadLight(currentNode, mLightLibrary[id] = Light()); if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
ReadLight(currentNode, mLightLibrary[id] = Light());
}
} }
} }
} }
@ -907,14 +895,20 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "camera") { 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 // create an entry and store it in the library under its ID
Camera &cam = mCameraLibrary[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()) { if (!name.empty()) {
cam.mName = name; cam.mName = name;
} }
@ -926,14 +920,12 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a material entry into the given material // Reads a material entry into the given material
void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) { void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
for (XmlNode currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "instance_effect") { if (currentName == "instance_effect") {
const char *url = currentNode.attribute("url").as_string(); std::string url;
if (url[0] != '#') { readUrlAttribute(currentNode, url);
throw DeadlyImportError("Unknown reference format"); pMaterial.mEffect = url.c_str();
}
pMaterial.mEffect = url + 1;
} }
} }
} }
@ -1032,7 +1024,7 @@ void ColladaParser::ReadEffectLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "effect") { if (currentName == "effect") {
// read ID. Do I have to repeat my ranting about "optional" attributes? // read ID. Do I have to repeat my ranting about "optional" attributes?
@ -1051,7 +1043,7 @@ void ColladaParser::ReadEffectLibrary(XmlNode &node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads an effect entry into the given effect // Reads an effect entry into the given effect
void ColladaParser::ReadEffect(XmlNode &node, Collada::Effect &pEffect) { void ColladaParser::ReadEffect(XmlNode &node, Collada::Effect &pEffect) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "profile_COMMON") { if (currentName == "profile_COMMON") {
ReadEffectProfileCommon(currentNode, pEffect); ReadEffectProfileCommon(currentNode, pEffect);
@ -1256,8 +1248,6 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
} else if (currentName == "technique") { } else if (currentName == "technique") {
std::string profile; std::string profile;
XmlParser::getStdStrAttribute(currentNode, "profile", profile); XmlParser::getStdStrAttribute(currentNode, "profile", profile);
//const int _profile = GetAttribute("profile");
//const char *profile = mReader->getAttributeValue(_profile);
// Some extensions are quite useful ... ReadSamplerProperties processes // Some extensions are quite useful ... ReadSamplerProperties processes
// several extensions in MAYA, OKINO and MAX3D profiles. // several extensions in MAYA, OKINO and MAX3D profiles.
@ -1330,7 +1320,7 @@ void ColladaParser::ReadGeometryLibrary(XmlNode &node) {
if (node.empty()) { if (node.empty()) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "geometry") { if (currentName == "geometry") {
// read ID. Another entry which is "optional" by design but obligatory in reality // read ID. Another entry which is "optional" by design but obligatory in reality
@ -1359,7 +1349,7 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) {
if (node.empty()) { if (node.empty()) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "mesh") { if (currentName == "mesh") {
ReadMesh(currentNode, pMesh); ReadMesh(currentNode, pMesh);
@ -1383,7 +1373,9 @@ void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) {
ReadSource(currentNode); ReadSource(currentNode);
} else if (currentName == "vertices") { } else if (currentName == "vertices") {
ReadVertexData(currentNode, pMesh); 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); ReadIndexData(currentNode, pMesh);
} }
} }
@ -1541,16 +1533,11 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
acc.mSubOffset[1] = acc.mParams.size(); acc.mSubOffset[1] = acc.mParams.size();
else if (name == "P") else if (name == "P")
acc.mSubOffset[2] = acc.mParams.size(); 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*/ /* Generic extra data, interpreted as UV data, too*/
else if (name == "U") else if (name == "U")
acc.mSubOffset[0] = acc.mParams.size(); acc.mSubOffset[0] = acc.mParams.size();
else if (name == "V") else if (name == "V")
acc.mSubOffset[1] = acc.mParams.size(); acc.mSubOffset[1] = acc.mParams.size();
//else
// DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." );
} }
if (XmlParser::hasAttribute(currentNode, "type")) { if (XmlParser::hasAttribute(currentNode, "type")) {
// read data type // read data type
@ -1575,7 +1562,7 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) { void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) {
// extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID); XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "input") { if (currentName == "input") {
ReadInputChannel(currentNode, pMesh.mPerVertexData); ReadInputChannel(currentNode, pMesh.mPerVertexData);
@ -1733,20 +1720,20 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
// determine the expected number of indices // determine the expected number of indices
size_t expectedPointCount = 0; size_t expectedPointCount = 0;
switch (pPrimType) { switch (pPrimType) {
case Prim_Polylist: { case Prim_Polylist: {
for (size_t i : pVCount) for (size_t i : pVCount)
expectedPointCount += i; expectedPointCount += i;
break; break;
} }
case Prim_Lines: case Prim_Lines:
expectedPointCount = 2 * pNumPrimitives; expectedPointCount = 2 * pNumPrimitives;
break; break;
case Prim_Triangles: case Prim_Triangles:
expectedPointCount = 3 * pNumPrimitives; expectedPointCount = 3 * pNumPrimitives;
break; break;
default: default:
// other primitive types don't state the index count upfront... we need to guess // other primitive types don't state the index count upfront... we need to guess
break; break;
} }
// and read all indices into a temporary array // and read all indices into a temporary array
@ -1778,7 +1765,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
} else { } else {
throw DeadlyImportError("Expected different index count in <p> element."); throw DeadlyImportError("Expected different index count in <p> element.");
} }
} else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) { } else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) {
throw DeadlyImportError("Expected different index count in <p> element."); throw DeadlyImportError("Expected different index count in <p> element.");
} }
@ -2030,7 +2016,7 @@ void ColladaParser::ReadSceneLibrary(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "visual_scene") { if (currentName == "visual_scene") {
// read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then?
@ -2197,11 +2183,8 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Processes bind_vertex_input and bind elements // Processes bind_vertex_input and bind elements
void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl) { void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl) {
//XmlNodeIterator xmlIt(node);
//xmlIt.collectChildrenPreOrder(node);
//XmlNode currentNode;
std::string name = node.name(); std::string name = node.name();
for (XmlNode currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "bind_vertex_input") { if (currentName == "bind_vertex_input") {
Collada::InputSemanticMapEntry vn; Collada::InputSemanticMapEntry vn;
@ -2296,8 +2279,8 @@ void ColladaParser::ReadScene(XmlNode &node) {
return; return;
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "instance_visual_scene") { if (currentName == "instance_visual_scene") {
// should be the first and only occurrence // should be the first and only occurrence
if (mRootNode) { if (mRootNode) {
@ -2321,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 // Calculates the resulting transformation from all the given transform steps
aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector<Transform> &pTransforms) const { aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector<Transform> &pTransforms) const {

View File

@ -243,8 +243,6 @@ protected:
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected: protected:
void ReportWarning(const char *msg, ...);
/** Calculates the resulting transformation from all the given transform steps */ /** Calculates the resulting transformation from all the given transform steps */
aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const; aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
@ -260,56 +258,55 @@ protected:
std::string mFileName; std::string mFileName;
// XML reader, member for everyday use // XML reader, member for everyday use
//irr::io::IrrXMLReader *mReader;
XmlParser mXmlParser; XmlParser mXmlParser;
/** All data arrays found in the file by ID. Might be referred to by actually /** All data arrays found in the file by ID. Might be referred to by actually
everyone. Collada, you are a steaming pile of indirection. */ everyone. Collada, you are a steaming pile of indirection. */
typedef std::map<std::string, Collada::Data> DataLibrary; using DataLibrary = std::map<std::string, Collada::Data> ;
DataLibrary mDataLibrary; DataLibrary mDataLibrary;
/** Same for accessors which define how the data in a data array is accessed. */ /** Same for accessors which define how the data in a data array is accessed. */
typedef std::map<std::string, Collada::Accessor> AccessorLibrary; using AccessorLibrary = std::map<std::string, Collada::Accessor> ;
AccessorLibrary mAccessorLibrary; AccessorLibrary mAccessorLibrary;
/** Mesh library: mesh by ID */ /** Mesh library: mesh by ID */
typedef std::map<std::string, Collada::Mesh *> MeshLibrary; using MeshLibrary = std::map<std::string, Collada::Mesh *>;
MeshLibrary mMeshLibrary; MeshLibrary mMeshLibrary;
/** node library: root node of the hierarchy part by ID */ /** node library: root node of the hierarchy part by ID */
typedef std::map<std::string, Collada::Node *> NodeLibrary; using NodeLibrary = std::map<std::string, Collada::Node *>;
NodeLibrary mNodeLibrary; NodeLibrary mNodeLibrary;
/** Image library: stores texture properties by ID */ /** Image library: stores texture properties by ID */
typedef std::map<std::string, Collada::Image> ImageLibrary; using ImageLibrary = std::map<std::string, Collada::Image> ;
ImageLibrary mImageLibrary; ImageLibrary mImageLibrary;
/** Effect library: surface attributes by ID */ /** Effect library: surface attributes by ID */
typedef std::map<std::string, Collada::Effect> EffectLibrary; using EffectLibrary = std::map<std::string, Collada::Effect> ;
EffectLibrary mEffectLibrary; EffectLibrary mEffectLibrary;
/** Material library: surface material by ID */ /** Material library: surface material by ID */
typedef std::map<std::string, Collada::Material> MaterialLibrary; using MaterialLibrary = std::map<std::string, Collada::Material> ;
MaterialLibrary mMaterialLibrary; MaterialLibrary mMaterialLibrary;
/** Light library: surface light by ID */ /** Light library: surface light by ID */
typedef std::map<std::string, Collada::Light> LightLibrary; using LightLibrary = std::map<std::string, Collada::Light> ;
LightLibrary mLightLibrary; LightLibrary mLightLibrary;
/** Camera library: surface material by ID */ /** Camera library: surface material by ID */
typedef std::map<std::string, Collada::Camera> CameraLibrary; using CameraLibrary = std::map<std::string, Collada::Camera> ;
CameraLibrary mCameraLibrary; CameraLibrary mCameraLibrary;
/** Controller library: joint controllers by ID */ /** Controller library: joint controllers by ID */
typedef std::map<std::string, Collada::Controller> ControllerLibrary; using ControllerLibrary = std::map<std::string, Collada::Controller> ;
ControllerLibrary mControllerLibrary; ControllerLibrary mControllerLibrary;
/** Animation library: animation references by ID */ /** Animation library: animation references by ID */
typedef std::map<std::string, Collada::Animation *> AnimationLibrary; using AnimationLibrary = std::map<std::string, Collada::Animation *> ;
AnimationLibrary mAnimationLibrary; AnimationLibrary mAnimationLibrary;
/** Animation clip library: clip animation references by ID */ /** Animation clip library: clip animation references by ID */
typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary; using AnimationClipLibrary = std::vector<std::pair<std::string, std::vector<std::string>>> ;
AnimationClipLibrary mAnimationClipLibrary; AnimationClipLibrary mAnimationClipLibrary;
/** Pointer to the root node. Don't delete, it just points to one of /** Pointer to the root node. Don't delete, it just points to one of
@ -334,13 +331,6 @@ protected:
Collada::FormatVersion mFormat; 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 // Finds the item in the given library by its reference, throws if not found
template <typename Type> template <typename Type>

View File

@ -187,6 +187,11 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// size relative to cm // size relative to cm
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
if (size_relative_to_cm == 0.0)
{
// BaseImporter later asserts that fileScale is non-zero.
ThrowException("The UnitScaleFactor must be non-zero");
}
// Set FBX file scale is relative to CM must be converted to M for // Set FBX file scale is relative to CM must be converted to M for
// assimp universal format (M) // assimp universal format (M)

View File

@ -1060,7 +1060,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
inline void Camera::Read(Value &obj, Asset & /*r*/) { inline void Camera::Read(Value &obj, Asset & /*r*/) {
type = MemberOrDefault(obj, "type", Camera::Perspective); 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); Value *it = FindObject(obj, subobjId);
if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters"); 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.zfar = MemberOrDefault(*it, "zfar", 100.f);
perspective.znear = MemberOrDefault(*it, "znear", 0.01f); perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
} else { } else {
ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -44,22 +44,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_STRINGUTILS_H #define INCLUDED_AI_STRINGUTILS_H
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC system_header #pragma GCC system_header
#endif #endif
#include <assimp/defs.h> #include <assimp/defs.h>
#include <sstream>
#include <stdarg.h> #include <stdarg.h>
#include <cstdlib>
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <cstdlib>
#include <locale> #include <locale>
#include <sstream>
#ifdef _MSC_VER #ifdef _MSC_VER
# define AI_SIZEFMT "%Iu" #define AI_SIZEFMT "%Iu"
#else #else
# define AI_SIZEFMT "%zu" #define AI_SIZEFMT "%zu"
#endif #endif
/// @fn ai_snprintf /// @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. /// @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 #if defined(_MSC_VER) && _MSC_VER < 1900
AI_FORCE_INLINE AI_FORCE_INLINE
int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
int count(-1); int count(-1);
if (0 != size) { if (0 != size) {
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
} }
if (count == -1) { if (count == -1) {
count = _vscprintf(format, ap); count = _vscprintf(format, ap);
} }
return count; return count;
} }
AI_FORCE_INLINE AI_FORCE_INLINE
int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
int count; int count;
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
count = c99_ai_vsnprintf(outBuf, size, format, ap); count = c99_ai_vsnprintf(outBuf, size, format, ap);
va_end(ap); va_end(ap);
return count; return count;
} }
#elif defined(__MINGW32__) #elif defined(__MINGW32__)
# define ai_snprintf __mingw_snprintf #define ai_snprintf __mingw_snprintf
#else #else
# define ai_snprintf snprintf #define ai_snprintf snprintf
#endif #endif
/// @fn to_string /// @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. /// @param value The value to write into the std::string.
/// @return The value as a std::string /// @return The value as a std::string
template <typename T> template <typename T>
AI_FORCE_INLINE AI_FORCE_INLINE std::string to_string(T value) {
std::string to_string( T value ) {
std::ostringstream os; std::ostringstream os;
os << value; os << value;
@ -121,17 +120,17 @@ std::string to_string( T value ) {
/// @param end The last character /// @param end The last character
/// @return The float value, 0.0f in cas of an error. /// @return The float value, 0.0f in cas of an error.
AI_FORCE_INLINE AI_FORCE_INLINE
float ai_strtof( const char *begin, const char *end ) { float ai_strtof(const char *begin, const char *end) {
if ( nullptr == begin ) { if (nullptr == begin) {
return 0.0f; return 0.0f;
} }
float val( 0.0f ); float val(0.0f);
if ( nullptr == end ) { if (nullptr == end) {
val = static_cast< float >( ::atof( begin ) ); val = static_cast<float>(::atof(begin));
} else { } else {
std::string::size_type len( end - begin ); std::string::size_type len(end - begin);
std::string token( begin, len ); std::string token(begin, len);
val = static_cast< float >( ::atof( token.c_str() ) ); val = static_cast<float>(::atof(token.c_str()));
} }
return val; 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. /// @brief The portable to convert a decimal value into a hexadecimal string.
/// @param toConvert Value to convert /// @param toConvert Value to convert
/// @return The hexadecimal string, is empty in case of an error. /// @return The hexadecimal string, is empty in case of an error.
template<class T> template <class T>
AI_FORCE_INLINE AI_FORCE_INLINE std::string DecimalToHexa(T toConvert) {
std::string DecimalToHexa( T toConvert ) {
std::string result; std::string result;
std::stringstream ss; std::stringstream ss;
ss << std::hex << toConvert; ss << std::hex << toConvert;
ss >> result; ss >> result;
for ( size_t i = 0; i < result.size(); ++i ) { for (size_t i = 0; i < result.size(); ++i) {
result[ i ] = (char) toupper( result[ i ] ); result[i] = (char)toupper(result[i]);
} }
return result; return result;
@ -164,31 +162,32 @@ std::string DecimalToHexa( T toConvert ) {
/// @param with_head # /// @param with_head #
/// @return The hexadecimal string, is empty in case of an error. /// @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) { AI_FORCE_INLINE std::string Rgba2Hex(int r, int g, int b, int a, bool with_head) {
std::stringstream ss; std::stringstream ss;
if (with_head) { if (with_head) {
ss << "#"; ss << "#";
} }
ss << std::hex << (r << 24 | g << 16 | b << 8 | a); ss << std::hex << (r << 24 | g << 16 | b << 8 | a);
return ss.str(); return ss.str();
} }
// trim from start (in place) // 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) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch); return !std::isspace(ch);
})); }));
} }
// trim from end (in place) // 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) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch); return !std::isspace(ch);
}).base(), s.end()); }).base(),
s.end());
} }
// trim from both ends (in place) // trim from both ends (in place)
inline void trim(std::string &s) { AI_FORCE_INLINE void trim(std::string &s) {
ltrim(s); ltrim(s);
rtrim(s); rtrim(s);
} }

View File

@ -179,7 +179,7 @@ public:
return true; 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); pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) { if (attr.empty()) {
return false; 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) { static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
pugi::xml_attribute attr = xmlNode.attribute(name); pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) { if (attr.empty()) {

View File

@ -24,11 +24,11 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <stdint.h> #include <stdint.h>
#include <stdexcept>
#include <assimp/defs.h> #include <assimp/defs.h>
#include "StringComparison.h" #include "StringComparison.h"
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Exceptional.h>
#ifdef _MSC_VER #ifdef _MSC_VER
# include <stdint.h> # include <stdint.h>
@ -185,13 +185,15 @@ unsigned int strtoul_cppstyle( const char* in, const char** out=0) {
// Special version of the function, providing higher accuracy and safety // Special version of the function, providing higher accuracy and safety
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows. // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
template<typename ExceptionType = DeadlyImportError>
inline inline
uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0) { uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0) {
unsigned int cur = 0; unsigned int cur = 0;
uint64_t value = 0; uint64_t value = 0;
if ( *in < '0' || *in > '9' ) { if ( *in < '0' || *in > '9' ) {
throw std::invalid_argument( std::string( "The string \"" ) + in + "\" cannot be converted into a value." ); // The string is known to be bad, so don't risk printing the whole thing.
throw ExceptionType("The string \"", std::string(in).substr(0, 100), "\" cannot be converted into a value." );
} }
for ( ;; ) { for ( ;; ) {
@ -237,6 +239,7 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// signed variant of strtoul10_64 // signed variant of strtoul10_64
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
template<typename ExceptionType = DeadlyImportError>
inline inline
int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) { int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) {
bool inv = (*in == '-'); bool inv = (*in == '-');
@ -244,7 +247,7 @@ int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inou
++in; ++in;
} }
int64_t value = strtoul10_64(in, out, max_inout); int64_t value = strtoul10_64<ExceptionType>(in, out, max_inout);
if (inv) { if (inv) {
value = -value; value = -value;
} }
@ -259,7 +262,7 @@ int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inou
//! about 6 times faster than atof in win32. //! about 6 times faster than atof in win32.
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org. // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
template<typename Real> template<typename Real, typename ExceptionType = DeadlyImportError>
inline inline
const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) { const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) {
Real f = 0; Real f = 0;
@ -289,13 +292,14 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
if (!(c[0] >= '0' && c[0] <= '9') && if (!(c[0] >= '0' && c[0] <= '9') &&
!((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) { !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
throw std::invalid_argument("Cannot parse string " // The string is known to be bad, so don't risk printing the whole thing.
"as real number: does not start with digit " throw ExceptionType("Cannot parse string \"", std::string(c).substr(0, 100),
"\" as a real number: does not start with digit "
"or decimal point followed by digit."); "or decimal point followed by digit.");
} }
if (*c != '.' && (! check_comma || c[0] != ',')) { if (*c != '.' && (! check_comma || c[0] != ',')) {
f = static_cast<Real>( strtoul10_64 ( c, &c) ); f = static_cast<Real>( strtoul10_64<ExceptionType> ( c, &c) );
} }
if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') { if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') {
@ -310,7 +314,7 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
// number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
// 1 and 15. // 1 and 15.
unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS; unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
double pl = static_cast<double>( strtoul10_64 ( c, &c, &diff )); double pl = static_cast<double>( strtoul10_64<ExceptionType> ( c, &c, &diff ));
pl *= fast_atof_table[diff]; pl *= fast_atof_table[diff];
f += static_cast<Real>( pl ); f += static_cast<Real>( pl );
@ -332,7 +336,7 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
// The reason float constants are used here is that we've seen cases where compilers // The reason float constants are used here is that we've seen cases where compilers
// would perform such casts on compile-time constants at runtime, which would be // would perform such casts on compile-time constants at runtime, which would be
// bad considering how frequently fast_atoreal_move<float> is called in Assimp. // bad considering how frequently fast_atoreal_move<float> is called in Assimp.
Real exp = static_cast<Real>( strtoul10_64(c, &c) ); Real exp = static_cast<Real>( strtoul10_64<ExceptionType>(c, &c) );
if (einv) { if (einv) {
exp = -exp; exp = -exp;
} }
@ -348,26 +352,29 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// The same but more human. // The same but more human.
template<typename ExceptionType = DeadlyImportError>
inline inline
ai_real fast_atof(const char* c) { ai_real fast_atof(const char* c) {
ai_real ret(0.0); ai_real ret(0.0);
fast_atoreal_move<ai_real>(c, ret); fast_atoreal_move<ai_real, ExceptionType>(c, ret);
return ret; return ret;
} }
template<typename ExceptionType = DeadlyImportError>
inline inline
ai_real fast_atof( const char* c, const char** cout) { ai_real fast_atof( const char* c, const char** cout) {
ai_real ret(0.0); ai_real ret(0.0);
*cout = fast_atoreal_move<ai_real>(c, ret); *cout = fast_atoreal_move<ai_real, ExceptionType>(c, ret);
return ret; return ret;
} }
template<typename ExceptionType = DeadlyImportError>
inline inline
ai_real fast_atof( const char** inout) { ai_real fast_atof( const char** inout) {
ai_real ret(0.0); ai_real ret(0.0);
*inout = fast_atoreal_move<ai_real>(*inout, ret); *inout = fast_atoreal_move<ai_real, ExceptionType>(*inout, ret);
return ret; return ret;
} }