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