1 /* 2 Open Asset Import Library (assimp) 3 ---------------------------------------------------------------------- 4 5 Copyright (c) 2006-2021, assimp team 6 7 All rights reserved. 8 9 Redistribution and use of this software in source and binary forms, 10 with or without modification, are permitted provided that the 11 following conditions are met: 12 13 * Redistributions of source code must retain the above 14 copyright notice, this list of conditions and the 15 following disclaimer. 16 17 * Redistributions in binary form must reproduce the above 18 copyright notice, this list of conditions and the 19 following disclaimer in the documentation and/or other 20 materials provided with the distribution. 21 22 * Neither the name of the assimp team, nor the names of its 23 contributors may be used to endorse or promote products 24 derived from this software without specific prior 25 written permission of the assimp team. 26 27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 39 ---------------------------------------------------------------------- 40 */ 41 42 /** Helper structures for the Collada loader */ 43 44 #ifndef AI_COLLADAHELPER_H_INC 45 #define AI_COLLADAHELPER_H_INC 46 47 #include <assimp/light.h> 48 #include <assimp/material.h> 49 #include <assimp/mesh.h> 50 51 #include <cstdint> 52 #include <map> 53 #include <set> 54 #include <vector> 55 56 struct aiMaterial; 57 58 namespace Assimp { 59 namespace Collada { 60 61 /// Collada file versions which evolved during the years ... 62 enum FormatVersion { 63 FV_1_5_n, 64 FV_1_4_n, 65 FV_1_3_n 66 }; 67 68 /// Transformation types that can be applied to a node 69 enum TransformType { 70 TF_LOOKAT, 71 TF_ROTATE, 72 TF_TRANSLATE, 73 TF_SCALE, 74 TF_SKEW, 75 TF_MATRIX 76 }; 77 78 /// Different types of input data to a vertex or face 79 enum InputType { 80 IT_Invalid, 81 IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data. 82 IT_Position, 83 IT_Normal, 84 IT_Texcoord, 85 IT_Color, 86 IT_Tangent, 87 IT_Bitangent 88 }; 89 90 /// Supported controller types 91 enum ControllerType { 92 Skin, 93 Morph 94 }; 95 96 /// Supported morph methods 97 enum MorphMethod { 98 Normalized, 99 Relative 100 }; 101 102 /// Common metadata keys as <Collada, Assimp> 103 using MetaKeyPair = std::pair<std::string, std::string>; 104 using MetaKeyPairVector = std::vector<MetaKeyPair>; 105 106 /// Collada as lower_case (native) 107 const MetaKeyPairVector &GetColladaAssimpMetaKeys(); 108 109 // Collada as CamelCase (used by Assimp for consistency) 110 const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); 111 112 /// Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" 113 void ToCamelCase(std::string &text); 114 115 /// Contains all data for one of the different transformation types 116 struct Transform { 117 std::string mID; ///< SID of the transform step, by which anim channels address their target node 118 TransformType mType; 119 ai_real f[16]; ///< Interpretation of data depends on the type of the transformation 120 }; 121 122 /// A collada camera. 123 struct Camera { CameraCamera124 Camera() : 125 mOrtho(false), 126 mHorFov(10e10f), 127 mVerFov(10e10f), 128 mAspect(10e10f), 129 mZNear(0.1f), 130 mZFar(1000.f) {} 131 132 /// Name of camera 133 std::string mName; 134 135 /// True if it is an orthographic camera 136 bool mOrtho; 137 138 /// Horizontal field of view in degrees 139 ai_real mHorFov; 140 141 /// Vertical field of view in degrees 142 ai_real mVerFov; 143 144 /// Screen aspect 145 ai_real mAspect; 146 147 /// Near& far z 148 ai_real mZNear, mZFar; 149 }; 150 151 #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f 152 153 /** A collada light source. */ 154 struct Light { LightLight155 Light() : 156 mType(aiLightSource_UNDEFINED), 157 mAttConstant(1.f), 158 mAttLinear(0.f), 159 mAttQuadratic(0.f), 160 mFalloffAngle(180.f), 161 mFalloffExponent(0.f), 162 mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), 163 mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), 164 mIntensity(1.f) {} 165 166 /// Type of the light source aiLightSourceType + ambient 167 unsigned int mType; 168 169 /// Color of the light 170 aiColor3D mColor; 171 172 /// Light attenuation 173 ai_real mAttConstant, mAttLinear, mAttQuadratic; 174 175 /// Spot light falloff 176 ai_real mFalloffAngle; 177 ai_real mFalloffExponent; 178 179 // ----------------------------------------------------- 180 // FCOLLADA extension from here 181 182 /// ... related stuff from maja and max extensions 183 ai_real mPenumbraAngle; 184 ai_real mOuterAngle; 185 186 /// Common light intensity 187 ai_real mIntensity; 188 }; 189 190 /** Short vertex index description */ 191 struct InputSemanticMapEntry { InputSemanticMapEntryInputSemanticMapEntry192 InputSemanticMapEntry() : 193 mSet(0), 194 mType(IT_Invalid) {} 195 196 /// Index of set, optional 197 unsigned int mSet; 198 199 /// Type of referenced vertex input 200 InputType mType; 201 }; 202 203 /// Table to map from effect to vertex input semantics 204 struct SemanticMappingTable { 205 /// Name of material 206 std::string mMatName; 207 208 /// List of semantic map commands, grouped by effect semantic name 209 using InputSemanticMap = std::map<std::string, InputSemanticMapEntry>; 210 InputSemanticMap mMap; 211 212 /// For std::find 213 bool operator==(const std::string &s) const { 214 return s == mMatName; 215 } 216 }; 217 218 /// A reference to a mesh inside a node, including materials assigned to the various subgroups. 219 /// The ID refers to either a mesh or a controller which specifies the mesh 220 struct MeshInstance { 221 ///< ID of the mesh or controller to be instanced 222 std::string mMeshOrController; 223 224 ///< Map of materials by the subgroup ID they're applied to 225 std::map<std::string, SemanticMappingTable> mMaterials; 226 }; 227 228 /// A reference to a camera inside a node 229 struct CameraInstance { 230 ///< ID of the camera 231 std::string mCamera; 232 }; 233 234 /// A reference to a light inside a node 235 struct LightInstance { 236 ///< ID of the camera 237 std::string mLight; 238 }; 239 240 /// A reference to a node inside a node 241 struct NodeInstance { 242 ///< ID of the node 243 std::string mNode; 244 }; 245 246 /// A node in a scene hierarchy 247 struct Node { 248 std::string mName; 249 std::string mID; 250 std::string mSID; 251 Node *mParent; 252 std::vector<Node *> mChildren; 253 254 /// Operations in order to calculate the resulting transformation to parent. 255 std::vector<Transform> mTransforms; 256 257 /// Meshes at this node 258 std::vector<MeshInstance> mMeshes; 259 260 /// Lights at this node 261 std::vector<LightInstance> mLights; 262 263 /// Cameras at this node 264 std::vector<CameraInstance> mCameras; 265 266 /// Node instances at this node 267 std::vector<NodeInstance> mNodeInstances; 268 269 /// Root-nodes: Name of primary camera, if any 270 std::string mPrimaryCamera; 271 272 /// Constructor. Begin with a zero parent NodeNode273 Node() : 274 mParent(nullptr) { 275 // empty 276 } 277 278 /// Destructor: delete all children subsequently ~NodeNode279 ~Node() { 280 for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) { 281 delete *it; 282 } 283 } 284 }; 285 286 /// Data source array: either floats or strings 287 struct Data { 288 bool mIsStringArray; 289 std::vector<ai_real> mValues; 290 std::vector<std::string> mStrings; 291 }; 292 293 /// Accessor to a data array 294 struct Accessor { 295 size_t mCount; // in number of objects 296 size_t mSize; // size of an object, in elements (floats or strings, mostly 1) 297 size_t mOffset; // in number of values 298 size_t mStride; // Stride in number of values 299 std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore. 300 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. 301 // For example, SubOffset[0] denotes which of the values inside the object is the vector X component. 302 std::string mSource; // URL of the source array 303 mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else 304 AccessorAccessor305 Accessor() { 306 mCount = 0; 307 mSize = 0; 308 mOffset = 0; 309 mStride = 0; 310 mData = nullptr; 311 mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; 312 } 313 }; 314 315 /// A single face in a mesh 316 struct Face { 317 std::vector<size_t> mIndices; 318 }; 319 320 /// An input channel for mesh data, referring to a single accessor 321 struct InputChannel { 322 InputType mType; // Type of the data 323 size_t mIndex; // Optional index, if multiple sets of the same data type are given 324 size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better. 325 std::string mAccessor; // ID of the accessor where to read the actual values from. 326 mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. nullptr else 327 InputChannelInputChannel328 InputChannel() { 329 mType = IT_Invalid; 330 mIndex = 0; 331 mOffset = 0; 332 mResolved = nullptr; 333 } 334 }; 335 336 /// Subset of a mesh with a certain material 337 struct SubMesh { 338 std::string mMaterial; ///< subgroup identifier 339 size_t mNumFaces; ///< number of faces in this sub-mesh 340 }; 341 342 /// Contains data for a single mesh 343 struct Mesh { MeshMesh344 Mesh(const std::string &id) : 345 mId(id) { 346 for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { 347 mNumUVComponents[i] = 2; 348 } 349 } 350 351 const std::string mId; 352 std::string mName; 353 354 // just to check if there's some sophisticated addressing involved... 355 // which we don't support, and therefore should warn about. 356 std::string mVertexID; 357 358 // Vertex data addressed by vertex indices 359 std::vector<InputChannel> mPerVertexData; 360 361 // actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed 362 std::vector<aiVector3D> mPositions; 363 std::vector<aiVector3D> mNormals; 364 std::vector<aiVector3D> mTangents; 365 std::vector<aiVector3D> mBitangents; 366 std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; 367 std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; 368 369 unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; 370 371 // Faces. Stored are only the number of vertices for each face. 372 // 1 == point, 2 == line, 3 == triangle, 4+ == poly 373 std::vector<size_t> mFaceSize; 374 375 // Position indices for all faces in the sequence given in mFaceSize - 376 // necessary for bone weight assignment 377 std::vector<size_t> mFacePosIndices; 378 379 // Sub-meshes in this mesh, each with a given material 380 std::vector<SubMesh> mSubMeshes; 381 }; 382 383 /// Which type of primitives the ReadPrimitives() function is going to read 384 enum PrimitiveType { 385 Prim_Invalid, 386 Prim_Lines, 387 Prim_LineStrip, 388 Prim_Triangles, 389 Prim_TriStrips, 390 Prim_TriFans, 391 Prim_Polylist, 392 Prim_Polygon 393 }; 394 395 /// A skeleton controller to deform a mesh with the use of joints 396 struct Controller { 397 // controller type 398 ControllerType mType; 399 400 // Morphing method if type is Morph 401 MorphMethod mMethod; 402 403 // the URL of the mesh deformed by the controller. 404 std::string mMeshId; 405 406 // accessor URL of the joint names 407 std::string mJointNameSource; 408 409 ///< 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 410 ai_real mBindShapeMatrix[16]; 411 412 // accessor URL of the joint inverse bind matrices 413 std::string mJointOffsetMatrixSource; 414 415 // input channel: joint names. 416 InputChannel mWeightInputJoints; 417 // input channel: joint weights 418 InputChannel mWeightInputWeights; 419 420 // Number of weights per vertex. 421 std::vector<size_t> mWeightCounts; 422 423 // JointIndex-WeightIndex pairs for all vertices 424 std::vector<std::pair<size_t, size_t>> mWeights; 425 426 std::string mMorphTarget; 427 std::string mMorphWeight; 428 }; 429 430 /// A collada material. Pretty much the only member is a reference to an effect. 431 struct Material { 432 std::string mName; 433 std::string mEffect; 434 }; 435 436 /// Type of the effect param 437 enum ParamType { 438 Param_Sampler, 439 Param_Surface 440 }; 441 442 /// A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them 443 struct EffectParam { 444 ParamType mType; 445 std::string mReference; // to which other thing the param is referring to. 446 }; 447 448 /// Shading type supported by the standard effect spec of Collada 449 enum ShadeType { 450 Shade_Invalid, 451 Shade_Constant, 452 Shade_Lambert, 453 Shade_Phong, 454 Shade_Blinn 455 }; 456 457 /// Represents a texture sampler in collada 458 struct Sampler { SamplerSampler459 Sampler() : 460 mWrapU(true), 461 mWrapV(true), 462 mMirrorU(), 463 mMirrorV(), 464 mOp(aiTextureOp_Multiply), 465 mUVId(UINT_MAX), 466 mWeighting(1.f), 467 mMixWithPrevious(1.f) {} 468 469 /// Name of image reference 470 std::string mName; 471 472 /// Wrap U? 473 bool mWrapU; 474 475 /// Wrap V? 476 bool mWrapV; 477 478 /// Mirror U? 479 bool mMirrorU; 480 481 /// Mirror V? 482 bool mMirrorV; 483 484 /// Blend mode 485 aiTextureOp mOp; 486 487 /// UV transformation 488 aiUVTransform mTransform; 489 490 /// Name of source UV channel 491 std::string mUVChannel; 492 493 /// Resolved UV channel index or UINT_MAX if not known 494 unsigned int mUVId; 495 496 // OKINO/MAX3D extensions from here 497 // ------------------------------------------------------- 498 499 /// Weighting factor 500 ai_real mWeighting; 501 502 /// Mixing factor from OKINO 503 ai_real mMixWithPrevious; 504 }; 505 506 /// A collada effect. Can contain about anything according to the Collada spec, 507 /// but we limit our version to a reasonable subset. 508 struct Effect { 509 /// Shading mode 510 ShadeType mShadeType; 511 512 /// Colors 513 aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, 514 mTransparent, mReflective; 515 516 /// Textures 517 Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, 518 mTexTransparent, mTexBump, mTexReflective; 519 520 /// Scalar factory 521 ai_real mShininess, mRefractIndex, mReflectivity; 522 ai_real mTransparency; 523 bool mHasTransparency; 524 bool mRGBTransparency; 525 bool mInvertTransparency; 526 527 /// local params referring to each other by their SID 528 using ParamLibrary = std::map<std::string, Collada::EffectParam>; 529 ParamLibrary mParams; 530 531 // MAX3D extensions 532 // --------------------------------------------------------- 533 // Double-sided? 534 bool mDoubleSided, mWireframe, mFaceted; 535 EffectEffect536 Effect() : 537 mShadeType(Shade_Phong), 538 mEmissive(0, 0, 0, 1), 539 mAmbient(0.1f, 0.1f, 0.1f, 1), 540 mDiffuse(0.6f, 0.6f, 0.6f, 1), 541 mSpecular(0.4f, 0.4f, 0.4f, 1), 542 mTransparent(0, 0, 0, 1), 543 mShininess(10.0f), 544 mRefractIndex(1.f), 545 mReflectivity(0.f), 546 mTransparency(1.f), 547 mHasTransparency(false), 548 mRGBTransparency(false), 549 mInvertTransparency(false), 550 mDoubleSided(false), 551 mWireframe(false), 552 mFaceted(false) { 553 } 554 }; 555 556 /// An image, meaning texture 557 struct Image { 558 std::string mFileName; 559 560 /// Embedded image data 561 std::vector<uint8_t> mImageData; 562 563 /// File format hint of embedded image data 564 std::string mEmbeddedFormat; 565 }; 566 567 /// An animation channel. 568 struct AnimationChannel { 569 /// URL of the data to animate. Could be about anything, but we support only the 570 /// "NodeID/TransformID.SubElement" notation 571 std::string mTarget; 572 573 /// Source URL of the time values. Collada calls them "input". Meh. 574 std::string mSourceTimes; 575 /// Source URL of the value values. Collada calls them "output". 576 std::string mSourceValues; 577 /// Source URL of the IN_TANGENT semantic values. 578 std::string mInTanValues; 579 /// Source URL of the OUT_TANGENT semantic values. 580 std::string mOutTanValues; 581 /// Source URL of the INTERPOLATION semantic values. 582 std::string mInterpolationValues; 583 }; 584 585 /// An animation. Container for 0-x animation channels or 0-x animations 586 struct Animation { 587 /// Anim name 588 std::string mName; 589 590 /// the animation channels, if any 591 std::vector<AnimationChannel> mChannels; 592 593 /// the sub-animations, if any 594 std::vector<Animation *> mSubAnims; 595 596 /// Destructor ~AnimationAnimation597 ~Animation() { 598 for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { 599 delete *it; 600 } 601 } 602 603 /// Collect all channels in the animation hierarchy into a single channel list. CollectChannelsRecursivelyAnimation604 void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) { 605 channels.insert(channels.end(), mChannels.begin(), mChannels.end()); 606 607 for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { 608 Animation *pAnim = (*it); 609 pAnim->CollectChannelsRecursively(channels); 610 } 611 } 612 613 /// Combine all single-channel animations' channel into the same (parent) animation channel list. CombineSingleChannelAnimationsAnimation614 void CombineSingleChannelAnimations() { 615 CombineSingleChannelAnimationsRecursively(this); 616 } 617 CombineSingleChannelAnimationsRecursivelyAnimation618 void CombineSingleChannelAnimationsRecursively(Animation *pParent) { 619 std::set<std::string> childrenTargets; 620 bool childrenAnimationsHaveDifferentChannels = true; 621 622 for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { 623 Animation *anim = *it; 624 CombineSingleChannelAnimationsRecursively(anim); 625 626 if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && 627 childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { 628 childrenTargets.insert(anim->mChannels[0].mTarget); 629 } else { 630 childrenAnimationsHaveDifferentChannels = false; 631 } 632 633 ++it; 634 } 635 636 // We only want to combine animations if they have different channels 637 if (childrenAnimationsHaveDifferentChannels) { 638 for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { 639 Animation *anim = *it; 640 641 pParent->mChannels.push_back(anim->mChannels[0]); 642 643 it = pParent->mSubAnims.erase(it); 644 645 delete anim; 646 continue; 647 } 648 } 649 } 650 }; 651 652 /// Description of a collada animation channel which has been determined to affect the current node 653 struct ChannelEntry { 654 const Collada::AnimationChannel *mChannel; ///< the source channel 655 std::string mTargetId; 656 std::string mTransformId; // the ID of the transformation step of the node which is influenced 657 size_t mTransformIndex; // Index into the node's transform chain to apply the channel to 658 size_t mSubElement; // starting index inside the transform data 659 660 // resolved data references 661 const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values 662 const Collada::Data *mTimeData; ///> Source data array for the time values 663 const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values 664 const Collada::Data *mValueData; ///> Source datat array for the key value values 665 ChannelEntryChannelEntry666 ChannelEntry() : 667 mChannel(), 668 mTransformIndex(), 669 mSubElement(), 670 mTimeAccessor(), 671 mTimeData(), 672 mValueAccessor(), 673 mValueData() {} 674 }; 675 676 } // end of namespace Collada 677 } // end of namespace Assimp 678 679 #endif // AI_COLLADAHELPER_H_INC 680