123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- /*
- Open Asset Import Library (assimp)
- ----------------------------------------------------------------------
- Copyright (c) 2006-2025, 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.
- ----------------------------------------------------------------------
- */
- /** Helper structures for the Collada loader */
- #ifndef AI_COLLADAHELPER_H_INC
- #define AI_COLLADAHELPER_H_INC
- #include <assimp/light.h>
- #include <assimp/material.h>
- #include <assimp/mesh.h>
- #include <cstdint>
- #include <map>
- #include <set>
- #include <vector>
- 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
- };
- /// Common metadata keys as <Collada, Assimp>
- using MetaKeyPair = std::pair<std::string, std::string>;
- using MetaKeyPairVector = std::vector<MetaKeyPair>;
- /// Collada as lower_case (native)
- const MetaKeyPairVector &GetColladaAssimpMetaKeys();
- // Collada as CamelCase (used by Assimp for consistency)
- const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
- /// Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool"
- void ToCamelCase(std::string &text);
- /// 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 orthographic 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
- using InputSemanticMap = std::map<std::string, InputSemanticMapEntry>;
- InputSemanticMap 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;
- /// Root-nodes: Name of primary camera, if any
- std::string mPrimaryCamera;
- /// Constructor. Begin with a zero parent
- Node() :
- mParent(nullptr) {
- // empty
- }
- /// 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]; // Sub-offset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
- // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
- std::string mSource; // URL of the source array
- mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
- Accessor() {
- mCount = 0;
- mSize = 0;
- mOffset = 0;
- mStride = 0;
- mData = nullptr;
- 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. nullptr else
- InputChannel() {
- mType = IT_Invalid;
- mIndex = 0;
- mOffset = 0;
- mResolved = nullptr;
- }
- };
- /// Subset of a mesh with a certain material
- struct SubMesh {
- std::string mMaterial; ///< subgroup identifier
- size_t mNumFaces; ///< number of faces in this sub-mesh
- };
- /// Contains data for a single mesh
- struct Mesh {
- Mesh(const std::string &id) :
- mId(id) {
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- mNumUVComponents[i] = 2;
- }
- }
- const std::string mId;
- 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;
- // Sub-meshes 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
- using ParamLibrary = std::map<std::string, Collada::EffectParam>;
- 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;
- /// Embedded image data
- std::vector<uint8_t> mImageData;
- /// File format hint 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) {
- std::set<std::string> childrenTargets;
- bool childrenAnimationsHaveDifferentChannels = true;
- for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
- Animation *anim = *it;
- // Assign the first animation name to the parent if empty.
- // This prevents the animation name from being lost when animations are combined
- if (mName.empty()) {
- mName = anim->mName;
- }
- CombineSingleChannelAnimationsRecursively(anim);
- if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
- childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
- childrenTargets.insert(anim->mChannels[0].mTarget);
- } else {
- childrenAnimationsHaveDifferentChannels = false;
- }
- ++it;
- }
- // We only want to combine animations if they have different channels
- if (childrenAnimationsHaveDifferentChannels) {
- for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
- Animation *anim = *it;
- pParent->mChannels.push_back(anim->mChannels[0]);
- it = pParent->mSubAnims.erase(it);
- delete anim;
- continue;
- }
- }
- }
- };
- /// 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 data 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
|