diff options
Diffstat (limited to 'src/3rdparty/assimp/code/OgreStructs.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/OgreStructs.cpp | 1193 |
1 files changed, 1193 insertions, 0 deletions
diff --git a/src/3rdparty/assimp/code/OgreStructs.cpp b/src/3rdparty/assimp/code/OgreStructs.cpp new file mode 100644 index 000000000..3eaf2df01 --- /dev/null +++ b/src/3rdparty/assimp/code/OgreStructs.cpp @@ -0,0 +1,1193 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "OgreStructs.h" +#include "TinyFormatter.h" + +namespace Assimp +{ +namespace Ogre +{ + +// VertexElement + +VertexElement::VertexElement() : + index(0), + source(0), + offset(0), + type(VET_FLOAT1), + semantic(VES_POSITION) +{ +} + +size_t VertexElement::Size() const +{ + return TypeSize(type); +} + +size_t VertexElement::ComponentCount() const +{ + return ComponentCount(type); +} + +size_t VertexElement::ComponentCount(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + case VET_FLOAT1: + case VET_DOUBLE1: + case VET_SHORT1: + case VET_USHORT1: + case VET_INT1: + case VET_UINT1: + return 1; + case VET_FLOAT2: + case VET_DOUBLE2: + case VET_SHORT2: + case VET_USHORT2: + case VET_INT2: + case VET_UINT2: + return 2; + case VET_FLOAT3: + case VET_DOUBLE3: + case VET_SHORT3: + case VET_USHORT3: + case VET_INT3: + case VET_UINT3: + return 3; + case VET_FLOAT4: + case VET_DOUBLE4: + case VET_SHORT4: + case VET_USHORT4: + case VET_INT4: + case VET_UINT4: + case VET_UBYTE4: + return 4; + } + return 0; +} + +size_t VertexElement::TypeSize(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + return sizeof(unsigned int); + case VET_FLOAT1: + return sizeof(float); + case VET_FLOAT2: + return sizeof(float)*2; + case VET_FLOAT3: + return sizeof(float)*3; + case VET_FLOAT4: + return sizeof(float)*4; + case VET_DOUBLE1: + return sizeof(double); + case VET_DOUBLE2: + return sizeof(double)*2; + case VET_DOUBLE3: + return sizeof(double)*3; + case VET_DOUBLE4: + return sizeof(double)*4; + case VET_SHORT1: + return sizeof(short); + case VET_SHORT2: + return sizeof(short)*2; + case VET_SHORT3: + return sizeof(short)*3; + case VET_SHORT4: + return sizeof(short)*4; + case VET_USHORT1: + return sizeof(unsigned short); + case VET_USHORT2: + return sizeof(unsigned short)*2; + case VET_USHORT3: + return sizeof(unsigned short)*3; + case VET_USHORT4: + return sizeof(unsigned short)*4; + case VET_INT1: + return sizeof(int); + case VET_INT2: + return sizeof(int)*2; + case VET_INT3: + return sizeof(int)*3; + case VET_INT4: + return sizeof(int)*4; + case VET_UINT1: + return sizeof(unsigned int); + case VET_UINT2: + return sizeof(unsigned int)*2; + case VET_UINT3: + return sizeof(unsigned int)*3; + case VET_UINT4: + return sizeof(unsigned int)*4; + case VET_UBYTE4: + return sizeof(unsigned char)*4; + } + return 0; +} + +std::string VertexElement::TypeToString() +{ + return TypeToString(type); +} + +std::string VertexElement::TypeToString(Type type) +{ + switch(type) + { + case VET_COLOUR: return "COLOUR"; + case VET_COLOUR_ABGR: return "COLOUR_ABGR"; + case VET_COLOUR_ARGB: return "COLOUR_ARGB"; + case VET_FLOAT1: return "FLOAT1"; + case VET_FLOAT2: return "FLOAT2"; + case VET_FLOAT3: return "FLOAT3"; + case VET_FLOAT4: return "FLOAT4"; + case VET_DOUBLE1: return "DOUBLE1"; + case VET_DOUBLE2: return "DOUBLE2"; + case VET_DOUBLE3: return "DOUBLE3"; + case VET_DOUBLE4: return "DOUBLE4"; + case VET_SHORT1: return "SHORT1"; + case VET_SHORT2: return "SHORT2"; + case VET_SHORT3: return "SHORT3"; + case VET_SHORT4: return "SHORT4"; + case VET_USHORT1: return "USHORT1"; + case VET_USHORT2: return "USHORT2"; + case VET_USHORT3: return "USHORT3"; + case VET_USHORT4: return "USHORT4"; + case VET_INT1: return "INT1"; + case VET_INT2: return "INT2"; + case VET_INT3: return "INT3"; + case VET_INT4: return "INT4"; + case VET_UINT1: return "UINT1"; + case VET_UINT2: return "UINT2"; + case VET_UINT3: return "UINT3"; + case VET_UINT4: return "UINT4"; + case VET_UBYTE4: return "UBYTE4"; + } + return "Uknown_VertexElement::Type"; +} + +std::string VertexElement::SemanticToString() +{ + return SemanticToString(semantic); +} + +std::string VertexElement::SemanticToString(Semantic semantic) +{ + switch(semantic) + { + case VES_POSITION: return "POSITION"; + case VES_BLEND_WEIGHTS: return "BLEND_WEIGHTS"; + case VES_BLEND_INDICES: return "BLEND_INDICES"; + case VES_NORMAL: return "NORMAL"; + case VES_DIFFUSE: return "DIFFUSE"; + case VES_SPECULAR: return "SPECULAR"; + case VES_TEXTURE_COORDINATES: return "TEXTURE_COORDINATES"; + case VES_BINORMAL: return "BINORMAL"; + case VES_TANGENT: return "TANGENT"; + } + return "Uknown_VertexElement::Semantic"; +} + +// IVertexData + +IVertexData::IVertexData() : + count(0) +{ +} + +bool IVertexData::HasBoneAssignments() const +{ + return !boneAssignments.empty(); +} + +void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex) +{ + BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]); + vertexIndexMapping[oldIndex].push_back(newIndex); +} + +void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const +{ + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + if (iter->vertexIndex == currentIndex) + { + VertexBoneAssignment a = (*iter); + a.vertexIndex = newIndex; + dest.push_back(a); + } + } +} + +AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices) +{ + AssimpVertexBoneWeightList weights; + for(size_t vi=0; vi<vertices; ++vi) + { + VertexBoneAssignmentList &vertexWeights = boneAssignmentsMap[vi]; + for (VertexBoneAssignmentList::const_iterator iter=vertexWeights.begin(), end=vertexWeights.end(); + iter!=end; ++iter) + { + std::vector<aiVertexWeight> &boneWeights = weights[iter->boneIndex]; + boneWeights.push_back(aiVertexWeight(vi, iter->weight)); + } + } + return weights; +} + +std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const +{ + std::set<uint16_t> referenced; + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + referenced.insert(iter->boneIndex); + } + return referenced; +} + +// VertexData + +VertexData::VertexData() +{ +} + +VertexData::~VertexData() +{ + Reset(); +} + +void VertexData::Reset() +{ + // Releases shared ptr memory streams. + vertexBindings.clear(); + vertexElements.clear(); +} + +uint32_t VertexData::VertexSize(uint16_t source) const +{ + uint32_t size = 0; + for(VertexElementList::const_iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + if (iter->source == source) + size += iter->Size(); + } + return size; +} + +MemoryStream *VertexData::VertexBuffer(uint16_t source) +{ + if (vertexBindings.find(source) != vertexBindings.end()) + return vertexBindings[source].get(); + return 0; +} + +VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index) +{ + for(VertexElementList::iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + VertexElement &element = (*iter); + if (element.semantic == semantic && element.index == index) + return &element; + } + return 0; +} + +// VertexDataXml + +VertexDataXml::VertexDataXml() +{ +} + +bool VertexDataXml::HasPositions() const +{ + return !positions.empty(); +} + +bool VertexDataXml::HasNormals() const +{ + return !normals.empty(); +} + +bool VertexDataXml::HasTangents() const +{ + return !tangents.empty(); +} + +bool VertexDataXml::HasUvs() const +{ + return !uvs.empty(); +} + +size_t VertexDataXml::NumUvs() const +{ + return uvs.size(); +} + +// IndexData + +IndexData::IndexData() : + count(0), + faceCount(0), + is32bit(false) +{ +} + +IndexData::~IndexData() +{ + Reset(); +} + +void IndexData::Reset() +{ + // Release shared ptr memory stream. + buffer.reset(); +} + +size_t IndexData::IndexSize() const +{ + return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t)); +} + +size_t IndexData::FaceSize() const +{ + return IndexSize() * 3; +} + +// Mesh + +Mesh::Mesh() : + sharedVertexData(0), + skeleton(0), + hasSkeletalAnimations(false) +{ +} + +Mesh::~Mesh() +{ + Reset(); +} + +void Mesh::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); i<len; ++i) { + OGRE_SAFE_DELETE(subMeshes[i]) + } + subMeshes.clear(); + for(size_t i=0, len=animations.size(); i<len; ++i) { + OGRE_SAFE_DELETE(animations[i]) + } + animations.clear(); + for(size_t i=0, len=poses.size(); i<len; ++i) { + OGRE_SAFE_DELETE(poses[i]) + } + poses.clear(); +} + +size_t Mesh::NumSubMeshes() const +{ + return subMeshes.size(); +} + +SubMesh *Mesh::GetSubMesh(uint16_t index) const +{ + for(size_t i=0; i<subMeshes.size(); ++i) + if (subMeshes[i]->index == index) + return subMeshes[i]; + return 0; +} + +void Mesh::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; i<dest->mNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); i<len; ++i) + { + dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode); + } + } + + // Animations + if (!skeleton->animations.empty()) + { + dest->mNumAnimations = skeleton->animations.size(); + dest->mAnimations = new aiAnimation*[dest->mNumAnimations]; + + for(size_t i=0, len=skeleton->animations.size(); i<len; ++i) + { + dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// ISubMesh + +ISubMesh::ISubMesh() : + index(0), + materialIndex(-1), + usesSharedVertexData(false), + operationType(OT_POINT_LIST) +{ +} + +// SubMesh + +SubMesh::SubMesh() : + vertexData(0), + indexData(new IndexData()) +{ +} + +SubMesh::~SubMesh() +{ + Reset(); +} + +void SubMesh::Reset() +{ + OGRE_SAFE_DELETE(vertexData) + OGRE_SAFE_DELETE(indexData) +} + +aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) +{ + if (operationType != OT_TRIANGLE_LIST) { + throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType); + } + + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Pick source vertex data from shader geometry or from internal geometry. + VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + + VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION); + VertexElement *normalsElement = src->GetVertexElement(VertexElement::VES_NORMAL); + VertexElement *uv1Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0); + VertexElement *uv2Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1); + + // Sanity checks + if (!positionsElement) { + throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!"); + } else if (positionsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + // Source streams + MemoryStream *positions = src->VertexBuffer(positionsElement->source); + MemoryStream *normals = (normalsElement ? src->VertexBuffer(normalsElement->source) : 0); + MemoryStream *uv1 = (uv1Element ? src->VertexBuffer(uv1Element->source) : 0); + MemoryStream *uv2 = (uv2Element ? src->VertexBuffer(uv2Element->source) : 0); + + // Element size + const size_t sizePosition = positionsElement->Size(); + const size_t sizeNormal = (normalsElement ? normalsElement->Size() : 0); + const size_t sizeUv1 = (uv1Element ? uv1Element->Size() : 0); + const size_t sizeUv2 = (uv2Element ? uv2Element->Size() : 0); + + // Vertex width + const size_t vWidthPosition = src->VertexSize(positionsElement->source); + const size_t vWidthNormal = (normalsElement ? src->VertexSize(normalsElement->source) : 0); + const size_t vWidthUv1 = (uv1Element ? src->VertexSize(uv1Element->source) : 0); + const size_t vWidthUv2 = (uv2Element ? src->VertexSize(uv2Element->source) : 0); + + bool boneAssignments = src->HasBoneAssignments(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs, ignoring incompatible UVs. + if (uv1) + { + if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[0] = uv1Element->ComponentCount(); + dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv1Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv1 = 0; + } + } + if (uv2) + { + if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[1] = uv2Element->ComponentCount(); + dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv2Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv2 = 0; + } + } + + aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : 0); + aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : 0); + + MemoryStream *faces = indexData->buffer.get(); + for (size_t fi=0, isize=indexData->IndexSize(), fsize=indexData->FaceSize(); + fi<dest->mNumFaces; ++fi) + { + // Source Ogre face + aiFace ogreFace; + ogreFace.mNumIndices = 3; + ogreFace.mIndices = new unsigned int[3]; + + faces->Seek(fi * fsize, aiOrigin_SET); + if (indexData->is32bit) + { + faces->Read(&ogreFace.mIndices[0], isize, 3); + } + else + { + uint16_t iout = 0; + for (size_t ii=0; ii<3; ++ii) + { + faces->Read(&iout, isize, 1); + ogreFace.mIndices[ii] = static_cast<unsigned int>(iout); + } + } + + // Destination Assimp face + aiFace &face = dest->mFaces[fi]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + + const size_t pos = fi * 3; + for (size_t v=0; v<3; ++v) + { + const size_t newIndex = pos + v; + + // Write face index + face.mIndices[v] = newIndex; + + // Ogres vertex index to ref into the source buffers. + const size_t ogreVertexIndex = ogreFace.mIndices[v]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET); + positions->Read(&dest->mVertices[newIndex], sizePosition, 1); + + // Normal + if (normals) + { + normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET); + normals->Read(&dest->mNormals[newIndex], sizeNormal, 1); + } + // UV0 + if (uv1 && uv1Dest) + { + uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET); + uv1->Read(&uv1Dest[newIndex], sizeUv1, 1); + uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + // UV1 + if (uv2 && uv2Dest) + { + uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET); + uv2->Read(&uv2Dest[newIndex], sizeUv2, 1); + uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// MeshXml + +MeshXml::MeshXml() : + sharedVertexData(0), + skeleton(0) +{ +} + +MeshXml::~MeshXml() +{ + Reset(); +} + +void MeshXml::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); i<len; ++i) { + OGRE_SAFE_DELETE(subMeshes[i]) + } + subMeshes.clear(); +} + +size_t MeshXml::NumSubMeshes() const +{ + return subMeshes.size(); +} + +SubMeshXml *MeshXml::GetSubMesh(uint16_t index) const +{ + for(size_t i=0; i<subMeshes.size(); ++i) + if (subMeshes[i]->index == index) + return subMeshes[i]; + return 0; +} + +void MeshXml::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; i<dest->mNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); i<len; ++i) + { + dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode); + } + } + + // Animations + if (!skeleton->animations.empty()) + { + dest->mNumAnimations = skeleton->animations.size(); + dest->mAnimations = new aiAnimation*[dest->mNumAnimations]; + + for(size_t i=0, len=skeleton->animations.size(); i<len; ++i) + { + dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// SubMeshXml + +SubMeshXml::SubMeshXml() : + vertexData(0), + indexData(new IndexDataXml()) +{ +} + +SubMeshXml::~SubMeshXml() +{ + Reset(); +} + +void SubMeshXml::Reset() +{ + OGRE_SAFE_DELETE(indexData) + OGRE_SAFE_DELETE(vertexData) +} + +aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent) +{ + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + bool boneAssignments = src->HasBoneAssignments(); + bool normals = src->HasNormals(); + size_t uvs = src->NumUvs(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs + for(size_t uvi=0; uvi<uvs; ++uvi) + { + dest->mNumUVComponents[uvi] = 2; + dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices]; + } + + for (size_t fi=0; fi<dest->mNumFaces; ++fi) + { + // Source Ogre face + aiFace &ogreFace = indexData->faces[fi]; + + // Destination Assimp face + aiFace &face = dest->mFaces[fi]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + + const size_t pos = fi * 3; + for (size_t v=0; v<3; ++v) + { + const size_t newIndex = pos + v; + + // Write face index + face.mIndices[v] = newIndex; + + // Ogres vertex index to ref into the source buffers. + const size_t ogreVertexIndex = ogreFace.mIndices[v]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + dest->mVertices[newIndex] = src->positions[ogreVertexIndex]; + + // Normal + if (normals) + dest->mNormals[newIndex] = src->normals[ogreVertexIndex]; + + // UVs + for(size_t uvi=0; uvi<uvs; ++uvi) + { + aiVector3D *uvDest = dest->mTextureCoords[uvi]; + std::vector<aiVector3D> &uvSrc = src->uvs[uvi]; + uvDest[newIndex] = uvSrc[ogreVertexIndex]; + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// Animation + +Animation::Animation(Skeleton *parent) : + parentSkeleton(parent), + parentMesh(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +Animation::Animation(Mesh *parent) : + parentMesh(parent), + parentSkeleton(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const +{ + if (!parentMesh) + return 0; + + bool sharedGeom = (track->target == 0); + if (sharedGeom) + return parentMesh->sharedVertexData; + else + return parentMesh->GetSubMesh(track->target-1)->vertexData; +} + +aiAnimation *Animation::ConvertToAssimpAnimation() +{ + aiAnimation *anim = new aiAnimation(); + anim->mName = name; + anim->mDuration = static_cast<double>(length); + anim->mTicksPerSecond = 1.0; + + // Tracks + if (!tracks.empty()) + { + anim->mNumChannels = tracks.size(); + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + + for(size_t i=0, len=tracks.size(); i<len; ++i) + { + anim->mChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton); + } + } + return anim; +} + +// Skeleton + +Skeleton::Skeleton() : + blendMode(ANIMBLEND_AVERAGE) +{ +} + +Skeleton::~Skeleton() +{ + Reset(); +} + +void Skeleton::Reset() +{ + for(size_t i=0, len=bones.size(); i<len; ++i) { + OGRE_SAFE_DELETE(bones[i]) + } + bones.clear(); + for(size_t i=0, len=animations.size(); i<len; ++i) { + OGRE_SAFE_DELETE(animations[i]) + } + animations.clear(); +} + +BoneList Skeleton::RootBones() const +{ + BoneList rootBones; + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if (!(*iter)->IsParented()) + rootBones.push_back((*iter)); + } + return rootBones; +} + +size_t Skeleton::NumRootBones() const +{ + size_t num = 0; + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if (!(*iter)->IsParented()) + num++; + } + return num; +} + +Bone *Skeleton::BoneByName(const std::string &name) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->name == name) + return (*iter); + } + return 0; +} + +Bone *Skeleton::BoneById(uint16_t id) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->id == id) + return (*iter); + } + return 0; +} + +// Bone + +Bone::Bone() : + id(0), + parent(0), + parentId(-1), + scale(1.0f, 1.0f, 1.0f) +{ +} + +bool Bone::IsParented() const +{ + return (parentId != -1 && parent != 0); +} + +uint16_t Bone::ParentId() const +{ + return static_cast<uint16_t>(parentId); +} + +void Bone::AddChild(Bone *bone) +{ + if (!bone) + return; + if (bone->IsParented()) + throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name); + + bone->parent = this; + bone->parentId = id; + children.push_back(bone->id); +} + +void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) +{ + if (!IsParented()) + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse(); + else + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix; + + defaultPose = aiMatrix4x4(scale, rotation, position); + + // Recursively for all children now that the parent matrix has been calculated. + for (size_t i=0, len=children.size(); i<len; ++i) + { + Bone *child = skeleton->BoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + child->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) +{ + // Bone node + aiNode* node = new aiNode(name); + node->mParent = parentNode; + node->mTransformation = defaultPose; + + // Children + if (!children.empty()) + { + node->mNumChildren = children.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + + for(size_t i=0, len=children.size(); i<len; ++i) + { + Bone *child = skeleton->BoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node); + } + } + return node; +} + +aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights) +{ + aiBone *bone = new aiBone(); + bone->mName = name; + bone->mOffsetMatrix = worldMatrix; + + if (!boneWeights.empty()) + { + bone->mNumWeights = boneWeights.size(); + bone->mWeights = new aiVertexWeight[boneWeights.size()]; + memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight)); + } + + return bone; +} + +// VertexAnimationTrack + +VertexAnimationTrack::VertexAnimationTrack() : + target(0), + type(VAT_NONE) +{ +} + +aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton) +{ + if (boneName.empty() || type != VAT_TRANSFORM) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM"); + } + + aiNodeAnim *nodeAnim = new aiNodeAnim(); + nodeAnim->mNodeName = boneName; + + Bone *bone = skeleton->BoneByName(boneName); + if (!bone) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton"); + } + + // Keyframes + size_t numKeyframes = transformKeyFrames.size(); + + nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes]; + nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mNumPositionKeys = numKeyframes; + nodeAnim->mNumRotationKeys = numKeyframes; + nodeAnim->mNumScalingKeys = numKeyframes; + + for(size_t kfi=0; kfi<numKeyframes; ++kfi) + { + TransformKeyFrame &kfSource = transformKeyFrames[kfi]; + + // Calculate the complete transformation from world space to bone space + aiVector3D pos; aiQuaternion rot; aiVector3D scale; + + aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform(); + finalTransform.Decompose(scale, rot, pos); + + double t = static_cast<double>(kfSource.timePos); + nodeAnim->mPositionKeys[kfi].mTime = t; + nodeAnim->mRotationKeys[kfi].mTime = t; + nodeAnim->mScalingKeys[kfi].mTime = t; + + nodeAnim->mPositionKeys[kfi].mValue = pos; + nodeAnim->mRotationKeys[kfi].mValue = rot; + nodeAnim->mScalingKeys[kfi].mValue = scale; + } + + return nodeAnim; +} + +// TransformKeyFrame + +TransformKeyFrame::TransformKeyFrame() : + timePos(0.0f), + scale(1.0f, 1.0f, 1.0f) +{ +} + +aiMatrix4x4 TransformKeyFrame::Transform() +{ + return aiMatrix4x4(scale, rotation, position); +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER |