OgreImporter: Implement binary skeleton serialization. Fix bone/animation matrix stuff to be simpler (aka read as Quats to internal structures). Cleanup code for pull request.
parent
cf9b705829
commit
1129ae5a6e
|
@ -39,6 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "OgreBinarySerializer.h"
|
#include "OgreBinarySerializer.h"
|
||||||
|
#include "OgreXmlSerializer.h"
|
||||||
|
#include "OgreParsingUtils.h"
|
||||||
|
|
||||||
#include "TinyFormatter.h"
|
#include "TinyFormatter.h"
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
|
@ -51,9 +54,15 @@ namespace Assimp
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
|
|
||||||
const std::string VERSION_1_8 = "[MeshSerializer_v1.8]";
|
const std::string MESH_VERSION_1_8 = "[MeshSerializer_v1.8]";
|
||||||
const unsigned short HEADER_CHUNK_ID = 0x1000;
|
const std::string SKELETON_VERSION_1_8 = "[Serializer_v1.80]";
|
||||||
const long MSTREAM_OVERHEAD_SIZE = sizeof(uint16_t) + sizeof(uint32_t);
|
const std::string SKELETON_VERSION_1_1 = "[Serializer_v1.10]";
|
||||||
|
|
||||||
|
const unsigned short HEADER_CHUNK_ID = 0x1000;
|
||||||
|
|
||||||
|
const long MSTREAM_OVERHEAD_SIZE = sizeof(uint16_t) + sizeof(uint32_t);
|
||||||
|
const long MSTREAM_BONE_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + sizeof(unsigned short) + (sizeof(float) * 7);
|
||||||
|
const long MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + (sizeof(float) * 8);
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline bool OgreBinarySerializer::Read<bool>()
|
inline bool OgreBinarySerializer::Read<bool>()
|
||||||
|
@ -118,6 +127,16 @@ void OgreBinarySerializer::ReadVector(aiVector3D &vec)
|
||||||
m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3);
|
m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadQuaternion(aiQuaternion &quat)
|
||||||
|
{
|
||||||
|
float temp[4];
|
||||||
|
m_reader->CopyAndAdvance(temp, sizeof(float)*4);
|
||||||
|
quat.x = temp[0];
|
||||||
|
quat.y = temp[1];
|
||||||
|
quat.z = temp[2];
|
||||||
|
quat.w = temp[3];
|
||||||
|
}
|
||||||
|
|
||||||
bool OgreBinarySerializer::AtEnd() const
|
bool OgreBinarySerializer::AtEnd() const
|
||||||
{
|
{
|
||||||
return (m_reader->GetRemainingSize() == 0);
|
return (m_reader->GetRemainingSize() == 0);
|
||||||
|
@ -152,7 +171,10 @@ uint16_t OgreBinarySerializer::ReadHeader(bool readLen)
|
||||||
|
|
||||||
#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
|
#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
|
||||||
if (id != HEADER_CHUNK_ID)
|
if (id != HEADER_CHUNK_ID)
|
||||||
DefaultLogger::get()->debug(Formatter::format() << MeshHeaderToString(static_cast<MeshChunkId>(id)));
|
{
|
||||||
|
DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh
|
||||||
|
? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(id))));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -172,9 +194,11 @@ void OgreBinarySerializer::SkipBytes(size_t numBytes)
|
||||||
m_reader->IncPtr(numBytes);
|
m_reader->IncPtr(numBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mesh
|
||||||
|
|
||||||
Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
|
Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
|
||||||
{
|
{
|
||||||
OgreBinarySerializer serializer(stream);
|
OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh);
|
||||||
|
|
||||||
uint16_t id = serializer.ReadHeader(false);
|
uint16_t id = serializer.ReadHeader(false);
|
||||||
if (id != HEADER_CHUNK_ID) {
|
if (id != HEADER_CHUNK_ID) {
|
||||||
|
@ -183,8 +207,11 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
|
||||||
|
|
||||||
/// @todo Check what we can actually support.
|
/// @todo Check what we can actually support.
|
||||||
std::string version = serializer.ReadLine();
|
std::string version = serializer.ReadLine();
|
||||||
if (version != VERSION_1_8)
|
if (version != MESH_VERSION_1_8)
|
||||||
throw DeadlyExportError("Mesh version " + version + " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.");
|
{
|
||||||
|
throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again."
|
||||||
|
<< " Supported versions: " << MESH_VERSION_1_8);
|
||||||
|
}
|
||||||
|
|
||||||
Mesh *mesh = new Mesh();
|
Mesh *mesh = new Mesh();
|
||||||
while (!serializer.AtEnd())
|
while (!serializer.AtEnd())
|
||||||
|
@ -732,8 +759,7 @@ void OgreBinarySerializer::ReadAnimations(Mesh *mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreBinarySerializer::ReadAnimation(Animation *anim)
|
void OgreBinarySerializer::ReadAnimation(Animation *anim)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!AtEnd())
|
if (!AtEnd())
|
||||||
{
|
{
|
||||||
uint16_t id = ReadHeader();
|
uint16_t id = ReadHeader();
|
||||||
|
@ -821,6 +847,263 @@ void OgreBinarySerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimati
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skeleton
|
||||||
|
|
||||||
|
bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
|
||||||
|
{
|
||||||
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Highly unusual to see in read world cases but support
|
||||||
|
// binary mesh referencing a XML skeleton file.
|
||||||
|
if (EndsWith(mesh->skeletonRef, ".skeleton.xml", false))
|
||||||
|
{
|
||||||
|
OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||||
|
|
||||||
|
Skeleton *skeleton = new Skeleton();
|
||||||
|
OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
|
||||||
|
serializer.ReadSkeleton(skeleton);
|
||||||
|
mesh->skeleton = skeleton;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
|
||||||
|
{
|
||||||
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||||
|
if (!reader.get())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Skeleton *skeleton = new Skeleton();
|
||||||
|
OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
|
||||||
|
serializer.ReadSkeleton(skeleton);
|
||||||
|
mesh->skeleton = skeleton;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
|
||||||
|
{
|
||||||
|
if (!EndsWith(filename, ".skeleton", false))
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
|
||||||
|
return MemoryStreamReaderPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pIOHandler->Exists(filename))
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
|
||||||
|
return MemoryStreamReaderPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
IOStream *f = pIOHandler->Open(filename, "rb");
|
||||||
|
if (!f) {
|
||||||
|
throw DeadlyImportError("Failed to open skeleton file " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemoryStreamReaderPtr(new MemoryStreamReader(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton)
|
||||||
|
{
|
||||||
|
uint16_t id = ReadHeader(false);
|
||||||
|
if (id != HEADER_CHUNK_ID) {
|
||||||
|
throw DeadlyExportError("Invalid Ogre Skeleton file header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This deserialization supports both versions of the skeleton spec
|
||||||
|
std::string version = ReadLine();
|
||||||
|
if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1)
|
||||||
|
{
|
||||||
|
throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer."
|
||||||
|
<< " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultLogger::get()->debug("Reading Skeleton");
|
||||||
|
|
||||||
|
bool firstBone = true;
|
||||||
|
bool firstAnim = true;
|
||||||
|
|
||||||
|
while (!AtEnd())
|
||||||
|
{
|
||||||
|
id = ReadHeader();
|
||||||
|
switch(id)
|
||||||
|
{
|
||||||
|
case SKELETON_BLENDMODE:
|
||||||
|
{
|
||||||
|
skeleton->blendMode = static_cast<Skeleton::BlendMode>(Read<uint16_t>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SKELETON_BONE:
|
||||||
|
{
|
||||||
|
if (firstBone)
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->debug(" - Bones");
|
||||||
|
firstBone = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadBone(skeleton);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SKELETON_BONE_PARENT:
|
||||||
|
{
|
||||||
|
ReadBoneParent(skeleton);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SKELETON_ANIMATION:
|
||||||
|
{
|
||||||
|
if (firstAnim)
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->debug(" - Animations");
|
||||||
|
firstAnim = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadSkeletonAnimation(skeleton);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SKELETON_ANIMATION_LINK:
|
||||||
|
{
|
||||||
|
ReadSkeletonAnimationLink(skeleton);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate bone matrices for root bones. Recursively calculates their children.
|
||||||
|
for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
|
||||||
|
{
|
||||||
|
Bone *bone = skeleton->bones[i];
|
||||||
|
if (!bone->IsParented())
|
||||||
|
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadBone(Skeleton *skeleton)
|
||||||
|
{
|
||||||
|
Bone *bone = new Bone();
|
||||||
|
bone->name = ReadLine();
|
||||||
|
bone->id = Read<uint16_t>();
|
||||||
|
|
||||||
|
// Pos and rot
|
||||||
|
ReadVector(bone->position);
|
||||||
|
ReadQuaternion(bone->rotation);
|
||||||
|
|
||||||
|
// Scale (optional)
|
||||||
|
if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE)
|
||||||
|
ReadVector(bone->scale);
|
||||||
|
|
||||||
|
// Bone indexes need to start from 0 and be contiguous
|
||||||
|
if (bone->id != skeleton->bones.size()) {
|
||||||
|
throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultLogger::get()->debug(Formatter::format() << " " << bone->id << " " << bone->name);
|
||||||
|
|
||||||
|
skeleton->bones.push_back(bone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton)
|
||||||
|
{
|
||||||
|
uint16_t childId = Read<uint16_t>();
|
||||||
|
uint16_t parentId = Read<uint16_t>();
|
||||||
|
|
||||||
|
Bone *child = skeleton->BoneById(childId);
|
||||||
|
Bone *parent = skeleton->BoneById(parentId);
|
||||||
|
|
||||||
|
if (child && parent)
|
||||||
|
parent->AddChild(child);
|
||||||
|
else
|
||||||
|
throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton)
|
||||||
|
{
|
||||||
|
Animation *anim = new Animation(skeleton);
|
||||||
|
anim->name = ReadLine();
|
||||||
|
anim->length = Read<float>();
|
||||||
|
|
||||||
|
if (!AtEnd())
|
||||||
|
{
|
||||||
|
uint16_t id = ReadHeader();
|
||||||
|
if (id == SKELETON_ANIMATION_BASEINFO)
|
||||||
|
{
|
||||||
|
anim->baseName = ReadLine();
|
||||||
|
anim->baseTime = Read<float>();
|
||||||
|
|
||||||
|
// Advance to first track
|
||||||
|
id = ReadHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!AtEnd() && id == SKELETON_ANIMATION_TRACK)
|
||||||
|
{
|
||||||
|
ReadSkeletonAnimationTrack(skeleton, anim);
|
||||||
|
|
||||||
|
if (!AtEnd())
|
||||||
|
id = ReadHeader();
|
||||||
|
}
|
||||||
|
if (!AtEnd())
|
||||||
|
RollbackHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton->animations.push_back(anim);
|
||||||
|
|
||||||
|
DefaultLogger::get()->debug(Formatter::format() << " " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest)
|
||||||
|
{
|
||||||
|
uint16_t boneId = Read<uint16_t>();
|
||||||
|
Bone *bone = dest->parentSkeleton->BoneById(boneId);
|
||||||
|
if (!bone) {
|
||||||
|
throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton");
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexAnimationTrack track;
|
||||||
|
track.type = VertexAnimationTrack::VAT_TRANSFORM;
|
||||||
|
track.boneName = bone->name;
|
||||||
|
|
||||||
|
uint16_t id = ReadHeader();
|
||||||
|
while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME)
|
||||||
|
{
|
||||||
|
ReadSkeletonAnimationKeyFrame(&track);
|
||||||
|
|
||||||
|
if (!AtEnd())
|
||||||
|
id = ReadHeader();
|
||||||
|
}
|
||||||
|
if (!AtEnd())
|
||||||
|
RollbackHeader();
|
||||||
|
|
||||||
|
dest->tracks.push_back(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest)
|
||||||
|
{
|
||||||
|
TransformKeyFrame keyframe;
|
||||||
|
keyframe.timePos = Read<float>();
|
||||||
|
|
||||||
|
// Rot and pos
|
||||||
|
ReadQuaternion(keyframe.rotation);
|
||||||
|
ReadVector(keyframe.position);
|
||||||
|
|
||||||
|
// Scale (optional)
|
||||||
|
if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE)
|
||||||
|
ReadVector(keyframe.scale);
|
||||||
|
|
||||||
|
dest->transformKeyFrames.push_back(keyframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton *skeleton)
|
||||||
|
{
|
||||||
|
// Skip bounds, not compatible with Assimp.
|
||||||
|
ReadLine(); // skeleton name
|
||||||
|
SkipBytes(sizeof(float) * 3); // scale
|
||||||
|
}
|
||||||
|
|
||||||
} // Ogre
|
} // Ogre
|
||||||
} // Assimp
|
} // Assimp
|
||||||
|
|
||||||
|
|
|
@ -49,263 +49,365 @@ namespace Assimp
|
||||||
{
|
{
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
class OgreBinarySerializer
|
|
||||||
|
typedef Assimp::StreamReaderLE MemoryStreamReader;
|
||||||
|
typedef boost::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr;
|
||||||
|
|
||||||
|
class OgreBinarySerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Imports mesh and returns the result.
|
||||||
|
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
||||||
|
static Mesh *ImportMesh(MemoryStreamReader *reader);
|
||||||
|
|
||||||
|
/// Imports skeleton to @c mesh into Mesh::skeleton.
|
||||||
|
/** If mesh does not have a skeleton reference or the skeleton file
|
||||||
|
cannot be found it is not a fatal DeadlyImportError. */
|
||||||
|
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||||
|
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum AssetMode
|
||||||
{
|
{
|
||||||
public:
|
AM_Mesh,
|
||||||
static Mesh *ImportMesh(MemoryStreamReader *reader);
|
AM_Skeleton
|
||||||
|
|
||||||
private:
|
|
||||||
OgreBinarySerializer(MemoryStreamReader *reader) :
|
|
||||||
m_reader(reader),
|
|
||||||
m_currentLen(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AtEnd() const;
|
|
||||||
|
|
||||||
void ReadMesh(Mesh *mesh);
|
|
||||||
void ReadMeshLodInfo(Mesh *mesh);
|
|
||||||
void ReadMeshSkeletonLink(Mesh *mesh);
|
|
||||||
void ReadMeshBounds(Mesh *mesh);
|
|
||||||
void ReadMeshExtremes(Mesh *mesh);
|
|
||||||
|
|
||||||
void ReadSubMesh(Mesh *mesh);
|
|
||||||
void ReadSubMeshNames(Mesh *mesh);
|
|
||||||
void ReadSubMeshOperation(SubMesh *submesh);
|
|
||||||
void ReadSubMeshTextureAlias(SubMesh *submesh);
|
|
||||||
|
|
||||||
void ReadBoneAssignment(VertexData *dest);
|
|
||||||
|
|
||||||
void ReadGeometry(VertexData *dest);
|
|
||||||
void ReadGeometryVertexDeclaration(VertexData *dest);
|
|
||||||
void ReadGeometryVertexElement(VertexData *dest);
|
|
||||||
void ReadGeometryVertexBuffer(VertexData *dest);
|
|
||||||
|
|
||||||
void ReadEdgeList(Mesh *mesh);
|
|
||||||
void ReadPoses(Mesh *mesh);
|
|
||||||
void ReadPoseVertices(Pose *pose);
|
|
||||||
|
|
||||||
void ReadAnimations(Mesh *mesh);
|
|
||||||
void ReadAnimation(Animation *anim);
|
|
||||||
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track);
|
|
||||||
|
|
||||||
void NormalizeBoneWeights(VertexData *vertexData) const;
|
|
||||||
|
|
||||||
uint16_t ReadHeader(bool readLen = true);
|
|
||||||
void RollbackHeader();
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T Read();
|
|
||||||
|
|
||||||
void ReadBytes(char *dest, size_t numBytes);
|
|
||||||
void ReadBytes(uint8_t *dest, size_t numBytes);
|
|
||||||
void ReadBytes(void *dest, size_t numBytes);
|
|
||||||
uint8_t *ReadBytes(size_t numBytes);
|
|
||||||
|
|
||||||
void ReadVector(aiVector3D &vec);
|
|
||||||
|
|
||||||
std::string ReadString(size_t len);
|
|
||||||
std::string ReadLine();
|
|
||||||
|
|
||||||
void SkipBytes(size_t numBytes);
|
|
||||||
|
|
||||||
uint32_t m_currentLen;
|
|
||||||
MemoryStreamReader *m_reader;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MeshChunkId
|
OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
|
||||||
|
m_reader(reader),
|
||||||
|
m_currentLen(0),
|
||||||
|
assetMode(mode)
|
||||||
{
|
{
|
||||||
M_HEADER = 0x1000,
|
}
|
||||||
// char* version : Version number check
|
|
||||||
M_MESH = 0x3000,
|
static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||||
// bool skeletallyAnimated // important flag which affects h/w buffer policies
|
|
||||||
// Optional M_GEOMETRY chunk
|
|
||||||
M_SUBMESH = 0x4000,
|
|
||||||
// char* materialName
|
|
||||||
// bool useSharedVertices
|
|
||||||
// unsigned int indexCount
|
|
||||||
// bool indexes32Bit
|
|
||||||
// unsigned int* faceVertexIndices (indexCount)
|
|
||||||
// OR
|
|
||||||
// unsigned short* faceVertexIndices (indexCount)
|
|
||||||
// M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
|
|
||||||
M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
|
|
||||||
// unsigned short operationType
|
|
||||||
M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
|
|
||||||
// Optional bone weights (repeating section)
|
|
||||||
// unsigned int vertexIndex;
|
|
||||||
// unsigned short boneIndex;
|
|
||||||
// float weight;
|
|
||||||
// Optional chunk that matches a texture name to an alias
|
|
||||||
// a texture alias is sent to the submesh material to use this texture name
|
|
||||||
// instead of the one in the texture unit with a matching alias name
|
|
||||||
M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
|
|
||||||
// char* aliasName;
|
|
||||||
// char* textureName;
|
|
||||||
|
|
||||||
M_GEOMETRY = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
|
// Header
|
||||||
// unsigned int vertexCount
|
|
||||||
M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
|
uint16_t ReadHeader(bool readLen = true);
|
||||||
M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
|
void RollbackHeader();
|
||||||
// unsigned short source; // buffer bind source
|
|
||||||
// unsigned short type; // VertexElementType
|
// Mesh
|
||||||
// unsigned short semantic; // VertexElementSemantic
|
|
||||||
// unsigned short offset; // start offset in buffer in bytes
|
void ReadMesh(Mesh *mesh);
|
||||||
// unsigned short index; // index of the semantic (for colours and texture coords)
|
void ReadMeshLodInfo(Mesh *mesh);
|
||||||
M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
|
void ReadMeshSkeletonLink(Mesh *mesh);
|
||||||
// unsigned short bindIndex; // Index to bind this buffer to
|
void ReadMeshBounds(Mesh *mesh);
|
||||||
// unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
|
void ReadMeshExtremes(Mesh *mesh);
|
||||||
M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
|
|
||||||
// raw buffer data
|
void ReadSubMesh(Mesh *mesh);
|
||||||
M_MESH_SKELETON_LINK = 0x6000,
|
void ReadSubMeshNames(Mesh *mesh);
|
||||||
// Optional link to skeleton
|
void ReadSubMeshOperation(SubMesh *submesh);
|
||||||
// char* skeletonName : name of .skeleton to use
|
void ReadSubMeshTextureAlias(SubMesh *submesh);
|
||||||
M_MESH_BONE_ASSIGNMENT = 0x7000,
|
|
||||||
|
void ReadBoneAssignment(VertexData *dest);
|
||||||
|
|
||||||
|
void ReadGeometry(VertexData *dest);
|
||||||
|
void ReadGeometryVertexDeclaration(VertexData *dest);
|
||||||
|
void ReadGeometryVertexElement(VertexData *dest);
|
||||||
|
void ReadGeometryVertexBuffer(VertexData *dest);
|
||||||
|
|
||||||
|
void ReadEdgeList(Mesh *mesh);
|
||||||
|
void ReadPoses(Mesh *mesh);
|
||||||
|
void ReadPoseVertices(Pose *pose);
|
||||||
|
|
||||||
|
void ReadAnimations(Mesh *mesh);
|
||||||
|
void ReadAnimation(Animation *anim);
|
||||||
|
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track);
|
||||||
|
|
||||||
|
void NormalizeBoneWeights(VertexData *vertexData) const;
|
||||||
|
|
||||||
|
// Skeleton
|
||||||
|
|
||||||
|
void ReadSkeleton(Skeleton *skeleton);
|
||||||
|
|
||||||
|
void ReadBone(Skeleton *skeleton);
|
||||||
|
void ReadBoneParent(Skeleton *skeleton);
|
||||||
|
|
||||||
|
void ReadSkeletonAnimation(Skeleton *skeleton);
|
||||||
|
void ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest);
|
||||||
|
void ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest);
|
||||||
|
void ReadSkeletonAnimationLink(Skeleton *skeleton);
|
||||||
|
|
||||||
|
// Reader utils
|
||||||
|
bool AtEnd() const;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T Read();
|
||||||
|
|
||||||
|
void ReadBytes(char *dest, size_t numBytes);
|
||||||
|
void ReadBytes(uint8_t *dest, size_t numBytes);
|
||||||
|
void ReadBytes(void *dest, size_t numBytes);
|
||||||
|
uint8_t *ReadBytes(size_t numBytes);
|
||||||
|
|
||||||
|
void ReadVector(aiVector3D &vec);
|
||||||
|
void ReadQuaternion(aiQuaternion &quat);
|
||||||
|
|
||||||
|
std::string ReadString(size_t len);
|
||||||
|
std::string ReadLine();
|
||||||
|
|
||||||
|
void SkipBytes(size_t numBytes);
|
||||||
|
|
||||||
|
uint32_t m_currentLen;
|
||||||
|
MemoryStreamReader *m_reader;
|
||||||
|
|
||||||
|
AssetMode assetMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MeshChunkId
|
||||||
|
{
|
||||||
|
M_HEADER = 0x1000,
|
||||||
|
// char* version : Version number check
|
||||||
|
M_MESH = 0x3000,
|
||||||
|
// bool skeletallyAnimated // important flag which affects h/w buffer policies
|
||||||
|
// Optional M_GEOMETRY chunk
|
||||||
|
M_SUBMESH = 0x4000,
|
||||||
|
// char* materialName
|
||||||
|
// bool useSharedVertices
|
||||||
|
// unsigned int indexCount
|
||||||
|
// bool indexes32Bit
|
||||||
|
// unsigned int* faceVertexIndices (indexCount)
|
||||||
|
// OR
|
||||||
|
// unsigned short* faceVertexIndices (indexCount)
|
||||||
|
// M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
|
||||||
|
M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
|
||||||
|
// unsigned short operationType
|
||||||
|
M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
|
||||||
// Optional bone weights (repeating section)
|
// Optional bone weights (repeating section)
|
||||||
// unsigned int vertexIndex;
|
// unsigned int vertexIndex;
|
||||||
// unsigned short boneIndex;
|
// unsigned short boneIndex;
|
||||||
// float weight;
|
// float weight;
|
||||||
M_MESH_LOD = 0x8000,
|
// Optional chunk that matches a texture name to an alias
|
||||||
// Optional LOD information
|
// a texture alias is sent to the submesh material to use this texture name
|
||||||
// string strategyName;
|
// instead of the one in the texture unit with a matching alias name
|
||||||
// unsigned short numLevels;
|
M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
|
||||||
// bool manual; (true for manual alternate meshes, false for generated)
|
// char* aliasName;
|
||||||
M_MESH_LOD_USAGE = 0x8100,
|
// char* textureName;
|
||||||
// Repeating section, ordered in increasing depth
|
|
||||||
// NB LOD 0 (full detail from 0 depth) is omitted
|
|
||||||
// LOD value - this is a distance, a pixel count etc, based on strategy
|
|
||||||
// float lodValue;
|
|
||||||
M_MESH_LOD_MANUAL = 0x8110,
|
|
||||||
// Required if M_MESH_LOD section manual = true
|
|
||||||
// String manualMeshName;
|
|
||||||
M_MESH_LOD_GENERATED = 0x8120,
|
|
||||||
// Required if M_MESH_LOD section manual = false
|
|
||||||
// Repeating section (1 per submesh)
|
|
||||||
// unsigned int indexCount;
|
|
||||||
// bool indexes32Bit
|
|
||||||
// unsigned short* faceIndexes; (indexCount)
|
|
||||||
// OR
|
|
||||||
// unsigned int* faceIndexes; (indexCount)
|
|
||||||
M_MESH_BOUNDS = 0x9000,
|
|
||||||
// float minx, miny, minz
|
|
||||||
// float maxx, maxy, maxz
|
|
||||||
// float radius
|
|
||||||
|
|
||||||
// Added By DrEvil
|
|
||||||
// optional chunk that contains a table of submesh indexes and the names of
|
|
||||||
// the sub-meshes.
|
|
||||||
M_SUBMESH_NAME_TABLE = 0xA000,
|
|
||||||
// Subchunks of the name table. Each chunk contains an index & string
|
|
||||||
M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
|
|
||||||
// short index
|
|
||||||
// char* name
|
|
||||||
// Optional chunk which stores precomputed edge data
|
|
||||||
M_EDGE_LISTS = 0xB000,
|
|
||||||
// Each LOD has a separate edge list
|
|
||||||
M_EDGE_LIST_LOD = 0xB100,
|
|
||||||
// unsigned short lodIndex
|
|
||||||
// bool isManual // If manual, no edge data here, loaded from manual mesh
|
|
||||||
// bool isClosed
|
|
||||||
// unsigned long numTriangles
|
|
||||||
// unsigned long numEdgeGroups
|
|
||||||
// Triangle* triangleList
|
|
||||||
// unsigned long indexSet
|
|
||||||
// unsigned long vertexSet
|
|
||||||
// unsigned long vertIndex[3]
|
|
||||||
// unsigned long sharedVertIndex[3]
|
|
||||||
// float normal[4]
|
|
||||||
|
|
||||||
M_EDGE_GROUP = 0xB110,
|
M_GEOMETRY = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
|
||||||
// unsigned long vertexSet
|
// unsigned int vertexCount
|
||||||
// unsigned long triStart
|
M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
|
||||||
// unsigned long triCount
|
M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
|
||||||
// unsigned long numEdges
|
// unsigned short source; // buffer bind source
|
||||||
// Edge* edgeList
|
// unsigned short type; // VertexElementType
|
||||||
// unsigned long triIndex[2]
|
// unsigned short semantic; // VertexElementSemantic
|
||||||
// unsigned long vertIndex[2]
|
// unsigned short offset; // start offset in buffer in bytes
|
||||||
// unsigned long sharedVertIndex[2]
|
// unsigned short index; // index of the semantic (for colours and texture coords)
|
||||||
// bool degenerate
|
M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
|
||||||
// Optional poses section, referred to by pose keyframes
|
// unsigned short bindIndex; // Index to bind this buffer to
|
||||||
M_POSES = 0xC000,
|
// unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
|
||||||
M_POSE = 0xC100,
|
M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
|
||||||
// char* name (may be blank)
|
// raw buffer data
|
||||||
// unsigned short target // 0 for shared geometry,
|
M_MESH_SKELETON_LINK = 0x6000,
|
||||||
// 1+ for submesh index + 1
|
// Optional link to skeleton
|
||||||
// bool includesNormals [1.8+]
|
// char* skeletonName : name of .skeleton to use
|
||||||
M_POSE_VERTEX = 0xC111,
|
M_MESH_BONE_ASSIGNMENT = 0x7000,
|
||||||
// unsigned long vertexIndex
|
// Optional bone weights (repeating section)
|
||||||
// float xoffset, yoffset, zoffset
|
// unsigned int vertexIndex;
|
||||||
// float xnormal, ynormal, znormal (optional, 1.8+)
|
// unsigned short boneIndex;
|
||||||
// Optional vertex animation chunk
|
// float weight;
|
||||||
M_ANIMATIONS = 0xD000,
|
M_MESH_LOD = 0x8000,
|
||||||
M_ANIMATION = 0xD100,
|
// Optional LOD information
|
||||||
|
// string strategyName;
|
||||||
|
// unsigned short numLevels;
|
||||||
|
// bool manual; (true for manual alternate meshes, false for generated)
|
||||||
|
M_MESH_LOD_USAGE = 0x8100,
|
||||||
|
// Repeating section, ordered in increasing depth
|
||||||
|
// NB LOD 0 (full detail from 0 depth) is omitted
|
||||||
|
// LOD value - this is a distance, a pixel count etc, based on strategy
|
||||||
|
// float lodValue;
|
||||||
|
M_MESH_LOD_MANUAL = 0x8110,
|
||||||
|
// Required if M_MESH_LOD section manual = true
|
||||||
|
// String manualMeshName;
|
||||||
|
M_MESH_LOD_GENERATED = 0x8120,
|
||||||
|
// Required if M_MESH_LOD section manual = false
|
||||||
|
// Repeating section (1 per submesh)
|
||||||
|
// unsigned int indexCount;
|
||||||
|
// bool indexes32Bit
|
||||||
|
// unsigned short* faceIndexes; (indexCount)
|
||||||
|
// OR
|
||||||
|
// unsigned int* faceIndexes; (indexCount)
|
||||||
|
M_MESH_BOUNDS = 0x9000,
|
||||||
|
// float minx, miny, minz
|
||||||
|
// float maxx, maxy, maxz
|
||||||
|
// float radius
|
||||||
|
|
||||||
|
// Added By DrEvil
|
||||||
|
// optional chunk that contains a table of submesh indexes and the names of
|
||||||
|
// the sub-meshes.
|
||||||
|
M_SUBMESH_NAME_TABLE = 0xA000,
|
||||||
|
// Subchunks of the name table. Each chunk contains an index & string
|
||||||
|
M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
|
||||||
|
// short index
|
||||||
// char* name
|
// char* name
|
||||||
// float length
|
// Optional chunk which stores precomputed edge data
|
||||||
M_ANIMATION_BASEINFO = 0xD105,
|
M_EDGE_LISTS = 0xB000,
|
||||||
// [Optional] base keyframe information (pose animation only)
|
// Each LOD has a separate edge list
|
||||||
// char* baseAnimationName (blank for self)
|
M_EDGE_LIST_LOD = 0xB100,
|
||||||
// float baseKeyFrameTime
|
// unsigned short lodIndex
|
||||||
M_ANIMATION_TRACK = 0xD110,
|
// bool isManual // If manual, no edge data here, loaded from manual mesh
|
||||||
// unsigned short type // 1 == morph, 2 == pose
|
// bool isClosed
|
||||||
// unsigned short target // 0 for shared geometry,
|
// unsigned long numTriangles
|
||||||
// 1+ for submesh index + 1
|
// unsigned long numEdgeGroups
|
||||||
M_ANIMATION_MORPH_KEYFRAME = 0xD111,
|
// Triangle* triangleList
|
||||||
// float time
|
// unsigned long indexSet
|
||||||
// bool includesNormals [1.8+]
|
// unsigned long vertexSet
|
||||||
// float x,y,z // repeat by number of vertices in original geometry
|
// unsigned long vertIndex[3]
|
||||||
M_ANIMATION_POSE_KEYFRAME = 0xD112,
|
// unsigned long sharedVertIndex[3]
|
||||||
// float time
|
// float normal[4]
|
||||||
M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
|
|
||||||
// unsigned short poseIndex
|
|
||||||
// float influence
|
|
||||||
// Optional submesh extreme vertex list chink
|
|
||||||
M_TABLE_EXTREMES = 0xE000,
|
|
||||||
// unsigned short submesh_index;
|
|
||||||
// float extremes [n_extremes][3];
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::string MeshHeaderToString(MeshChunkId id)
|
|
||||||
{
|
|
||||||
switch(id)
|
|
||||||
{
|
|
||||||
case M_HEADER: return "HEADER";
|
|
||||||
case M_MESH: return "MESH";
|
|
||||||
case M_SUBMESH: return "SUBMESH";
|
|
||||||
case M_SUBMESH_OPERATION: return "SUBMESH_OPERATION";
|
|
||||||
case M_SUBMESH_BONE_ASSIGNMENT: return "SUBMESH_BONE_ASSIGNMENT";
|
|
||||||
case M_SUBMESH_TEXTURE_ALIAS: return "SUBMESH_TEXTURE_ALIAS";
|
|
||||||
case M_GEOMETRY: return "GEOMETRY";
|
|
||||||
case M_GEOMETRY_VERTEX_DECLARATION: return "GEOMETRY_VERTEX_DECLARATION";
|
|
||||||
case M_GEOMETRY_VERTEX_ELEMENT: return "GEOMETRY_VERTEX_ELEMENT";
|
|
||||||
case M_GEOMETRY_VERTEX_BUFFER: return "GEOMETRY_VERTEX_BUFFER";
|
|
||||||
case M_GEOMETRY_VERTEX_BUFFER_DATA: return "GEOMETRY_VERTEX_BUFFER_DATA";
|
|
||||||
case M_MESH_SKELETON_LINK: return "MESH_SKELETON_LINK";
|
|
||||||
case M_MESH_BONE_ASSIGNMENT: return "MESH_BONE_ASSIGNMENT";
|
|
||||||
case M_MESH_LOD: return "MESH_LOD";
|
|
||||||
case M_MESH_LOD_USAGE: return "MESH_LOD_USAGE";
|
|
||||||
case M_MESH_LOD_MANUAL: return "MESH_LOD_MANUAL";
|
|
||||||
case M_MESH_LOD_GENERATED: return "MESH_LOD_GENERATED";
|
|
||||||
case M_MESH_BOUNDS: return "MESH_BOUNDS";
|
|
||||||
case M_SUBMESH_NAME_TABLE: return "SUBMESH_NAME_TABLE";
|
|
||||||
case M_SUBMESH_NAME_TABLE_ELEMENT: return "SUBMESH_NAME_TABLE_ELEMENT";
|
|
||||||
case M_EDGE_LISTS: return "EDGE_LISTS";
|
|
||||||
case M_EDGE_LIST_LOD: return "EDGE_LIST_LOD";
|
|
||||||
case M_EDGE_GROUP: return "EDGE_GROUP";
|
|
||||||
case M_POSES: return "POSES";
|
|
||||||
case M_POSE: return "POSE";
|
|
||||||
case M_POSE_VERTEX: return "POSE_VERTEX";
|
|
||||||
case M_ANIMATIONS: return "ANIMATIONS";
|
|
||||||
case M_ANIMATION: return "ANIMATION";
|
|
||||||
case M_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
|
||||||
case M_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
|
||||||
case M_ANIMATION_MORPH_KEYFRAME: return "ANIMATION_MORPH_KEYFRAME";
|
|
||||||
case M_ANIMATION_POSE_KEYFRAME: return "ANIMATION_POSE_KEYFRAME";
|
|
||||||
case M_ANIMATION_POSE_REF: return "ANIMATION_POSE_REF";
|
|
||||||
case M_TABLE_EXTREMES: return "TABLE_EXTREMES";
|
|
||||||
}
|
|
||||||
return "Uknown_MeshChunkId";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
M_EDGE_GROUP = 0xB110,
|
||||||
|
// unsigned long vertexSet
|
||||||
|
// unsigned long triStart
|
||||||
|
// unsigned long triCount
|
||||||
|
// unsigned long numEdges
|
||||||
|
// Edge* edgeList
|
||||||
|
// unsigned long triIndex[2]
|
||||||
|
// unsigned long vertIndex[2]
|
||||||
|
// unsigned long sharedVertIndex[2]
|
||||||
|
// bool degenerate
|
||||||
|
// Optional poses section, referred to by pose keyframes
|
||||||
|
M_POSES = 0xC000,
|
||||||
|
M_POSE = 0xC100,
|
||||||
|
// char* name (may be blank)
|
||||||
|
// unsigned short target // 0 for shared geometry,
|
||||||
|
// 1+ for submesh index + 1
|
||||||
|
// bool includesNormals [1.8+]
|
||||||
|
M_POSE_VERTEX = 0xC111,
|
||||||
|
// unsigned long vertexIndex
|
||||||
|
// float xoffset, yoffset, zoffset
|
||||||
|
// float xnormal, ynormal, znormal (optional, 1.8+)
|
||||||
|
// Optional vertex animation chunk
|
||||||
|
M_ANIMATIONS = 0xD000,
|
||||||
|
M_ANIMATION = 0xD100,
|
||||||
|
// char* name
|
||||||
|
// float length
|
||||||
|
M_ANIMATION_BASEINFO = 0xD105,
|
||||||
|
// [Optional] base keyframe information (pose animation only)
|
||||||
|
// char* baseAnimationName (blank for self)
|
||||||
|
// float baseKeyFrameTime
|
||||||
|
M_ANIMATION_TRACK = 0xD110,
|
||||||
|
// unsigned short type // 1 == morph, 2 == pose
|
||||||
|
// unsigned short target // 0 for shared geometry,
|
||||||
|
// 1+ for submesh index + 1
|
||||||
|
M_ANIMATION_MORPH_KEYFRAME = 0xD111,
|
||||||
|
// float time
|
||||||
|
// bool includesNormals [1.8+]
|
||||||
|
// float x,y,z // repeat by number of vertices in original geometry
|
||||||
|
M_ANIMATION_POSE_KEYFRAME = 0xD112,
|
||||||
|
// float time
|
||||||
|
M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
|
||||||
|
// unsigned short poseIndex
|
||||||
|
// float influence
|
||||||
|
// Optional submesh extreme vertex list chink
|
||||||
|
M_TABLE_EXTREMES = 0xE000,
|
||||||
|
// unsigned short submesh_index;
|
||||||
|
// float extremes [n_extremes][3];
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string MeshHeaderToString(MeshChunkId id)
|
||||||
|
{
|
||||||
|
switch(id)
|
||||||
|
{
|
||||||
|
case M_HEADER: return "HEADER";
|
||||||
|
case M_MESH: return "MESH";
|
||||||
|
case M_SUBMESH: return "SUBMESH";
|
||||||
|
case M_SUBMESH_OPERATION: return "SUBMESH_OPERATION";
|
||||||
|
case M_SUBMESH_BONE_ASSIGNMENT: return "SUBMESH_BONE_ASSIGNMENT";
|
||||||
|
case M_SUBMESH_TEXTURE_ALIAS: return "SUBMESH_TEXTURE_ALIAS";
|
||||||
|
case M_GEOMETRY: return "GEOMETRY";
|
||||||
|
case M_GEOMETRY_VERTEX_DECLARATION: return "GEOMETRY_VERTEX_DECLARATION";
|
||||||
|
case M_GEOMETRY_VERTEX_ELEMENT: return "GEOMETRY_VERTEX_ELEMENT";
|
||||||
|
case M_GEOMETRY_VERTEX_BUFFER: return "GEOMETRY_VERTEX_BUFFER";
|
||||||
|
case M_GEOMETRY_VERTEX_BUFFER_DATA: return "GEOMETRY_VERTEX_BUFFER_DATA";
|
||||||
|
case M_MESH_SKELETON_LINK: return "MESH_SKELETON_LINK";
|
||||||
|
case M_MESH_BONE_ASSIGNMENT: return "MESH_BONE_ASSIGNMENT";
|
||||||
|
case M_MESH_LOD: return "MESH_LOD";
|
||||||
|
case M_MESH_LOD_USAGE: return "MESH_LOD_USAGE";
|
||||||
|
case M_MESH_LOD_MANUAL: return "MESH_LOD_MANUAL";
|
||||||
|
case M_MESH_LOD_GENERATED: return "MESH_LOD_GENERATED";
|
||||||
|
case M_MESH_BOUNDS: return "MESH_BOUNDS";
|
||||||
|
case M_SUBMESH_NAME_TABLE: return "SUBMESH_NAME_TABLE";
|
||||||
|
case M_SUBMESH_NAME_TABLE_ELEMENT: return "SUBMESH_NAME_TABLE_ELEMENT";
|
||||||
|
case M_EDGE_LISTS: return "EDGE_LISTS";
|
||||||
|
case M_EDGE_LIST_LOD: return "EDGE_LIST_LOD";
|
||||||
|
case M_EDGE_GROUP: return "EDGE_GROUP";
|
||||||
|
case M_POSES: return "POSES";
|
||||||
|
case M_POSE: return "POSE";
|
||||||
|
case M_POSE_VERTEX: return "POSE_VERTEX";
|
||||||
|
case M_ANIMATIONS: return "ANIMATIONS";
|
||||||
|
case M_ANIMATION: return "ANIMATION";
|
||||||
|
case M_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||||
|
case M_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||||
|
case M_ANIMATION_MORPH_KEYFRAME: return "ANIMATION_MORPH_KEYFRAME";
|
||||||
|
case M_ANIMATION_POSE_KEYFRAME: return "ANIMATION_POSE_KEYFRAME";
|
||||||
|
case M_ANIMATION_POSE_REF: return "ANIMATION_POSE_REF";
|
||||||
|
case M_TABLE_EXTREMES: return "TABLE_EXTREMES";
|
||||||
|
}
|
||||||
|
return "Unknown_MeshChunkId";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SkeletonChunkId
|
||||||
|
{
|
||||||
|
SKELETON_HEADER = 0x1000,
|
||||||
|
// char* version : Version number check
|
||||||
|
SKELETON_BLENDMODE = 0x1010, // optional
|
||||||
|
// unsigned short blendmode : SkeletonAnimationBlendMode
|
||||||
|
SKELETON_BONE = 0x2000,
|
||||||
|
// Repeating section defining each bone in the system.
|
||||||
|
// Bones are assigned indexes automatically based on their order of declaration
|
||||||
|
// starting with 0.
|
||||||
|
// char* name : name of the bone
|
||||||
|
// unsigned short handle : handle of the bone, should be contiguous & start at 0
|
||||||
|
// Vector3 position : position of this bone relative to parent
|
||||||
|
// Quaternion orientation : orientation of this bone relative to parent
|
||||||
|
// Vector3 scale : scale of this bone relative to parent
|
||||||
|
SKELETON_BONE_PARENT = 0x3000,
|
||||||
|
// Record of the parent of a single bone, used to build the node tree
|
||||||
|
// Repeating section, listed in Bone Index order, one per Bone
|
||||||
|
// unsigned short handle : child bone
|
||||||
|
// unsigned short parentHandle : parent bone
|
||||||
|
SKELETON_ANIMATION = 0x4000,
|
||||||
|
// A single animation for this skeleton
|
||||||
|
// char* name : Name of the animation
|
||||||
|
// float length : Length of the animation in seconds
|
||||||
|
SKELETON_ANIMATION_BASEINFO = 0x4010,
|
||||||
|
// [Optional] base keyframe information
|
||||||
|
// char* baseAnimationName (blank for self)
|
||||||
|
// float baseKeyFrameTime
|
||||||
|
SKELETON_ANIMATION_TRACK = 0x4100,
|
||||||
|
// A single animation track (relates to a single bone)
|
||||||
|
// Repeating section (within SKELETON_ANIMATION)
|
||||||
|
// unsigned short boneIndex : Index of bone to apply to
|
||||||
|
SKELETON_ANIMATION_TRACK_KEYFRAME = 0x4110,
|
||||||
|
// A single keyframe within the track
|
||||||
|
// Repeating section
|
||||||
|
// float time : The time position (seconds)
|
||||||
|
// Quaternion rotate : Rotation to apply at this keyframe
|
||||||
|
// Vector3 translate : Translation to apply at this keyframe
|
||||||
|
// Vector3 scale : Scale to apply at this keyframe
|
||||||
|
SKELETON_ANIMATION_LINK = 0x5000
|
||||||
|
// Link to another skeleton, to re-use its animations
|
||||||
|
// char* skeletonName : name of skeleton to get animations from
|
||||||
|
// float scale : scale to apply to trans/scale keys
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string SkeletonHeaderToString(SkeletonChunkId id)
|
||||||
|
{
|
||||||
|
switch(id)
|
||||||
|
{
|
||||||
|
case SKELETON_HEADER: return "HEADER";
|
||||||
|
case SKELETON_BLENDMODE: return "BLENDMODE";
|
||||||
|
case SKELETON_BONE: return "BONE";
|
||||||
|
case SKELETON_BONE_PARENT: return "BONE_PARENT";
|
||||||
|
case SKELETON_ANIMATION: return "ANIMATION";
|
||||||
|
case SKELETON_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||||
|
case SKELETON_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||||
|
case SKELETON_ANIMATION_TRACK_KEYFRAME: return "ANIMATION_TRACK_KEYFRAME";
|
||||||
|
case SKELETON_ANIMATION_LINK: return "ANIMATION_LINK";
|
||||||
|
}
|
||||||
|
return "Unknown_SkeletonChunkId";
|
||||||
|
}
|
||||||
} // Ogre
|
} // Ogre
|
||||||
} // Assimp
|
} // Assimp
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,9 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
|
||||||
// Import mesh
|
// Import mesh
|
||||||
boost::scoped_ptr<Mesh> mesh = OgreBinarySerializer::ImportMesh(&reader);
|
boost::scoped_ptr<Mesh> mesh = OgreBinarySerializer::ImportMesh(&reader);
|
||||||
|
|
||||||
|
// Import skeleton
|
||||||
|
OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh);
|
||||||
|
|
||||||
// Import mesh referenced materials
|
// Import mesh referenced materials
|
||||||
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
||||||
|
|
||||||
|
|
|
@ -459,6 +459,35 @@ void Mesh::ConvertToAssimpScene(aiScene* dest)
|
||||||
dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
|
dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
|
||||||
dest->mRootNode->mMeshes[i] = i;
|
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
|
||||||
|
@ -652,7 +681,7 @@ aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bones and bone weights
|
// Bones and bone weights
|
||||||
if (parent->skeleton && boneAssignments)
|
if (parent->skeleton && boneAssignments)
|
||||||
{
|
{
|
||||||
|
@ -926,7 +955,8 @@ aiAnimation *Animation::ConvertToAssimpAnimation()
|
||||||
|
|
||||||
// Skeleton
|
// Skeleton
|
||||||
|
|
||||||
Skeleton::Skeleton()
|
Skeleton::Skeleton() :
|
||||||
|
blendMode(ANIMBLEND_AVERAGE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,7 +1025,6 @@ Bone::Bone() :
|
||||||
id(0),
|
id(0),
|
||||||
parent(0),
|
parent(0),
|
||||||
parentId(-1),
|
parentId(-1),
|
||||||
rotationAngle(0.0f),
|
|
||||||
scale(1.0f, 1.0f, 1.0f)
|
scale(1.0f, 1.0f, 1.0f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1024,16 +1053,12 @@ void Bone::AddChild(Bone *bone)
|
||||||
|
|
||||||
void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton)
|
void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton)
|
||||||
{
|
{
|
||||||
aiMatrix4x4 t0, t1;
|
|
||||||
aiMatrix4x4 transform = aiMatrix4x4::Rotation(-rotationAngle, rotation, t1) * aiMatrix4x4::Translation(-position, t0);
|
|
||||||
|
|
||||||
if (!IsParented())
|
if (!IsParented())
|
||||||
worldMatrix = transform;
|
worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse();
|
||||||
else
|
else
|
||||||
worldMatrix = transform * parent->worldMatrix;
|
worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix;
|
||||||
|
|
||||||
aiMatrix4x4 t2, t3; /// @todo t0 and t1 could probably be reused here?
|
defaultPose = aiMatrix4x4(scale, rotation, position);
|
||||||
defaultPose = aiMatrix4x4::Translation(position, t2) * aiMatrix4x4::Rotation(rotationAngle, rotation, t3);
|
|
||||||
|
|
||||||
// Recursively for all children now that the parent matrix has been calculated.
|
// Recursively for all children now that the parent matrix has been calculated.
|
||||||
for (size_t i=0, len=children.size(); i<len; ++i)
|
for (size_t i=0, len=children.size(); i<len; ++i)
|
||||||
|
@ -1048,8 +1073,6 @@ void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton)
|
||||||
|
|
||||||
aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
|
aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
|
||||||
{
|
{
|
||||||
aiMatrix4x4 t0,t1;
|
|
||||||
|
|
||||||
// Bone node
|
// Bone node
|
||||||
aiNode* node = new aiNode(name);
|
aiNode* node = new aiNode(name);
|
||||||
node->mParent = parentNode;
|
node->mParent = parentNode;
|
||||||
|
@ -1123,35 +1146,40 @@ aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleto
|
||||||
|
|
||||||
for(size_t kfi=0; kfi<numKeyframes; ++kfi)
|
for(size_t kfi=0; kfi<numKeyframes; ++kfi)
|
||||||
{
|
{
|
||||||
const TransformKeyFrame &kfSource = transformKeyFrames[kfi];
|
TransformKeyFrame &kfSource = transformKeyFrames[kfi];
|
||||||
|
|
||||||
// Create a matrix to transform a vector from the bones
|
|
||||||
// default pose to the bone bones in this animation key
|
|
||||||
aiMatrix4x4 t0, t1;
|
|
||||||
aiMatrix4x4 keyBonePose =
|
|
||||||
aiMatrix4x4::Translation(kfSource.position, t0) *
|
|
||||||
aiMatrix4x4(kfSource.rotation.GetMatrix()) *
|
|
||||||
aiMatrix4x4::Scaling(kfSource.scale, t1);
|
|
||||||
|
|
||||||
// Calculate the complete transformation from world space to bone space
|
// Calculate the complete transformation from world space to bone space
|
||||||
aiMatrix4x4 finalTransform = bone->defaultPose * keyBonePose;
|
aiVector3D pos; aiQuaternion rot; aiVector3D scale;
|
||||||
|
|
||||||
aiVector3D kfPos; aiQuaternion kfRot; aiVector3D kfScale;
|
aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform();
|
||||||
finalTransform.Decompose(kfScale, kfRot, kfPos);
|
finalTransform.Decompose(scale, rot, pos);
|
||||||
|
|
||||||
double t = static_cast<double>(kfSource.timePos);
|
double t = static_cast<double>(kfSource.timePos);
|
||||||
nodeAnim->mPositionKeys[kfi].mTime = t;
|
nodeAnim->mPositionKeys[kfi].mTime = t;
|
||||||
nodeAnim->mRotationKeys[kfi].mTime = t;
|
nodeAnim->mRotationKeys[kfi].mTime = t;
|
||||||
nodeAnim->mScalingKeys[kfi].mTime = t;
|
nodeAnim->mScalingKeys[kfi].mTime = t;
|
||||||
|
|
||||||
nodeAnim->mPositionKeys[kfi].mValue = kfPos;
|
nodeAnim->mPositionKeys[kfi].mValue = pos;
|
||||||
nodeAnim->mRotationKeys[kfi].mValue = kfRot;
|
nodeAnim->mRotationKeys[kfi].mValue = rot;
|
||||||
nodeAnim->mScalingKeys[kfi].mValue = kfScale;
|
nodeAnim->mScalingKeys[kfi].mValue = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeAnim;
|
return nodeAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransformKeyFrame
|
||||||
|
|
||||||
|
TransformKeyFrame::TransformKeyFrame() :
|
||||||
|
timePos(0.0f),
|
||||||
|
scale(1.0f, 1.0f, 1.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
aiMatrix4x4 TransformKeyFrame::Transform()
|
||||||
|
{
|
||||||
|
return aiMatrix4x4(scale, rotation, position);
|
||||||
|
}
|
||||||
|
|
||||||
} // Ogre
|
} // Ogre
|
||||||
} // Assimp
|
} // Assimp
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ class Skeleton;
|
||||||
#define OGRE_SAFE_DELETE(p) delete p; p=0;
|
#define OGRE_SAFE_DELETE(p) delete p; p=0;
|
||||||
|
|
||||||
// Typedefs
|
// Typedefs
|
||||||
typedef Assimp::StreamReaderLE MemoryStreamReader;
|
|
||||||
typedef Assimp::MemoryIOStream MemoryStream;
|
typedef Assimp::MemoryIOStream MemoryStream;
|
||||||
typedef boost::shared_ptr<MemoryStream> MemoryStreamPtr;
|
typedef boost::shared_ptr<MemoryStream> MemoryStreamPtr;
|
||||||
typedef std::map<uint16_t, MemoryStreamPtr> VertexBufferBindings;
|
typedef std::map<uint16_t, MemoryStreamPtr> VertexBufferBindings;
|
||||||
|
@ -318,6 +317,10 @@ typedef std::vector<MorphKeyFrame> MorphKeyFrameList;
|
||||||
/// Ogre animation key frame
|
/// Ogre animation key frame
|
||||||
struct TransformKeyFrame
|
struct TransformKeyFrame
|
||||||
{
|
{
|
||||||
|
TransformKeyFrame();
|
||||||
|
|
||||||
|
aiMatrix4x4 Transform();
|
||||||
|
|
||||||
float timePos;
|
float timePos;
|
||||||
|
|
||||||
aiQuaternion rotation;
|
aiQuaternion rotation;
|
||||||
|
@ -435,9 +438,8 @@ public:
|
||||||
std::vector<uint16_t> children;
|
std::vector<uint16_t> children;
|
||||||
|
|
||||||
aiVector3D position;
|
aiVector3D position;
|
||||||
aiVector3D rotation;
|
aiQuaternion rotation;
|
||||||
aiVector3D scale; ///< @todo Implement taking scale into account in matrix/pose calculations!
|
aiVector3D scale;
|
||||||
float rotationAngle;
|
|
||||||
|
|
||||||
aiMatrix4x4 worldMatrix;
|
aiMatrix4x4 worldMatrix;
|
||||||
aiMatrix4x4 defaultPose;
|
aiMatrix4x4 defaultPose;
|
||||||
|
@ -448,6 +450,14 @@ typedef std::vector<Bone*> BoneList;
|
||||||
class Skeleton
|
class Skeleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum BlendMode
|
||||||
|
{
|
||||||
|
/// Animations are applied by calculating a weighted average of all animations
|
||||||
|
ANIMBLEND_AVERAGE = 0,
|
||||||
|
/// Animations are applied by calculating a weighted cumulative total
|
||||||
|
ANIMBLEND_CUMULATIVE = 1
|
||||||
|
};
|
||||||
|
|
||||||
Skeleton();
|
Skeleton();
|
||||||
~Skeleton();
|
~Skeleton();
|
||||||
|
|
||||||
|
@ -468,6 +478,9 @@ public:
|
||||||
|
|
||||||
BoneList bones;
|
BoneList bones;
|
||||||
AnimationList animations;
|
AnimationList animations;
|
||||||
|
|
||||||
|
/// @todo Take blend mode into account, but where?
|
||||||
|
BlendMode blendMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Ogre Sub Mesh interface, inherited by the binary and XML implementations.
|
/// Ogre Sub Mesh interface, inherited by the binary and XML implementations.
|
||||||
|
|
|
@ -39,8 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "OgreXmlSerializer.h"
|
#include "OgreXmlSerializer.h"
|
||||||
|
#include "OgreBinarySerializer.h"
|
||||||
|
#include "OgreParsingUtils.h"
|
||||||
|
|
||||||
#include "irrXMLWrapper.h"
|
|
||||||
#include "TinyFormatter.h"
|
#include "TinyFormatter.h"
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
|
@ -638,9 +639,10 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
|
||||||
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
|
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
|
||||||
ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex);
|
ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex);
|
||||||
ba.weight = ReadAttribute<float>(anWeight);
|
ba.weight = ReadAttribute<float>(anWeight);
|
||||||
|
|
||||||
dest->boneAssignments.push_back(ba);
|
dest->boneAssignments.push_back(ba);
|
||||||
|
|
||||||
influencedVertices.insert(ba.vertexIndex);
|
influencedVertices.insert(ba.vertexIndex);
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,23 +677,61 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
|
||||||
|
|
||||||
void OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
|
void OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
|
||||||
{
|
{
|
||||||
if (mesh->skeletonRef.empty())
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/** @todo Also support referencing a binary skeleton from a XML mesh?
|
// Highly unusual to see in read world cases but support
|
||||||
This will involves new interfacing to cross ref from MeshXml... */
|
// XML mesh referencing a binary skeleton file.
|
||||||
|
if (EndsWith(mesh->skeletonRef, ".skeleton", false))
|
||||||
std::string filename = mesh->skeletonRef;
|
|
||||||
if (EndsWith(filename, ".skeleton"))
|
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->warn("Mesh is referencing a Ogre binary skeleton. Parsing binary Ogre assets is not supported at the moment. Trying to find .skeleton.xml file instead.");
|
if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
|
||||||
filename += ".xml";
|
return;
|
||||||
|
|
||||||
|
/** Last fallback if .skeleton failed to be read.
|
||||||
|
Try reading from .skeleton.xml even if the XML file
|
||||||
|
referenced a binary skeleton.
|
||||||
|
@note This logic was in the previous version and
|
||||||
|
I don't want to break old code that depends on it. */
|
||||||
|
mesh->skeletonRef = mesh->skeletonRef + ".xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||||
|
if (!reader.get())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Skeleton *skeleton = new Skeleton();
|
||||||
|
OgreXmlSerializer serializer(reader.get());
|
||||||
|
serializer.ReadSkeleton(skeleton);
|
||||||
|
mesh->skeleton = skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
|
||||||
|
{
|
||||||
|
if (!mesh || mesh->skeletonRef.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||||
|
if (!reader.get())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Skeleton *skeleton = new Skeleton();
|
||||||
|
OgreXmlSerializer serializer(reader.get());
|
||||||
|
serializer.ReadSkeleton(skeleton);
|
||||||
|
mesh->skeleton = skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
|
||||||
|
{
|
||||||
|
if (!EndsWith(filename, ".skeleton.xml", false))
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
|
||||||
|
return XmlReaderPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pIOHandler->Exists(filename))
|
if (!pIOHandler->Exists(filename))
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
|
DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
|
||||||
return;
|
return XmlReaderPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::scoped_ptr<IOStream> file(pIOHandler->Open(filename));
|
boost::scoped_ptr<IOStream> file(pIOHandler->Open(filename));
|
||||||
|
@ -700,15 +740,11 @@ void OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::scoped_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
|
boost::scoped_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
|
||||||
XmlReader* reader = irr::io::createIrrXMLReader(stream.get());
|
XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get()));
|
||||||
if (!reader) {
|
if (!reader.get()) {
|
||||||
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
|
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
|
||||||
}
|
}
|
||||||
|
return reader;
|
||||||
Skeleton *skeleton = new Skeleton();
|
|
||||||
OgreXmlSerializer serializer(reader);
|
|
||||||
serializer.ReadSkeleton(skeleton);
|
|
||||||
mesh->skeleton = skeleton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
||||||
|
@ -718,6 +754,12 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultLogger::get()->debug("Reading Skeleton");
|
DefaultLogger::get()->debug("Reading Skeleton");
|
||||||
|
|
||||||
|
// Optional blend mode from root node
|
||||||
|
if (HasAttribute("blendmode")) {
|
||||||
|
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative"
|
||||||
|
? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
|
||||||
|
}
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
|
|
||||||
|
@ -854,10 +896,10 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton)
|
||||||
if (bone && parent)
|
if (bone && parent)
|
||||||
parent->AddChild(bone);
|
parent->AddChild(bone);
|
||||||
else
|
else
|
||||||
DefaultLogger::get()->warn("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
|
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate bone matrices for root bones. Recursively calcutes their children.
|
// Calculate bone matrices for root bones. Recursively calculates their children.
|
||||||
for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
|
for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
|
||||||
{
|
{
|
||||||
Bone *bone = skeleton->bones[i];
|
Bone *bone = skeleton->bones[i];
|
||||||
|
@ -895,15 +937,18 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
|
||||||
}
|
}
|
||||||
else if (m_currentNodeName == nnRotation)
|
else if (m_currentNodeName == nnRotation)
|
||||||
{
|
{
|
||||||
bone->rotationAngle = ReadAttribute<float>("angle");
|
float angle = ReadAttribute<float>("angle");
|
||||||
|
|
||||||
if (NextNode() != nnAxis) {
|
if (NextNode() != nnAxis) {
|
||||||
throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id);
|
throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bone->rotation.x = ReadAttribute<float>(anX);
|
aiVector3D axis;
|
||||||
bone->rotation.y = ReadAttribute<float>(anY);
|
axis.x = ReadAttribute<float>(anX);
|
||||||
bone->rotation.z = ReadAttribute<float>(anZ);
|
axis.y = ReadAttribute<float>(anY);
|
||||||
|
axis.z = ReadAttribute<float>(anZ);
|
||||||
|
|
||||||
|
bone->rotation = aiQuaternion(axis, angle);
|
||||||
}
|
}
|
||||||
else if (m_currentNodeName == nnScale)
|
else if (m_currentNodeName == nnScale)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,8 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||||
|
|
||||||
#include "OgreStructs.h"
|
#include "OgreStructs.h"
|
||||||
#include "OgreParsingUtils.h"
|
|
||||||
|
|
||||||
#include "irrXMLWrapper.h"
|
#include "irrXMLWrapper.h"
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
|
@ -54,6 +52,7 @@ namespace Ogre
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef irr::io::IrrXMLReader XmlReader;
|
typedef irr::io::IrrXMLReader XmlReader;
|
||||||
|
typedef boost::shared_ptr<XmlReader> XmlReaderPtr;
|
||||||
|
|
||||||
class OgreXmlSerializer
|
class OgreXmlSerializer
|
||||||
{
|
{
|
||||||
|
@ -62,16 +61,19 @@ public:
|
||||||
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
||||||
static MeshXml *ImportMesh(XmlReader *reader);
|
static MeshXml *ImportMesh(XmlReader *reader);
|
||||||
|
|
||||||
/// Imports skeleton to @c mesh into MeshXML::skeleton.
|
/// Imports skeleton to @c mesh.
|
||||||
/** If mesh does not have a skeleton reference or the skeleton file
|
/** If mesh does not have a skeleton reference or the skeleton file
|
||||||
cannot be found it is not a fatal DeadlyImportError. */
|
cannot be found it is not a fatal DeadlyImportError. */
|
||||||
static void ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
static void ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
||||||
|
static void ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OgreXmlSerializer(XmlReader *reader) :
|
OgreXmlSerializer(XmlReader *reader) :
|
||||||
m_reader(reader)
|
m_reader(reader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||||
|
|
||||||
// Mesh
|
// Mesh
|
||||||
void ReadMesh(MeshXml *mesh);
|
void ReadMesh(MeshXml *mesh);
|
||||||
|
|
Loading…
Reference in New Issue