#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
#include "OgreStructs.h"
#include "TinyFormatter.h"
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include "Exceptional.h"
namespace Assimp
{
namespace Ogre
{
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() :
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 (const auto &boneAssign : boneAssignments)
{
if (boneAssign.vertexIndex == currentIndex)
{
VertexBoneAssignment a = boneAssign;
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[static_cast<unsigned int>(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(static_cast<unsigned int>(vi), iter->weight));
}
}
return weights;
}
std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const
{
std::set<uint16_t> referenced;
for (const auto &boneAssign : boneAssignments)
{
referenced.insert(boneAssign.boneIndex);
}
return referenced;
}
VertexData::VertexData()
{
}
VertexData::~VertexData()
{
Reset();
}
void VertexData::Reset()
{
vertexBindings.clear();
vertexElements.clear();
}
uint32_t VertexData::VertexSize(uint16_t source) const
{
uint32_t size = 0;
for(const auto &element : vertexElements)
{
if (element.source == source)
size += static_cast<uint32_t>(element.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(auto & element : vertexElements)
{
if (element.semantic == semantic && element.index == index)
return &element;
}
return 0;
}
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() :
count(0),
faceCount(0),
is32bit(false)
{
}
IndexData::~IndexData()
{
Reset();
}
void IndexData::Reset()
{
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()
: hasSkeletalAnimations(false)
, skeleton(NULL)
, sharedVertexData(NULL)
, subMeshes()
, animations()
, poses()
{
}
Mesh::~Mesh()
{
Reset();
}
void Mesh::Reset()
{
OGRE_SAFE_DELETE(skeleton)
OGRE_SAFE_DELETE(sharedVertexData)
for(auto &mesh : subMeshes) {
OGRE_SAFE_DELETE(mesh)
}
subMeshes.clear();
for(auto &anim : animations) {
OGRE_SAFE_DELETE(anim)
}
animations.clear();
for(auto &pose : poses) {
OGRE_SAFE_DELETE(pose)
}
poses.clear();
}
size_t Mesh::NumSubMeshes() const
{
return subMeshes.size();
}
SubMesh *Mesh::GetSubMesh( size_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)
{
if ( nullptr == dest ) {
return;
}
dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
dest->mMeshes = new aiMesh*[dest->mNumMeshes];
dest->mRootNode = new aiNode();
dest->mRootNode->mNumMeshes = dest->mNumMeshes;
dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
for(size_t i=0; i<dest->mNumMeshes; ++i) {
dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
}
if (skeleton)
{
if (!skeleton->bones.empty())
{
BoneList rootBones = skeleton->RootBones();
dest->mRootNode->mNumChildren = static_cast<unsigned int>(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);
}
}
if (!skeleton->animations.empty())
{
dest->mNumAnimations = static_cast<unsigned int>(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() :
index(0),
materialIndex(-1),
usesSharedVertexData(false),
operationType(OT_POINT_LIST)
{
}
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;
if (materialIndex != -1)
dest->mMaterialIndex = materialIndex;
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);
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.");
}
dest->mNumFaces = indexData->faceCount;
dest->mFaces = new aiFace[dest->mNumFaces];
size_t uniqueVertexCount = dest->mNumFaces * 3;
dest->mNumVertices = static_cast<unsigned int>(uniqueVertexCount);
dest->mVertices = new aiVector3D[dest->mNumVertices];
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);
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);
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();
if (normals)
dest->mNormals = new aiVector3D[dest->mNumVertices];
if (uv1)
{
if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3)
{
dest->mNumUVComponents[0] = static_cast<unsigned int>(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] = static_cast<unsigned int>(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)
{
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);
}
}
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;
face.mIndices[v] = static_cast<unsigned int>(newIndex);
const size_t ogreVertexIndex = ogreFace.mIndices[v];
src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET);
positions->Read(&dest->mVertices[newIndex], sizePosition, 1);
if (normals)
{
normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET);
normals->Read(&dest->mNormals[newIndex], sizeNormal, 1);
}
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; }
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; }
}
}
if (parent->skeleton && boneAssignments)
{
AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
dest->mNumBones = static_cast<unsigned int>(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() :
skeleton(0),
sharedVertexData(0)
{
}
MeshXml::~MeshXml()
{
Reset();
}
void MeshXml::Reset()
{
OGRE_SAFE_DELETE(skeleton)
OGRE_SAFE_DELETE(sharedVertexData)
for(auto &mesh : subMeshes) {
OGRE_SAFE_DELETE(mesh)
}
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)
{
dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
dest->mMeshes = new aiMesh*[dest->mNumMeshes];
dest->mRootNode = new aiNode();
dest->mRootNode->mNumMeshes = dest->mNumMeshes;
dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
for(size_t i=0; i<dest->mNumMeshes; ++i)
{
dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
}
if (skeleton)
{
if (!skeleton->bones.empty())
{
BoneList rootBones = skeleton->RootBones();
dest->mRootNode->mNumChildren = static_cast<unsigned int>(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);
}
}
if (!skeleton->animations.empty())
{
dest->mNumAnimations = static_cast<unsigned int>(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() :
indexData(new IndexDataXml()),
vertexData(0)
{
}
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;
if (materialIndex != -1)
dest->mMaterialIndex = materialIndex;
dest->mNumFaces = indexData->faceCount;
dest->mFaces = new aiFace[dest->mNumFaces];
size_t uniqueVertexCount = dest->mNumFaces * 3;
dest->mNumVertices = static_cast<unsigned int>(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();
if (normals)
dest->mNormals = new aiVector3D[dest->mNumVertices];
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)
{
aiFace &ogreFace = indexData->faces[fi];
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;
face.mIndices[v] = static_cast<unsigned int>(newIndex);
const size_t ogreVertexIndex = ogreFace.mIndices[v];
src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
dest->mVertices[newIndex] = src->positions[ogreVertexIndex];
if (normals)
dest->mNormals[newIndex] = src->normals[ogreVertexIndex];
for(size_t uvi=0; uvi<uvs; ++uvi)
{
aiVector3D *uvDest = dest->mTextureCoords[uvi];
std::vector<aiVector3D> &uvSrc = src->uvs[uvi];
uvDest[newIndex] = uvSrc[ogreVertexIndex];
}
}
}
if (parent->skeleton && boneAssignments)
{
AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
dest->mNumBones = static_cast<unsigned int>(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(Skeleton *parent) :
parentMesh(NULL),
parentSkeleton(parent),
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;
if (!tracks.empty())
{
anim->mNumChannels = static_cast<unsigned int>(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() :
bones(),
animations(),
blendMode(ANIMBLEND_AVERAGE)
{
}
Skeleton::~Skeleton()
{
Reset();
}
void Skeleton::Reset()
{
for(auto &bone : bones) {
OGRE_SAFE_DELETE(bone)
}
bones.clear();
for(auto &anim : animations) {
OGRE_SAFE_DELETE(anim)
}
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() :
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);
for (auto boneId : children)
{
Bone *child = skeleton->BoneById(boneId);
if (!child) {
throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << boneId << " for parent " << id << " " << name);
}
child->CalculateWorldMatrixAndDefaultPose(skeleton);
}
}
aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
{
aiNode* node = new aiNode(name);
node->mParent = parentNode;
node->mTransformation = defaultPose;
if (!children.empty())
{
node->mNumChildren = static_cast<unsigned int>(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 * , const std::vector<aiVertexWeight> &boneWeights)
{
aiBone *bone = new aiBone();
bone->mName = name;
bone->mOffsetMatrix = worldMatrix;
if (!boneWeights.empty())
{
bone->mNumWeights = static_cast<unsigned int>(boneWeights.size());
bone->mWeights = new aiVertexWeight[boneWeights.size()];
memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight));
}
return bone;
}
VertexAnimationTrack::VertexAnimationTrack() :
type(VAT_NONE),
target(0)
{
}
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");
}
size_t numKeyframes = transformKeyFrames.size();
nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes];
nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes];
nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes];
nodeAnim->mNumPositionKeys = static_cast<unsigned int>(numKeyframes);
nodeAnim->mNumRotationKeys = static_cast<unsigned int>(numKeyframes);
nodeAnim->mNumScalingKeys = static_cast<unsigned int>(numKeyframes);
for(size_t kfi=0; kfi<numKeyframes; ++kfi)
{
TransformKeyFrame &kfSource = transformKeyFrames[kfi];
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() :
timePos(0.0f),
scale(1.0f, 1.0f, 1.0f)
{
}
aiMatrix4x4 TransformKeyFrame::Transform()
{
return aiMatrix4x4(scale, rotation, position);
}
} }
#endif