| /** Helper structures for the Collada loader */ |
| |
| /* |
| Open Asset Import Library (assimp) |
| ---------------------------------------------------------------------- |
| |
| Copyright (c) 2006-2017, assimp team |
| |
| All rights reserved. |
| |
| Redistribution and use of this software in source and binary forms, |
| with or without modification, are permitted provided that the |
| following conditions are met: |
| |
| * Redistributions of source code must retain the above |
| copyright notice, this list of conditions and the |
| following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the |
| following disclaimer in the documentation and/or other |
| materials provided with the distribution. |
| |
| * Neither the name of the assimp team, nor the names of its |
| contributors may be used to endorse or promote products |
| derived from this software without specific prior |
| written permission of the assimp team. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| ---------------------------------------------------------------------- |
| */ |
| |
| #ifndef AI_COLLADAHELPER_H_INC |
| #define AI_COLLADAHELPER_H_INC |
| |
| #include <map> |
| #include <vector> |
| #include <stdint.h> |
| #include <assimp/light.h> |
| #include <assimp/mesh.h> |
| #include <assimp/material.h> |
| |
| struct aiMaterial; |
| |
| namespace Assimp { |
| namespace Collada { |
| |
| /** 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 */ |
| enum TransformType |
| { |
| TF_LOOKAT, |
| TF_ROTATE, |
| TF_TRANSLATE, |
| TF_SCALE, |
| TF_SKEW, |
| TF_MATRIX |
| }; |
| |
| /** 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 <vertices> element carrying the per-vertex data. |
| IT_Position, |
| IT_Normal, |
| IT_Texcoord, |
| IT_Color, |
| IT_Tangent, |
| IT_Bitangent |
| }; |
| |
| /** Supported controller types */ |
| enum ControllerType |
| { |
| Skin, |
| Morph |
| }; |
| |
| /** Supported morph methods */ |
| enum MorphMethod |
| { |
| Normalized, |
| Relative |
| }; |
| |
| |
| /** 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. */ |
| struct Camera |
| { |
| Camera() |
| : mOrtho (false) |
| , mHorFov (10e10f) |
| , mVerFov (10e10f) |
| , mAspect (10e10f) |
| , mZNear (0.1f) |
| , mZFar (1000.f) |
| {} |
| |
| // Name of camera |
| std::string mName; |
| |
| // True if it is an orthografic camera |
| bool mOrtho; |
| |
| //! Horizontal field of view in degrees |
| ai_real mHorFov; |
| |
| //! Vertical field of view in degrees |
| ai_real mVerFov; |
| |
| //! Screen aspect |
| ai_real mAspect; |
| |
| //! Near& far z |
| ai_real mZNear, mZFar; |
| }; |
| |
| #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f |
| |
| /** A collada light source. */ |
| struct Light |
| { |
| Light() |
| : mType (aiLightSource_UNDEFINED) |
| , mAttConstant (1.f) |
| , mAttLinear (0.f) |
| , mAttQuadratic (0.f) |
| , mFalloffAngle (180.f) |
| , mFalloffExponent (0.f) |
| , mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) |
| , mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) |
| , mIntensity (1.f) |
| {} |
| |
| //! Type of the light source aiLightSourceType + ambient |
| unsigned int mType; |
| |
| //! Color of the light |
| aiColor3D mColor; |
| |
| //! Light attenuation |
| ai_real mAttConstant,mAttLinear,mAttQuadratic; |
| |
| //! Spot light falloff |
| ai_real mFalloffAngle; |
| ai_real mFalloffExponent; |
| |
| // ----------------------------------------------------- |
| // FCOLLADA extension from here |
| |
| //! ... related stuff from maja and max extensions |
| ai_real mPenumbraAngle; |
| ai_real mOuterAngle; |
| |
| //! Common light intensity |
| ai_real mIntensity; |
| }; |
| |
| /** Short vertex index description */ |
| struct InputSemanticMapEntry |
| { |
| InputSemanticMapEntry() |
| : mSet(0) |
| , mType(IT_Invalid) |
| {} |
| |
| //! Index of set, optional |
| unsigned int mSet; |
| |
| //! Type of referenced vertex input |
| InputType mType; |
| }; |
| |
| /** Table to map from effect to vertex input semantics */ |
| struct SemanticMappingTable |
| { |
| //! Name of material |
| std::string mMatName; |
| |
| //! List of semantic map commands, grouped by effect semantic name |
| std::map<std::string, InputSemanticMapEntry> mMap; |
| |
| //! 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 |
| */ |
| struct MeshInstance |
| { |
| ///< ID of the mesh or controller to be instanced |
| std::string mMeshOrController; |
| |
| ///< Map of materials by the subgroup ID they're applied to |
| std::map<std::string, SemanticMappingTable> mMaterials; |
| }; |
| |
| /** 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*/ |
| struct LightInstance |
| { |
| ///< ID of the camera |
| std::string mLight; |
| }; |
| |
| /** A reference to a node inside a node*/ |
| struct NodeInstance |
| { |
| ///< ID of the node |
| std::string mNode; |
| }; |
| |
| /** A node in a scene hierarchy */ |
| struct Node |
| { |
| std::string mName; |
| std::string mID; |
| std::string mSID; |
| Node* mParent; |
| std::vector<Node*> mChildren; |
| |
| /** Operations in order to calculate the resulting transformation to parent. */ |
| std::vector<Transform> mTransforms; |
| |
| /** Meshes at this node */ |
| std::vector<MeshInstance> mMeshes; |
| |
| /** Lights at this node */ |
| std::vector<LightInstance> mLights; |
| |
| /** Cameras at this node */ |
| std::vector<CameraInstance> mCameras; |
| |
| /** Node instances at this node */ |
| std::vector<NodeInstance> mNodeInstances; |
| |
| /** Rootnodes: Name of primary camera, if any */ |
| std::string mPrimaryCamera; |
| |
| //! Constructor. Begin with a zero parent |
| Node() { |
| mParent = NULL; |
| } |
| |
| //! Destructor: delete all children subsequently |
| ~Node() { |
| for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) |
| delete *it; |
| } |
| }; |
| |
| /** Data source array: either floats or strings */ |
| struct Data |
| { |
| bool mIsStringArray; |
| std::vector<ai_real> mValues; |
| std::vector<std::string> mStrings; |
| }; |
| |
| /** 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<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. |
| // 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. NULL else |
| |
| Accessor() |
| { |
| mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL; |
| mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; |
| } |
| }; |
| |
| /** A single face in a mesh */ |
| struct Face |
| { |
| std::vector<size_t> mIndices; |
| }; |
| |
| /** 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 |
| size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better. |
| std::string mAccessor; // ID of the accessor where to read the actual values from. |
| mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else |
| |
| InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; } |
| }; |
| |
| /** Subset of a mesh with a certain material */ |
| struct SubMesh |
| { |
| std::string mMaterial; ///< subgroup identifier |
| size_t mNumFaces; ///< number of faces in this submesh |
| }; |
| |
| /** Contains data for a single mesh */ |
| struct Mesh |
| { |
| Mesh() |
| { |
| for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) |
| mNumUVComponents[i] = 2; |
| } |
| |
| std::string mName; |
| |
| // just to check if there's some sophisticated addressing involved... |
| // which we don't support, and therefore should warn about. |
| std::string mVertexID; |
| |
| // Vertex data addressed by vertex indices |
| std::vector<InputChannel> mPerVertexData; |
| |
| // actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed |
| std::vector<aiVector3D> mPositions; |
| std::vector<aiVector3D> mNormals; |
| std::vector<aiVector3D> mTangents; |
| std::vector<aiVector3D> mBitangents; |
| std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
| std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; |
| |
| unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
| |
| // Faces. Stored are only the number of vertices for each face. |
| // 1 == point, 2 == line, 3 == triangle, 4+ == poly |
| std::vector<size_t> mFaceSize; |
| |
| // Position indices for all faces in the sequence given in mFaceSize - |
| // necessary for bone weight assignment |
| std::vector<size_t> mFacePosIndices; |
| |
| // Submeshes in this mesh, each with a given material |
| std::vector<SubMesh> mSubMeshes; |
| }; |
| |
| /** Which type of primitives the ReadPrimitives() function is going to read */ |
| enum PrimitiveType |
| { |
| Prim_Invalid, |
| Prim_Lines, |
| Prim_LineStrip, |
| Prim_Triangles, |
| Prim_TriStrips, |
| Prim_TriFans, |
| Prim_Polylist, |
| Prim_Polygon |
| }; |
| |
| /** A skeleton controller to deform a mesh with the use of joints */ |
| struct Controller |
| { |
| // controller type |
| ControllerType mType; |
| |
| // Morphing method if type is Morph |
| MorphMethod mMethod; |
| |
| // the URL of the mesh deformed by the controller. |
| std::string mMeshId; |
| |
| // accessor URL of the joint names |
| std::string mJointNameSource; |
| |
| ///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases |
| ai_real mBindShapeMatrix[16]; |
| |
| // accessor URL of the joint inverse bind matrices |
| std::string mJointOffsetMatrixSource; |
| |
| // input channel: joint names. |
| InputChannel mWeightInputJoints; |
| // input channel: joint weights |
| InputChannel mWeightInputWeights; |
| |
| // Number of weights per vertex. |
| std::vector<size_t> mWeightCounts; |
| |
| // JointIndex-WeightIndex pairs for all vertices |
| std::vector< std::pair<size_t, size_t> > mWeights; |
| |
| std::string mMorphTarget; |
| std::string mMorphWeight; |
| }; |
| |
| /** 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 */ |
| 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 */ |
| 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 */ |
| enum ShadeType |
| { |
| Shade_Invalid, |
| Shade_Constant, |
| Shade_Lambert, |
| Shade_Phong, |
| Shade_Blinn |
| }; |
| |
| /** Represents a texture sampler in collada */ |
| struct Sampler |
| { |
| Sampler() |
| : mWrapU (true) |
| , mWrapV (true) |
| , mMirrorU () |
| , mMirrorV () |
| , mOp (aiTextureOp_Multiply) |
| , mUVId (UINT_MAX) |
| , mWeighting (1.f) |
| , mMixWithPrevious (1.f) |
| {} |
| |
| /** Name of image reference |
| */ |
| std::string mName; |
| |
| /** Wrap U? |
| */ |
| bool mWrapU; |
| |
| /** Wrap V? |
| */ |
| bool mWrapV; |
| |
| /** Mirror U? |
| */ |
| bool mMirrorU; |
| |
| /** Mirror V? |
| */ |
| bool mMirrorV; |
| |
| /** Blend mode |
| */ |
| aiTextureOp mOp; |
| |
| /** UV transformation |
| */ |
| aiUVTransform mTransform; |
| |
| /** Name of source UV channel |
| */ |
| std::string mUVChannel; |
| |
| /** Resolved UV channel index or UINT_MAX if not known |
| */ |
| unsigned int mUVId; |
| |
| // OKINO/MAX3D extensions from here |
| // ------------------------------------------------------- |
| |
| /** Weighting factor |
| */ |
| ai_real mWeighting; |
| |
| /** 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. */ |
| struct Effect |
| { |
| // Shading mode |
| ShadeType mShadeType; |
| |
| // Colors |
| aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, |
| mTransparent, mReflective; |
| |
| // Textures |
| Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, |
| mTexTransparent, mTexBump, mTexReflective; |
| |
| // 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<std::string, Collada::EffectParam> ParamLibrary; |
| ParamLibrary mParams; |
| |
| // MAX3D extensions |
| // --------------------------------------------------------- |
| // Double-sided? |
| bool mDoubleSided, mWireframe, mFaceted; |
| |
| Effect() |
| : mShadeType (Shade_Phong) |
| , mEmissive ( 0, 0, 0, 1) |
| , mAmbient ( 0.1f, 0.1f, 0.1f, 1) |
| , mDiffuse ( 0.6f, 0.6f, 0.6f, 1) |
| , mSpecular ( 0.4f, 0.4f, 0.4f, 1) |
| , mTransparent ( 0, 0, 0, 1) |
| , mShininess (10.0f) |
| , mRefractIndex (1.f) |
| , mReflectivity (0.f) |
| , mTransparency (1.f) |
| , mHasTransparency (false) |
| , mRGBTransparency(false) |
| , mInvertTransparency(false) |
| , mDoubleSided (false) |
| , mWireframe (false) |
| , mFaceted (false) |
| { |
| } |
| }; |
| |
| /** An image, meaning texture */ |
| struct Image |
| { |
| std::string mFileName; |
| |
| /** If image file name is zero, embedded image data |
| */ |
| std::vector<uint8_t> mImageData; |
| |
| /** If image file name is zero, file format of |
| * embedded image data. |
| */ |
| std::string mEmbeddedFormat; |
| |
| }; |
| |
| /** An animation channel. */ |
| struct AnimationChannel |
| { |
| /** 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. */ |
| std::string mSourceTimes; |
| /** Source URL of the value values. Collada calls them "output". */ |
| std::string mSourceValues; |
| /** Source URL of the IN_TANGENT semantic values. */ |
| std::string mInTanValues; |
| /** Source URL of the OUT_TANGENT semantic values. */ |
| std::string mOutTanValues; |
| /** Source URL of the INTERPOLATION semantic values. */ |
| std::string mInterpolationValues; |
| }; |
| |
| /** An animation. Container for 0-x animation channels or 0-x animations */ |
| struct Animation |
| { |
| /** Anim name */ |
| std::string mName; |
| |
| /** the animation channels, if any */ |
| std::vector<AnimationChannel> mChannels; |
| |
| /** the sub-animations, if any */ |
| std::vector<Animation*> mSubAnims; |
| |
| /** Destructor */ |
| ~Animation() |
| { |
| for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) |
| delete *it; |
| } |
| |
| /** Collect all channels in the animation hierarchy into a single channel list. */ |
| void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) |
| { |
| channels.insert(channels.end(), mChannels.begin(), mChannels.end()); |
| |
| for (std::vector<Animation*>::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. */ |
| void CombineSingleChannelAnimations() |
| { |
| CombineSingleChannelAnimationsRecursively(this); |
| } |
| |
| void CombineSingleChannelAnimationsRecursively(Animation *pParent) |
| { |
| for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) |
| { |
| Animation *anim = *it; |
| |
| CombineSingleChannelAnimationsRecursively(anim); |
| |
| if (anim->mChannels.size() == 1) |
| { |
| pParent->mChannels.push_back(anim->mChannels[0]); |
| |
| it = pParent->mSubAnims.erase(it); |
| |
| delete anim; |
| } |
| else |
| { |
| ++it; |
| } |
| } |
| } |
| }; |
| |
| /** Description of a collada animation channel which has been determined to affect the current node */ |
| struct ChannelEntry |
| { |
| 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 |
| size_t mSubElement; // starting index inside the transform data |
| |
| // resolved data references |
| const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values |
| const Collada::Data* mTimeData; ///> Source data array for the time values |
| const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values |
| const Collada::Data* mValueData; ///> Source datat array for the key value values |
| |
| ChannelEntry() |
| : mChannel() |
| , mTransformIndex() |
| , mSubElement() |
| , mTimeAccessor() |
| , mTimeData() |
| , mValueAccessor() |
| , mValueData() |
| {} |
| }; |
| |
| } // end of namespace Collada |
| } // end of namespace Assimp |
| |
| #endif // AI_COLLADAHELPER_H_INC |