nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "ScenePreprocessor.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: // --------------------------------------------------------------------------------------------- nuclear@0: void ScenePreprocessor::ProcessScene () nuclear@0: { nuclear@0: ai_assert(scene != NULL); nuclear@0: nuclear@0: // Process all meshes nuclear@0: for (unsigned int i = 0; i < scene->mNumMeshes;++i) nuclear@0: ProcessMesh(scene->mMeshes[i]); nuclear@0: nuclear@0: // - nothing to do for nodes for the moment nuclear@0: // - nothing to do for textures for the moment nuclear@0: // - nothing to do for lights for the moment nuclear@0: // - nothing to do for cameras for the moment nuclear@0: nuclear@0: // Process all animations nuclear@0: for (unsigned int i = 0; i < scene->mNumAnimations;++i) nuclear@0: ProcessAnimation(scene->mAnimations[i]); nuclear@0: nuclear@0: // Generate a default material if none was specified nuclear@0: if (!scene->mNumMaterials && scene->mNumMeshes) { nuclear@0: scene->mMaterials = new aiMaterial*[2]; nuclear@0: aiMaterial* helper; nuclear@0: nuclear@0: aiString name; nuclear@0: nuclear@0: scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial(); nuclear@0: aiColor3D clr(0.6f,0.6f,0.6f); nuclear@0: helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); nuclear@0: nuclear@0: // setup the default name to make this material identifyable nuclear@0: name.Set(AI_DEFAULT_MATERIAL_NAME); nuclear@0: helper->AddProperty(&name,AI_MATKEY_NAME); nuclear@0: nuclear@0: DefaultLogger::get()->debug("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); nuclear@0: nuclear@0: for (unsigned int i = 0; i < scene->mNumMeshes;++i) { nuclear@0: scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials; nuclear@0: } nuclear@0: nuclear@0: scene->mNumMaterials++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // --------------------------------------------------------------------------------------------- nuclear@0: void ScenePreprocessor::ProcessMesh (aiMesh* mesh) nuclear@0: { nuclear@0: // If aiMesh::mNumUVComponents is *not* set assign the default value of 2 nuclear@0: for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { nuclear@0: if (!mesh->mTextureCoords[i]) nuclear@0: mesh->mNumUVComponents[i] = 0; nuclear@0: nuclear@0: else { nuclear@0: if( !mesh->mNumUVComponents[i]) nuclear@0: mesh->mNumUVComponents[i] = 2; nuclear@0: nuclear@0: aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices; nuclear@0: nuclear@0: // Ensure unsued components are zeroed. This will make 1D texture channels work nuclear@0: // as if they were 2D channels .. just in case an application doesn't handle nuclear@0: // this case nuclear@0: if (2 == mesh->mNumUVComponents[i]) { nuclear@0: for (; p != end; ++p) nuclear@0: p->z = 0.f; nuclear@0: } nuclear@0: else if (1 == mesh->mNumUVComponents[i]) { nuclear@0: for (; p != end; ++p) nuclear@0: p->z = p->y = 0.f; nuclear@0: } nuclear@0: else if (3 == mesh->mNumUVComponents[i]) { nuclear@0: nuclear@0: // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element nuclear@0: for (; p != end; ++p) { nuclear@0: if (p->z != 0) nuclear@0: break; nuclear@0: } nuclear@0: if (p == end) { nuclear@0: DefaultLogger::get()->warn("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D."); nuclear@0: mesh->mNumUVComponents[i] = 2; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // If the information which primitive types are there in the nuclear@0: // mesh is currently not available, compute it. nuclear@0: if (!mesh->mPrimitiveTypes) { nuclear@0: for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { nuclear@0: aiFace& face = mesh->mFaces[a]; nuclear@0: switch (face.mNumIndices) nuclear@0: { nuclear@0: case 3u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; nuclear@0: break; nuclear@0: nuclear@0: case 2u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; nuclear@0: break; nuclear@0: nuclear@0: case 1u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // If tangents and normals are given but no bitangents compute them nuclear@0: if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { nuclear@0: nuclear@0: mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; nuclear@0: for (unsigned int i = 0; i < mesh->mNumVertices;++i) { nuclear@0: mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // --------------------------------------------------------------------------------------------- nuclear@0: void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) nuclear@0: { nuclear@0: double first = 10e10, last = -10e10; nuclear@0: for (unsigned int i = 0; i < anim->mNumChannels;++i) { nuclear@0: aiNodeAnim* channel = anim->mChannels[i]; nuclear@0: nuclear@0: /* If the exact duration of the animation is not given nuclear@0: * compute it now. nuclear@0: */ nuclear@0: if (anim->mDuration == -1.) { nuclear@0: nuclear@0: // Position keys nuclear@0: for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) { nuclear@0: aiVectorKey& key = channel->mPositionKeys[i]; nuclear@0: first = std::min (first, key.mTime); nuclear@0: last = std::max (last, key.mTime); nuclear@0: } nuclear@0: nuclear@0: // Scaling keys nuclear@0: for (unsigned int i = 0; i < channel->mNumScalingKeys;++i) { nuclear@0: aiVectorKey& key = channel->mScalingKeys[i]; nuclear@0: first = std::min (first, key.mTime); nuclear@0: last = std::max (last, key.mTime); nuclear@0: } nuclear@0: nuclear@0: // Rotation keys nuclear@0: for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) { nuclear@0: aiQuatKey& key = channel->mRotationKeys[i]; nuclear@0: first = std::min (first, key.mTime); nuclear@0: last = std::max (last, key.mTime); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /* Check whether the animation channel has no rotation nuclear@0: * or position tracks. In this case we generate a dummy nuclear@0: * track from the information we have in the transformation nuclear@0: * matrix of the corresponding node. nuclear@0: */ nuclear@0: if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { nuclear@0: // Find the node that belongs to this animation nuclear@0: aiNode* node = scene->mRootNode->FindNode(channel->mNodeName); nuclear@0: if (node) // ValidateDS will complain later if 'node' is NULL nuclear@0: { nuclear@0: // Decompose the transformation matrix of the node nuclear@0: aiVector3D scaling, position; nuclear@0: aiQuaternion rotation; nuclear@0: nuclear@0: node->mTransformation.Decompose(scaling, rotation,position); nuclear@0: nuclear@0: // No rotation keys? Generate a dummy track nuclear@0: if (!channel->mNumRotationKeys) { nuclear@0: channel->mNumRotationKeys = 1; nuclear@0: channel->mRotationKeys = new aiQuatKey[1]; nuclear@0: aiQuatKey& q = channel->mRotationKeys[0]; nuclear@0: nuclear@0: q.mTime = 0.; nuclear@0: q.mValue = rotation; nuclear@0: nuclear@0: DefaultLogger::get()->debug("ScenePreprocessor: Dummy rotation track has been generated"); nuclear@0: } nuclear@0: nuclear@0: // No scaling keys? Generate a dummy track nuclear@0: if (!channel->mNumScalingKeys) { nuclear@0: channel->mNumScalingKeys = 1; nuclear@0: channel->mScalingKeys = new aiVectorKey[1]; nuclear@0: aiVectorKey& q = channel->mScalingKeys[0]; nuclear@0: nuclear@0: q.mTime = 0.; nuclear@0: q.mValue = scaling; nuclear@0: nuclear@0: DefaultLogger::get()->debug("ScenePreprocessor: Dummy scaling track has been generated"); nuclear@0: } nuclear@0: nuclear@0: // No position keys? Generate a dummy track nuclear@0: if (!channel->mNumPositionKeys) { nuclear@0: channel->mNumPositionKeys = 1; nuclear@0: channel->mPositionKeys = new aiVectorKey[1]; nuclear@0: aiVectorKey& q = channel->mPositionKeys[0]; nuclear@0: nuclear@0: q.mTime = 0.; nuclear@0: q.mValue = position; nuclear@0: nuclear@0: DefaultLogger::get()->debug("ScenePreprocessor: Dummy position track has been generated"); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (anim->mDuration == -1.) { nuclear@0: DefaultLogger::get()->debug("ScenePreprocessor: Setting animation duration"); nuclear@0: anim->mDuration = last - std::min( first, 0. ); nuclear@0: } nuclear@0: }