/src/assimp/code/AssetLib/Collada/ColladaHelper.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, 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 { |
124 | | Camera() : |
125 | 0 | mOrtho(false), |
126 | 0 | mHorFov(10e10f), |
127 | 0 | mVerFov(10e10f), |
128 | 0 | mAspect(10e10f), |
129 | 0 | mZNear(0.1f), |
130 | 0 | 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 | 0 | #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f |
152 | | |
153 | | /** A collada light source. */ |
154 | | struct Light { |
155 | | Light() : |
156 | 0 | mType(aiLightSource_UNDEFINED), |
157 | 0 | mAttConstant(1.f), |
158 | 0 | mAttLinear(0.f), |
159 | 0 | mAttQuadratic(0.f), |
160 | 0 | mFalloffAngle(180.f), |
161 | 0 | mFalloffExponent(0.f), |
162 | 0 | mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), |
163 | 0 | mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET), |
164 | 0 | 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 { |
192 | | InputSemanticMapEntry() : |
193 | 0 | mSet(0), |
194 | 0 | 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 | 0 | bool operator==(const std::string &s) const { |
214 | 0 | return s == mMatName; |
215 | 0 | } |
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 |
273 | | Node() : |
274 | 0 | mParent(nullptr) { |
275 | | // empty |
276 | 0 | } |
277 | | |
278 | | /// Destructor: delete all children subsequently |
279 | 0 | ~Node() { |
280 | 0 | for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) { |
281 | 0 | delete *it; |
282 | 0 | } |
283 | 0 | } |
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 | | |
305 | 0 | Accessor() { |
306 | 0 | mCount = 0; |
307 | 0 | mSize = 0; |
308 | 0 | mOffset = 0; |
309 | 0 | mStride = 0; |
310 | 0 | mData = nullptr; |
311 | 0 | mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; |
312 | 0 | } |
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 | | |
328 | 0 | InputChannel() { |
329 | 0 | mType = IT_Invalid; |
330 | 0 | mIndex = 0; |
331 | 0 | mOffset = 0; |
332 | 0 | mResolved = nullptr; |
333 | 0 | } |
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 { |
344 | | Mesh(const std::string &id) : |
345 | 0 | mId(id) { |
346 | 0 | for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { |
347 | 0 | mNumUVComponents[i] = 2; |
348 | 0 | } |
349 | 0 | } |
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 { |
459 | | Sampler() : |
460 | 0 | mWrapU(true), |
461 | 0 | mWrapV(true), |
462 | | mMirrorU(), |
463 | | mMirrorV(), |
464 | 0 | mOp(aiTextureOp_Multiply), |
465 | | mUVId(UINT_MAX), |
466 | 0 | mWeighting(1.f), |
467 | 0 | 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 | | |
536 | | Effect() : |
537 | 0 | mShadeType(Shade_Phong), |
538 | 0 | mEmissive(0, 0, 0, 1), |
539 | 0 | mAmbient(0.1f, 0.1f, 0.1f, 1), |
540 | 0 | mDiffuse(0.6f, 0.6f, 0.6f, 1), |
541 | 0 | mSpecular(0.4f, 0.4f, 0.4f, 1), |
542 | 0 | mTransparent(0, 0, 0, 1), |
543 | 0 | mShininess(10.0f), |
544 | 0 | mRefractIndex(1.f), |
545 | 0 | mReflectivity(0.f), |
546 | 0 | mTransparency(1.f), |
547 | 0 | mHasTransparency(false), |
548 | 0 | mRGBTransparency(false), |
549 | 0 | mInvertTransparency(false), |
550 | 0 | mDoubleSided(false), |
551 | 0 | mWireframe(false), |
552 | 0 | mFaceted(false) { |
553 | 0 | } |
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 |
597 | 1 | ~Animation() { |
598 | 1 | for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { |
599 | 0 | delete *it; |
600 | 0 | } |
601 | 1 | } |
602 | | |
603 | | /// Collect all channels in the animation hierarchy into a single channel list. |
604 | 0 | void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) { |
605 | 0 | channels.insert(channels.end(), mChannels.begin(), mChannels.end()); |
606 | |
|
607 | 0 | for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) { |
608 | 0 | Animation *pAnim = (*it); |
609 | 0 | pAnim->CollectChannelsRecursively(channels); |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | /// Combine all single-channel animations' channel into the same (parent) animation channel list. |
614 | 0 | void CombineSingleChannelAnimations() { |
615 | 0 | CombineSingleChannelAnimationsRecursively(this); |
616 | 0 | } |
617 | | |
618 | 0 | void CombineSingleChannelAnimationsRecursively(Animation *pParent) { |
619 | 0 | std::set<std::string> childrenTargets; |
620 | 0 | bool childrenAnimationsHaveDifferentChannels = true; |
621 | |
|
622 | 0 | for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { |
623 | 0 | Animation *anim = *it; |
624 | | // Assign the first animation name to the parent if empty. |
625 | | // This prevents the animation name from being lost when animations are combined |
626 | 0 | if (mName.empty()) { |
627 | 0 | mName = anim->mName; |
628 | 0 | } |
629 | 0 | CombineSingleChannelAnimationsRecursively(anim); |
630 | |
|
631 | 0 | if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && |
632 | 0 | childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { |
633 | 0 | childrenTargets.insert(anim->mChannels[0].mTarget); |
634 | 0 | } else { |
635 | 0 | childrenAnimationsHaveDifferentChannels = false; |
636 | 0 | } |
637 | |
|
638 | 0 | ++it; |
639 | 0 | } |
640 | | |
641 | | // We only want to combine animations if they have different channels |
642 | 0 | if (childrenAnimationsHaveDifferentChannels) { |
643 | 0 | for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { |
644 | 0 | Animation *anim = *it; |
645 | |
|
646 | 0 | pParent->mChannels.push_back(anim->mChannels[0]); |
647 | |
|
648 | 0 | it = pParent->mSubAnims.erase(it); |
649 | |
|
650 | 0 | delete anim; |
651 | 0 | continue; |
652 | 0 | } |
653 | 0 | } |
654 | 0 | } |
655 | | }; |
656 | | |
657 | | /// Description of a collada animation channel which has been determined to affect the current node |
658 | | struct ChannelEntry { |
659 | | const Collada::AnimationChannel *mChannel; ///< the source channel |
660 | | std::string mTargetId; |
661 | | std::string mTransformId; // the ID of the transformation step of the node which is influenced |
662 | | size_t mTransformIndex; // Index into the node's transform chain to apply the channel to |
663 | | size_t mSubElement; // starting index inside the transform data |
664 | | |
665 | | // resolved data references |
666 | | const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values |
667 | | const Collada::Data *mTimeData; ///> Source data array for the time values |
668 | | const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values |
669 | | const Collada::Data *mValueData; ///> Source data array for the key value values |
670 | | |
671 | | ChannelEntry() : |
672 | | mChannel(), |
673 | | mTransformIndex(), |
674 | | mSubElement(), |
675 | | mTimeAccessor(), |
676 | | mTimeData(), |
677 | | mValueAccessor(), |
678 | 0 | mValueData() {} |
679 | | }; |
680 | | |
681 | | } // end of namespace Collada |
682 | | } // end of namespace Assimp |
683 | | |
684 | | #endif // AI_COLLADAHELPER_H_INC |