1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following 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
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#include "ScenePreprocessor.h"
43#include <assimp/ai_assert.h>
44#include <assimp/scene.h>
45#include <assimp/DefaultLogger.hpp>
46
47
48using namespace Assimp;
49
50// ---------------------------------------------------------------------------------------------
51void ScenePreprocessor::ProcessScene ()
52{
53 ai_assert(scene != NULL);
54
55 // Process all meshes
56 for (unsigned int i = 0; i < scene->mNumMeshes;++i)
57 ProcessMesh(scene->mMeshes[i]);
58
59 // - nothing to do for nodes for the moment
60 // - nothing to do for textures for the moment
61 // - nothing to do for lights for the moment
62 // - nothing to do for cameras for the moment
63
64 // Process all animations
65 for (unsigned int i = 0; i < scene->mNumAnimations;++i)
66 ProcessAnimation(scene->mAnimations[i]);
67
68 // Generate a default material if none was specified
69 if (!scene->mNumMaterials && scene->mNumMeshes) {
70 scene->mMaterials = new aiMaterial*[2];
71 aiMaterial* helper;
72
73 aiString name;
74
75 scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial();
76 aiColor3D clr(0.6f,0.6f,0.6f);
77 helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
78
79 // setup the default name to make this material identifiable
80 name.Set(AI_DEFAULT_MATERIAL_NAME);
81 helper->AddProperty(&name,AI_MATKEY_NAME);
82
83 DefaultLogger::get()->debug("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'");
84
85 for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
86 scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials;
87 }
88
89 scene->mNumMaterials++;
90 }
91}
92
93// ---------------------------------------------------------------------------------------------
94void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
95{
96 // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
97 for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
98 if (!mesh->mTextureCoords[i]) {
99 mesh->mNumUVComponents[i] = 0;
100 } else {
101 if (!mesh->mNumUVComponents[i])
102 mesh->mNumUVComponents[i] = 2;
103
104 aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices;
105
106 // Ensure unsued components are zeroed. This will make 1D texture channels work
107 // as if they were 2D channels .. just in case an application doesn't handle
108 // this case
109 if (2 == mesh->mNumUVComponents[i]) {
110 for (; p != end; ++p)
111 p->z = 0.f;
112 }
113 else if (1 == mesh->mNumUVComponents[i]) {
114 for (; p != end; ++p)
115 p->z = p->y = 0.f;
116 }
117 else if (3 == mesh->mNumUVComponents[i]) {
118 // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
119 for (; p != end; ++p) {
120 if (p->z != 0)
121 break;
122 }
123 if (p == end) {
124 DefaultLogger::get()->warn("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
125 mesh->mNumUVComponents[i] = 2;
126 }
127 }
128 }
129 }
130
131 // If the information which primitive types are there in the
132 // mesh is currently not available, compute it.
133 if (!mesh->mPrimitiveTypes) {
134 for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
135 aiFace& face = mesh->mFaces[a];
136 switch (face.mNumIndices)
137 {
138 case 3u:
139 mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
140 break;
141
142 case 2u:
143 mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
144 break;
145
146 case 1u:
147 mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
148 break;
149
150 default:
151 mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
152 break;
153 }
154 }
155 }
156
157 // If tangents and normals are given but no bitangents compute them
158 if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
159
160 mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
161 for (unsigned int i = 0; i < mesh->mNumVertices;++i) {
162 mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
163 }
164 }
165}
166
167// ---------------------------------------------------------------------------------------------
168void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
169{
170 double first = 10e10, last = -10e10;
171 for (unsigned int i = 0; i < anim->mNumChannels;++i) {
172 aiNodeAnim* channel = anim->mChannels[i];
173
174 /* If the exact duration of the animation is not given
175 * compute it now.
176 */
177 if (anim->mDuration == -1.) {
178
179 // Position keys
180 for (unsigned int j = 0; j < channel->mNumPositionKeys;++j) {
181 aiVectorKey& key = channel->mPositionKeys[j];
182 first = std::min (first, key.mTime);
183 last = std::max (last, key.mTime);
184 }
185
186 // Scaling keys
187 for (unsigned int j = 0; j < channel->mNumScalingKeys;++j ) {
188 aiVectorKey& key = channel->mScalingKeys[j];
189 first = std::min (first, key.mTime);
190 last = std::max (last, key.mTime);
191 }
192
193 // Rotation keys
194 for (unsigned int j = 0; j < channel->mNumRotationKeys;++j ) {
195 aiQuatKey& key = channel->mRotationKeys[ j ];
196 first = std::min (first, key.mTime);
197 last = std::max (last, key.mTime);
198 }
199 }
200
201 /* Check whether the animation channel has no rotation
202 * or position tracks. In this case we generate a dummy
203 * track from the information we have in the transformation
204 * matrix of the corresponding node.
205 */
206 if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
207 // Find the node that belongs to this animation
208 aiNode* node = scene->mRootNode->FindNode(channel->mNodeName);
209 if (node) // ValidateDS will complain later if 'node' is NULL
210 {
211 // Decompose the transformation matrix of the node
212 aiVector3D scaling, position;
213 aiQuaternion rotation;
214
215 node->mTransformation.Decompose(scaling, rotation,position);
216
217 // No rotation keys? Generate a dummy track
218 if (!channel->mNumRotationKeys) {
219 channel->mNumRotationKeys = 1;
220 channel->mRotationKeys = new aiQuatKey[1];
221 aiQuatKey& q = channel->mRotationKeys[0];
222
223 q.mTime = 0.;
224 q.mValue = rotation;
225
226 DefaultLogger::get()->debug("ScenePreprocessor: Dummy rotation track has been generated");
227 }
228
229 // No scaling keys? Generate a dummy track
230 if (!channel->mNumScalingKeys) {
231 channel->mNumScalingKeys = 1;
232 channel->mScalingKeys = new aiVectorKey[1];
233 aiVectorKey& q = channel->mScalingKeys[0];
234
235 q.mTime = 0.;
236 q.mValue = scaling;
237
238 DefaultLogger::get()->debug("ScenePreprocessor: Dummy scaling track has been generated");
239 }
240
241 // No position keys? Generate a dummy track
242 if (!channel->mNumPositionKeys) {
243 channel->mNumPositionKeys = 1;
244 channel->mPositionKeys = new aiVectorKey[1];
245 aiVectorKey& q = channel->mPositionKeys[0];
246
247 q.mTime = 0.;
248 q.mValue = position;
249
250 DefaultLogger::get()->debug("ScenePreprocessor: Dummy position track has been generated");
251 }
252 }
253 }
254 }
255
256 if (anim->mDuration == -1.) {
257 DefaultLogger::get()->debug("ScenePreprocessor: Setting animation duration");
258 anim->mDuration = last - std::min( first, 0. );
259 }
260}
261