diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index da39c10c4..5ab4437b1 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -322,8 +322,14 @@ SOURCE_GROUP( Obj FILES ${Obj_SRCS}) SET( Ogre_SRCS OgreImporter.h + OgreStructs.h OgreParsingUtils.h + OgreBinarySerializer.h + OgreXmlSerializer.h OgreImporter.cpp + OgreStructs.cpp + OgreBinarySerializer.cpp + OgreXmlSerializer.cpp OgreMaterial.cpp OgreMesh.cpp OgreSkeleton.cpp diff --git a/code/OgreBinarySerializer.cpp b/code/OgreBinarySerializer.cpp new file mode 100644 index 000000000..7ade0baa7 --- /dev/null +++ b/code/OgreBinarySerializer.cpp @@ -0,0 +1,759 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +#include "OgreBinarySerializer.h" +#include "TinyFormatter.h" + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +namespace Assimp +{ +namespace Ogre +{ + +const std::string VERSION_1_8 = "[MeshSerializer_v1.8]"; +const unsigned short HEADER_CHUNK_ID = 0x1000; +const long MSTREAM_OVERHEAD_SIZE = sizeof(uint16_t) + sizeof(uint32_t); + +template<> +inline bool OgreBinarySerializer::Read() +{ + return (m_reader->GetU1() > 0); +} + +template<> +inline char OgreBinarySerializer::Read() +{ + return static_cast(m_reader->GetU1()); +} + +template<> +inline uint8_t OgreBinarySerializer::Read() +{ + return m_reader->GetU1(); +} + +template<> +inline uint16_t OgreBinarySerializer::Read() +{ + return m_reader->GetU2(); +} + +template<> +inline uint32_t OgreBinarySerializer::Read() +{ + return m_reader->GetU4(); +} + +template<> +inline float OgreBinarySerializer::Read() +{ + return m_reader->GetF4(); +} + +void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes) +{ + ReadBytes(static_cast(dest), numBytes); +} + +void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes) +{ + ReadBytes(static_cast(dest), numBytes); +} + +void OgreBinarySerializer::ReadBytes(void *dest, size_t numBytes) +{ + m_reader->CopyAndAdvance(dest, numBytes); +} + +uint8_t *OgreBinarySerializer::ReadBytes(size_t numBytes) +{ + uint8_t *bytes = new uint8_t[numBytes]; + ReadBytes(bytes, numBytes); + return bytes; +} + +void OgreBinarySerializer::ReadVector(aiVector3D &vec) +{ + m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3); +} + +bool OgreBinarySerializer::AtEnd() const +{ + return (m_reader->GetRemainingSize() == 0); +} + +std::string OgreBinarySerializer::ReadString(size_t len) +{ + std::string str; + str.resize(len); + ReadBytes(&str[0], len); + return str; +} + +std::string OgreBinarySerializer::ReadLine() +{ + std::string str; + while(!AtEnd()) + { + char c = Read(); + if (c == '\n') + break; + str += c; + } + return str; +} + +uint16_t OgreBinarySerializer::ReadHeader(bool readLen) +{ + uint16_t id = Read(); + if (readLen) + m_currentLen = Read(); + //if (id != HEADER_CHUNK_ID) + // DefaultLogger::get()->debug(Formatter::format() << MeshHeaderToString(static_cast(id))); + return id; +} + +void OgreBinarySerializer::RollbackHeader() +{ + m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE); +} + +void OgreBinarySerializer::SkipBytes(size_t num) +{ + m_reader->IncPtr(num); +} + +Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) +{ + OgreBinarySerializer serializer(stream); + + uint16_t id = serializer.ReadHeader(false); + if (id != HEADER_CHUNK_ID) + throw DeadlyExportError("Invalid Mesh file header"); + + /// @todo Check what we can actually support. + std::string version = serializer.ReadLine(); + if (version != VERSION_1_8) + throw DeadlyExportError("Mesh version " + version + " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again."); + + Mesh *mesh = new Mesh(); + while (!serializer.AtEnd()) + { + id = serializer.ReadHeader(); + switch(id) + { + case M_MESH: + { + serializer.ReadMesh(mesh); + break; + } + } + } + return mesh; +} + +void OgreBinarySerializer::ReadMesh(Mesh *mesh) +{ + mesh->hasSkeletalAnimations = Read(); + + DefaultLogger::get()->debug(Formatter::format() << "Reading Mesh"); + DefaultLogger::get()->debug(Formatter::format() << " - Skeletal animations: " << (mesh->hasSkeletalAnimations ? "true" : "false")); + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && + (id == M_GEOMETRY || + id == M_SUBMESH || + id == M_MESH_SKELETON_LINK || + id == M_MESH_BONE_ASSIGNMENT || + id == M_MESH_LOD || + id == M_MESH_BOUNDS || + id == M_SUBMESH_NAME_TABLE || + id == M_EDGE_LISTS || + id == M_POSES || + id == M_ANIMATIONS || + id == M_TABLE_EXTREMES)) + { + switch(id) + { + case M_GEOMETRY: + { + mesh->sharedVertexData = new VertexData(); + ReadGeometry(mesh, mesh->sharedVertexData); + break; + } + case M_SUBMESH: + ReadSubMesh(mesh); + break; + case M_MESH_SKELETON_LINK: + ReadMeshSkeletonLink(mesh); + break; + case M_MESH_BONE_ASSIGNMENT: + ReadBoneAssignment(mesh); + break; + case M_MESH_LOD: + ReadMeshLodInfo(mesh); + break; + case M_MESH_BOUNDS: + ReadMeshBounds(mesh); + break; + case M_SUBMESH_NAME_TABLE: + ReadSubMeshNames(mesh); + break; + case M_EDGE_LISTS: + ReadEdgeList(mesh); + break; + case M_POSES: + ReadPoses(mesh); + break; + case M_ANIMATIONS: + ReadAnimations(mesh); + break; + case M_TABLE_EXTREMES: + ReadMeshExtremes(mesh); + break; + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadMeshLodInfo(Mesh *mesh) +{ + // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped. + // @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information. + ReadLine(); // strategy name + uint16_t numLods = Read(); + bool manual = Read(); + + /// @note Main mesh is considered as LOD 0, start from index 1. + for (size_t i=1; iIncPtr(sizeof(float)); // user value + + if (manual) + { + id = ReadHeader(); + if (id != M_MESH_LOD_MANUAL) + throw DeadlyImportError("Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL"); + + ReadLine(); // manual mesh name (ref to another mesh) + } + else + { + for(size_t si=0, silen=mesh->NumSubMeshes(); si(); + bool is32bit = Read(); + + if (indexCount > 0) + { + uint32_t len = indexCount * (is32bit ? sizeof(uint32_t) : sizeof(uint16_t)); + m_reader->IncPtr(len); + } + } + } + } +} + +void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh) +{ + mesh->skeletonRef = ReadLine(); +} + +void OgreBinarySerializer::ReadMeshBounds(Mesh *mesh) +{ + // Skip bounds, not compatible with Assimp. + // 2x float vec3 + 1x float sphere radius + SkipBytes(sizeof(float) * 7); +} + +void OgreBinarySerializer::ReadMeshExtremes(Mesh *mesh) +{ + // Skip extremes, not compatible with Assimp. + size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE; + SkipBytes(numBytes); +} + +void OgreBinarySerializer::ReadBoneAssignment(Mesh *dest) +{ + VertexBoneAssignment ba; + ba.vertexIndex = Read(); + ba.boneIndex = Read(); + ba.weight = Read(); + + dest->boneAssignments.push_back(ba); +} + +void OgreBinarySerializer::ReadBoneAssignment(SubMesh2 *dest) +{ + VertexBoneAssignment ba; + ba.vertexIndex = Read(); + ba.boneIndex = Read(); + ba.weight = Read(); + + dest->boneAssignments.push_back(ba); +} + +void OgreBinarySerializer::ReadSubMesh(Mesh *mesh) +{ + uint16_t id = 0; + + SubMesh2 *submesh = new SubMesh2(); + submesh->materialRef = ReadLine(); + submesh->usesSharedVertexData = Read(); + + submesh->indexData->count = Read(); + submesh->indexData->faceCount = static_cast(submesh->indexData->count / 3); + submesh->indexData->is32bit = Read(); + + DefaultLogger::get()->debug(Formatter::format() << "Reading SubMesh " << mesh->subMeshes.size()); + DefaultLogger::get()->debug(Formatter::format() << " - Material: '" << submesh->materialRef << "'"); + DefaultLogger::get()->debug(Formatter::format() << " - Uses shared geometry: " << (submesh->usesSharedVertexData ? "true" : "false")); + + // Index buffer + if (submesh->indexData->count > 0) + { + uint32_t numBytes = submesh->indexData->count * (submesh->indexData->is32bit ? sizeof(uint32_t) : sizeof(uint16_t)); + uint8_t *indexBuffer = ReadBytes(numBytes); + submesh->indexData->buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(indexBuffer, numBytes, true)); + + DefaultLogger::get()->debug(Formatter::format() << " - " << submesh->indexData->faceCount + << " faces from " << submesh->indexData->count << (submesh->indexData->is32bit ? " 32bit" : " 16bit") + << " indexes of " << numBytes << " bytes"); + } + + // Vertex buffer if not referencing the shared geometry + if (!submesh->usesSharedVertexData) + { + id = ReadHeader(); + if (id != M_GEOMETRY) + throw DeadlyImportError("M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false"); + + submesh->vertexData = new VertexData(); + ReadGeometry(mesh, submesh->vertexData); + } + + // Bone assignment, submesh operation and texture aliases + if (!AtEnd()) + { + id = ReadHeader(); + while (!AtEnd() && + (id == M_SUBMESH_OPERATION || + id == M_SUBMESH_BONE_ASSIGNMENT || + id == M_SUBMESH_TEXTURE_ALIAS)) + { + switch(id) + { + case M_SUBMESH_OPERATION: + { + ReadSubMeshOperation(submesh); + break; + } + case M_SUBMESH_BONE_ASSIGNMENT: + { + ReadBoneAssignment(submesh); + break; + } + case M_SUBMESH_TEXTURE_ALIAS: + { + ReadSubMeshTextureAlias(submesh); + break; + } + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } + + submesh->index = mesh->subMeshes.size(); + mesh->subMeshes.push_back(submesh); +} + +void OgreBinarySerializer::ReadSubMeshOperation(SubMesh2 *submesh) +{ + submesh->operationType = static_cast(Read()); +} + +void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh2 *submesh) +{ + submesh->textureAliasName = ReadLine(); + submesh->textureAliasRef = ReadLine(); +} + +void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) +{ + uint16_t id = 0; + uint16_t submeshIndex = 0; + + if (!AtEnd()) + { + id = ReadHeader(); + while (!AtEnd() && id == M_SUBMESH_NAME_TABLE_ELEMENT) + { + SubMesh2 *submesh = mesh->SubMesh(Read()); + if (submesh) + { + submesh->name = ReadLine(); + DefaultLogger::get()->debug(Formatter::format() << " - SubMesh " << submesh->index << " name '" << submesh->name << "'"); + } + else + ReadLine(); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometry(Mesh *mesh, VertexData *dest) +{ + dest->count = Read(); + + DefaultLogger::get()->debug(Formatter::format() << " - Reading geometry of " << dest->count << " vertices"); + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && + (id == M_GEOMETRY_VERTEX_DECLARATION || + id == M_GEOMETRY_VERTEX_BUFFER)) + { + switch(id) + { + case M_GEOMETRY_VERTEX_DECLARATION: + { + ReadGeometryVertexDeclaration(mesh, dest); + break; + } + case M_GEOMETRY_VERTEX_BUFFER: + { + ReadGeometryVertexBuffer(mesh, dest); + break; + } + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometryVertexDeclaration(Mesh *mesh, VertexData *dest) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT) + { + ReadGeometryVertexElement(mesh, dest); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometryVertexElement(Mesh *mesh, VertexData *dest) +{ + VertexElement element; + element.source = Read(); + element.type = static_cast(Read()); + element.semantic = static_cast(Read()); + element.offset = Read(); + element.index = Read(); + + DefaultLogger::get()->debug(Formatter::format() << " - Vertex element " << element.SemanticToString() << " of type " + << element.TypeToString() << " index=" << element.index << " source=" << element.source); + + dest->vertexElements.push_back(element); +} + +void OgreBinarySerializer::ReadGeometryVertexBuffer(Mesh *mesh, VertexData *dest) +{ + uint16_t bindIndex = Read(); + uint16_t vertexSize = Read(); + + uint16_t id = ReadHeader(); + if (id != M_GEOMETRY_VERTEX_BUFFER_DATA) + throw DeadlyImportError("M_GEOMETRY_VERTEX_BUFFER_DATA not found in M_GEOMETRY_VERTEX_BUFFER"); + + if (dest->VertexSize(bindIndex) != vertexSize) + throw DeadlyImportError("Vertex buffer size does not agree with vertex declaration in M_GEOMETRY_VERTEX_BUFFER"); + + size_t numBytes = dest->count * vertexSize; + uint8_t *vertexBuffer = ReadBytes(numBytes); + dest->vertexBindings[bindIndex] = MemoryStreamPtr(new Assimp::MemoryIOStream(vertexBuffer, numBytes, true)); + + DefaultLogger::get()->debug(Formatter::format() << " - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes"); +} + +void OgreBinarySerializer::ReadEdgeList(Mesh *mesh) +{ + // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped. + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_EDGE_LIST_LOD) + { + m_reader->IncPtr(sizeof(uint16_t)); // lod index + bool manual = Read(); + + if (!manual) + { + m_reader->IncPtr(sizeof(uint8_t)); + uint32_t numTriangles = Read(); + uint32_t numEdgeGroups = Read(); + + size_t skipBytes = (sizeof(uint32_t) * 8 + sizeof(float) * 4) * numTriangles; + m_reader->IncPtr(skipBytes); + + for (size_t i=0; iIncPtr(sizeof(uint32_t) * 3); + uint32_t numEdges = Read(); + for (size_t j=0; jIncPtr(sizeof(uint32_t) * 6 + sizeof(uint8_t)); + } + } + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadPoses(Mesh *mesh) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_POSE) + { + Pose *pose = new Pose(); + pose->name = ReadLine(); + pose->target = Read(); + pose->hasNormals = Read(); + + ReadPoseVertices(pose); + + mesh->poses.push_back(pose); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadPoseVertices(Pose *pose) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_POSE_VERTEX) + { + Pose::Vertex v; + v.index = Read(); + ReadVector(v.offset); + if (pose->hasNormals) + ReadVector(v.normal); + + pose->vertices[v.index] = v; + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadAnimations(Mesh *mesh) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_ANIMATION) + { + Animation2 *anim = new Animation2(mesh); + anim->name = ReadLine(); + anim->length = Read(); + + ReadAnimation(anim); + + mesh->animations.push_back(anim); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadAnimation(Animation2 *anim) +{ + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + if (id == M_ANIMATION_BASEINFO) + { + anim->baseName = ReadLine(); + anim->baseTime = Read(); + + // Advance to first track + id = ReadHeader(); + } + + while (!AtEnd() && id == M_ANIMATION_TRACK) + { + VertexAnimationTrack track; + track.type = static_cast(Read()); + track.target = Read(); + + ReadAnimationKeyFrames(anim, &track); + + anim->tracks.push_back(track); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadAnimationKeyFrames(Animation2 *anim, VertexAnimationTrack *track) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && + (id == M_ANIMATION_MORPH_KEYFRAME || + id == M_ANIMATION_POSE_KEYFRAME)) + { + if (id == M_ANIMATION_MORPH_KEYFRAME) + { + MorphKeyFrame kf; + kf.timePos = Read(); + bool hasNormals = Read(); + + size_t vertexCount = anim->AssociatedVertexData(track)->count; + size_t vertexSize = sizeof(float) * (hasNormals ? 6 : 3); + size_t numBytes = vertexCount * vertexSize; + + uint8_t *morphBuffer = ReadBytes(numBytes); + kf.buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(morphBuffer, numBytes, true)); + + track->morphKeyFrames.push_back(kf); + } + else if (id == M_ANIMATION_POSE_KEYFRAME) + { + PoseKeyFrame kf; + kf.timePos = Read(); + + if (!AtEnd()) + { + id = ReadHeader(); + while (!AtEnd() && id == M_ANIMATION_POSE_REF) + { + PoseRef pr; + pr.index = Read(); + pr.influence = Read(); + kf.references.push_back(pr); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } + + track->poseKeyFrames.push_back(kf); + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreBinarySerializer.h b/code/OgreBinarySerializer.h new file mode 100644 index 000000000..26e2951c7 --- /dev/null +++ b/code/OgreBinarySerializer.h @@ -0,0 +1,312 @@ +/* +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 AI_OGREBINARYSERIALIZER_H_INC +#define AI_OGREBINARYSERIALIZER_H_INC + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "OgreStructs.h" + +namespace Assimp +{ +namespace Ogre +{ + class OgreBinarySerializer + { + public: + static Mesh *ImportMesh(MemoryStreamReader *reader); + + 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(SubMesh2 *submesh); + void ReadSubMeshTextureAlias(SubMesh2 *submesh); + + void ReadBoneAssignment(Mesh *dest); + void ReadBoneAssignment(SubMesh2 *dest); + + void ReadGeometry(Mesh *mesh, VertexData *dest); + void ReadGeometryVertexDeclaration(Mesh *mesh, VertexData *dest); + void ReadGeometryVertexElement(Mesh *mesh, VertexData *dest); + void ReadGeometryVertexBuffer(Mesh *mesh, VertexData *dest); + + void ReadEdgeList(Mesh *mesh); + void ReadPoses(Mesh *mesh); + void ReadPoseVertices(Pose *pose); + + void ReadAnimations(Mesh *mesh); + void ReadAnimation(Animation2 *anim); + void ReadAnimationKeyFrames(Animation2 *anim, VertexAnimationTrack *track); + + uint16_t ReadHeader(bool readLen = true); + void RollbackHeader(); + + template + 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 num); + + uint32_t m_currentLen; + MemoryStreamReader *m_reader; + }; + + 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) + // 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 + // unsigned int vertexCount + M_GEOMETRY_VERTEX_DECLARATION = 0x5100, + M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section + // unsigned short source; // buffer bind source + // unsigned short type; // VertexElementType + // unsigned short semantic; // VertexElementSemantic + // unsigned short offset; // start offset in buffer in bytes + // unsigned short index; // index of the semantic (for colours and texture coords) + M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section + // unsigned short bindIndex; // Index to bind this buffer to + // unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index + M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210, + // raw buffer data + M_MESH_SKELETON_LINK = 0x6000, + // Optional link to skeleton + // char* skeletonName : name of .skeleton to use + M_MESH_BONE_ASSIGNMENT = 0x7000, + // Optional bone weights (repeating section) + // unsigned int vertexIndex; + // unsigned short boneIndex; + // float weight; + M_MESH_LOD = 0x8000, + // 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 + // 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, + // 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 "Uknown_MeshChunkId"; + } + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER +#endif // AI_OGREBINARYSERIALIZER_H_INC diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index dbf6e8105..cc2f8fccb 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -38,28 +38,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -#include "AssimpPCH.h" - #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER +#include "AssimpPCH.h" + #include #include +#include #include "OgreImporter.h" +#include "OgreBinarySerializer.h" + #include "TinyFormatter.h" #include "irrXMLWrapper.h" static const aiImporterDesc desc = { - "Ogre XML Mesh Importer", + "Ogre3D Mesh Importer", "", "", "", - aiImporterFlags_SupportTextFlavour, + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, 0, 0, 0, 0, - "mesh.xml" + "mesh mesh.xml" }; using namespace std; @@ -83,11 +86,18 @@ void OgreImporter::SetupProperties(const Importer* pImp) bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const { if (!checkSig) { - return EndsWith(pFile, ".mesh.xml", false); + return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false); } - const char* tokens[] = { "" }; - return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + if (EndsWith(pFile, ".mesh.xml", false)) + { + const char* tokens[] = { "" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + } + else + { + return EndsWith(pFile, ".mesh", false); + } } void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) @@ -95,12 +105,30 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass // -------------------- Initial file and XML operations -------------------- // Open - boost::scoped_ptr file(pIOHandler->Open(pFile)); - if (!file.get()) { + IOStream *f = pIOHandler->Open(pFile, "rb"); + if (!f) { throw DeadlyImportError("Failed to open file " + pFile); } + // Binary .mesh import + if (EndsWith(pFile, ".mesh", false)) { + // Read full data from file + /// @note MemoryStreamReader takes ownership of f. + MemoryStreamReader reader(f); + + // Import mesh + boost::scoped_ptr mesh = OgreBinarySerializer::ImportMesh(&reader); + + // Import mesh referenced materials + ReadMaterials(pFile, pIOHandler, pScene, mesh.get()); + + // Convert to Assimp. + mesh->ConvertToAssimpScene(pScene); + return; + } + // Read + boost::scoped_ptr file(f); boost::scoped_ptr xmlStream(new CIrrXML_IOStreamReader(file.get())); boost::scoped_ptr reader(irr::io::createIrrXMLReader(xmlStream.get())); if (!reader) { @@ -153,18 +181,19 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass SubMesh* submesh = new SubMesh(); ReadSubMesh(subMeshes.size(), *submesh, reader.get()); - // Just a index in a array, we add a mesh in each loop cycle, so we get indicies like 0, 1, 2 ... n; - // so it is important to do this before pushing the mesh in the vector! - /// @todo Not sure if this really is needed, refactor out if possible. - submesh->MaterialIndex = subMeshes.size(); - - subMeshes.push_back(boost::shared_ptr(submesh)); - /** @todo What is the correct way of handling empty ref here. Does Assimp require there to be a valid material index for each mesh, even if its a dummy material. */ aiMaterial* material = ReadMaterial(pFile, pIOHandler, submesh->MaterialName); - materials.push_back(material); + if (!material) + material = new aiMaterial(); + if (material) + { + submesh->MaterialIndex = materials.size(); + materials.push_back(material); + } + + subMeshes.push_back(boost::shared_ptr(submesh)); } if (subMeshes.empty()) { @@ -223,10 +252,12 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass // -------------------- Apply to aiScene -------------------- // Materials - pScene->mMaterials = new aiMaterial*[materials.size()]; pScene->mNumMaterials = materials.size(); + if (pScene->mNumMaterials > 0) { + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + } - for(size_t i=0, len=materials.size(); imNumMaterials; ++i) { pScene->mMaterials[i] = materials[i]; } diff --git a/code/OgreImporter.h b/code/OgreImporter.h index e40809073..538ea83f5 100644 --- a/code/OgreImporter.h +++ b/code/OgreImporter.h @@ -1,3 +1,42 @@ +/* +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 AI_OGREIMPORTER_H_INC #define AI_OGREIMPORTER_H_INC @@ -5,6 +44,8 @@ #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER #include "BaseImporter.h" + +#include "OgreStructs.h" #include "OgreParsingUtils.h" namespace Assimp @@ -114,6 +155,9 @@ private: //-------------------------------- OgreMaterial.cpp ------------------------------- + /// Read materials referenced by the @c mesh to @c pScene. + void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh); + /// Reads material aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName); diff --git a/code/OgreMaterial.cpp b/code/OgreMaterial.cpp index b284dbb31..63ff53485 100644 --- a/code/OgreMaterial.cpp +++ b/code/OgreMaterial.cpp @@ -59,11 +59,40 @@ static const string partComment = "//"; static const string partBlockStart = "{"; static const string partBlockEnd = "}"; +void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh) +{ + std::vector materials; + + // Create materials that can be found and parsed via the IOSystem. + for (size_t i=0, len=mesh->NumSubMeshes(); iSubMesh(i); + if (submesh && !submesh->materialRef.empty()) + { + aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef); + if (material) + { + submesh->materialIndex = materials.size(); + materials.push_back(material); + } + } + } + + // Assign material to scene + pScene->mNumMaterials = materials.size(); + if (pScene->mNumMaterials > 0) + { + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for(size_t i=0;imNumMaterials; ++i) { + pScene->mMaterials[i] = materials[i]; + } + } +} + aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string materialName) { - /// @todo Should we return null ptr here or a empty material? if (materialName.empty()) { - return new aiMaterial(); + return 0; } // Full reference and examples of Ogre Material Script @@ -117,17 +146,15 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste } if (!materialFile) { - /// @todo Should we return null ptr here or a empty material? DefaultLogger::get()->error(Formatter::format() << "Failed to find source file for material '" << materialName << "'"); - return new aiMaterial(); + return 0; } boost::scoped_ptr stream(materialFile); if (stream->FileSize() == 0) { - /// @todo Should we return null ptr here or a empty material? DefaultLogger::get()->warn(Formatter::format() << "Source file for material '" << materialName << "' is empty (size is 0 bytes)"); - return new aiMaterial(); + return 0; } // Read bytes diff --git a/code/OgreMesh.cpp b/code/OgreMesh.cpp index ff481b1b4..a1b213127 100644 --- a/code/OgreMesh.cpp +++ b/code/OgreMesh.cpp @@ -469,7 +469,8 @@ aiMesh *OgreImporter::CreateAssimpSubMesh(aiScene *pScene, const SubMesh& submes aiMesh *dest = new aiMesh(); // Material - dest->mMaterialIndex = submesh.MaterialIndex; + if (submesh.MaterialIndex != -1) + dest->mMaterialIndex = submesh.MaterialIndex; // Positions dest->mVertices = new aiVector3D[submesh.Positions.size()]; diff --git a/code/OgreParsingUtils.h b/code/OgreParsingUtils.h index ac1e58173..0771a0d30 100644 --- a/code/OgreParsingUtils.h +++ b/code/OgreParsingUtils.h @@ -1,3 +1,42 @@ +/* +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 AI_OGREPARSINGUTILS_H_INC #define AI_OGREPARSINGUTILS_H_INC @@ -13,6 +52,70 @@ namespace Assimp namespace Ogre { +/// Returns a lower cased copy of @s. +static inline std::string ToLower(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + return s; +} + +/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching. +static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) +{ + if (s.empty() || suffix.empty()) + { + return false; + } + else if (s.length() < suffix.length()) + { + return false; + } + + if (!caseSensitive) { + return EndsWith(ToLower(s), ToLower(suffix), true); + } + + size_t len = suffix.length(); + std::string sSuffix = s.substr(s.length()-len, len); + return (ASSIMP_stricmp(sSuffix, suffix) == 0); +} + +// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring + +/// Trim from start +static inline std::string &TrimLeft(std::string &s, bool newlines = true) +{ + if (!newlines) + { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpace)))); + } + else + { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); + } + return s; +} + +/// Trim from end +static inline std::string &TrimRight(std::string &s, bool newlines = true) +{ + if (!newlines) + { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(Assimp::IsSpace))).base(),s.end()); + } + else + { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); + } + return s; +} + +/// Trim from both ends +static inline std::string &Trim(std::string &s, bool newlines = true) +{ + return TrimLeft(TrimRight(s, newlines), newlines); +} + typedef irr::io::IrrXMLReader XmlReader; static void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") @@ -93,7 +196,7 @@ inline std::string GetAttribute(const XmlReader* reader, const std: template<> inline bool GetAttribute(const XmlReader* reader, const std::string &name) { - std::string value = GetAttribute(reader, name); + std::string value = Ogre::ToLower(GetAttribute(reader, name)); if (ASSIMP_stricmp(value, "true") == 0) { return true; @@ -143,70 +246,6 @@ static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &n return skipped; } -/// Returns a lower cased copy of @s. -static inline std::string ToLower(std::string s) -{ - std::transform(s.begin(), s.end(), s.begin(), ::tolower); - return s; -} - -/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching. -static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) -{ - if (s.empty() || suffix.empty()) - { - return false; - } - else if (s.length() < suffix.length()) - { - return false; - } - - if (!caseSensitive) { - return EndsWith(ToLower(s), ToLower(suffix), true); - } - - size_t len = suffix.length(); - std::string sSuffix = s.substr(s.length()-len, len); - return (ASSIMP_stricmp(sSuffix, suffix) == 0); -} - -// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring - -/// Trim from start -static inline std::string &TrimLeft(std::string &s, bool newlines = true) -{ - if (!newlines) - { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpace)))); - } - else - { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); - } - return s; -} - -/// Trim from end -static inline std::string &TrimRight(std::string &s, bool newlines = true) -{ - if (!newlines) - { - s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(Assimp::IsSpace))).base(),s.end()); - } - else - { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); - } - return s; -} - -/// Trim from both ends -static inline std::string &Trim(std::string &s, bool newlines = true) -{ - return TrimLeft(TrimRight(s, newlines), newlines); -} - } // Ogre } // Assimp diff --git a/code/OgreSkeleton.cpp b/code/OgreSkeleton.cpp index 3f0b7abb1..b8ac4e43b 100644 --- a/code/OgreSkeleton.cpp +++ b/code/OgreSkeleton.cpp @@ -5,11 +5,11 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2012, assimp team All rights reserved. -Redistribution and use of this software in aSource and binary forms, +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 aSource code must retain the above +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/code/OgreStructs.cpp b/code/OgreStructs.cpp new file mode 100644 index 000000000..9390021d9 --- /dev/null +++ b/code/OgreStructs.cpp @@ -0,0 +1,583 @@ +/* +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"; +} + +// VertexData + +VertexData::VertexData() : + count(0) +{ +} + +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]; + 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; +} + +// 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), + hasSkeletalAnimations(false) +{ +} + +Mesh::~Mesh() +{ + Reset(); +} + +void Mesh::Reset() +{ + OGRE_SAFE_DELETE(sharedVertexData) + for(size_t i=0, len=subMeshes.size(); iindex == index) + return subMeshes[i]; + return 0; +} + +void Mesh::ConvertToAssimpScene(aiScene* dest) +{ + // Export meshes + 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]; + + for(size_t i=0; imNumMeshes; ++i) { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } +} + +// SubMesh2 + +SubMesh2::SubMesh2() : + index(0), + vertexData(0), + indexData(new IndexData()), + usesSharedVertexData(false), + operationType(OT_POINT_LIST), + materialIndex(-1) +{ +} + +SubMesh2::~SubMesh2() +{ + Reset(); +} + +void SubMesh2::Reset() +{ + OGRE_SAFE_DELETE(vertexData) + OGRE_SAFE_DELETE(indexData) +} + +aiMesh *SubMesh2::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); + + // 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(); + fimNumFaces; ++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(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]; + + // 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); + } + // UV1 + if (uv2 && uv2Dest) + { + uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET); + uv2->Read(&uv2Dest[newIndex], sizeUv2, 1); + } + + /// @todo Bones and bone weights. + } + } + return dest; +} + +// Animation2 + +Animation2::Animation2(Mesh *_parentMesh) : + parentMesh(_parentMesh), + length(0.0f), + baseTime(-1.0f) +{ +} + +VertexData *Animation2::AssociatedVertexData(VertexAnimationTrack *track) const +{ + bool sharedGeom = (track->target == 0); + if (sharedGeom) + return parentMesh->sharedVertexData; + else + return parentMesh->SubMesh(track->target-1)->vertexData; +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreStructs.h b/code/OgreStructs.h new file mode 100644 index 000000000..72cdd3e91 --- /dev/null +++ b/code/OgreStructs.h @@ -0,0 +1,444 @@ +/* +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 AI_OGRESTRUCTS_H_INC +#define AI_OGRESTRUCTS_H_INC + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "AssimpPCH.h" +#include "MemoryIOWrapper.h" + +/** @note Parts of this implementation, for example enums, deserialization constants and logic + has been copied directly with minor modifications from the MIT licensed Ogre3D code base. + See more from https://bitbucket.org/sinbad/ogre. */ + +namespace Assimp +{ +namespace Ogre +{ + +// Forward decl +class Mesh; +class SubMesh2; + +#define OGRE_SAFE_DELETE(p) delete p; p=0; + +// Typedefs +typedef Assimp::StreamReaderLE MemoryStreamReader; +typedef Assimp::MemoryIOStream MemoryStream; +typedef boost::shared_ptr MemoryStreamPtr; +typedef std::map VertexBufferBindings; + +// Ogre Vertex Element +class VertexElement +{ +public: + /// Vertex element semantics, used to identify the meaning of vertex buffer contents + enum Semantic { + /// Position, 3 reals per vertex + VES_POSITION = 1, + /// Blending weights + VES_BLEND_WEIGHTS = 2, + /// Blending indices + VES_BLEND_INDICES = 3, + /// Normal, 3 reals per vertex + VES_NORMAL = 4, + /// Diffuse colours + VES_DIFFUSE = 5, + /// Specular colours + VES_SPECULAR = 6, + /// Texture coordinates + VES_TEXTURE_COORDINATES = 7, + /// Binormal (Y axis if normal is Z) + VES_BINORMAL = 8, + /// Tangent (X axis if normal is Z) + VES_TANGENT = 9, + /// The number of VertexElementSemantic elements (note - the first value VES_POSITION is 1) + VES_COUNT = 9 + }; + + /// Vertex element type, used to identify the base types of the vertex contents + enum Type + { + VET_FLOAT1 = 0, + VET_FLOAT2 = 1, + VET_FLOAT3 = 2, + VET_FLOAT4 = 3, + /// alias to more specific colour type - use the current rendersystem's colour packing + VET_COLOUR = 4, + VET_SHORT1 = 5, + VET_SHORT2 = 6, + VET_SHORT3 = 7, + VET_SHORT4 = 8, + VET_UBYTE4 = 9, + /// D3D style compact colour + VET_COLOUR_ARGB = 10, + /// GL style compact colour + VET_COLOUR_ABGR = 11, + VET_DOUBLE1 = 12, + VET_DOUBLE2 = 13, + VET_DOUBLE3 = 14, + VET_DOUBLE4 = 15, + VET_USHORT1 = 16, + VET_USHORT2 = 17, + VET_USHORT3 = 18, + VET_USHORT4 = 19, + VET_INT1 = 20, + VET_INT2 = 21, + VET_INT3 = 22, + VET_INT4 = 23, + VET_UINT1 = 24, + VET_UINT2 = 25, + VET_UINT3 = 26, + VET_UINT4 = 27 + }; + + VertexElement(); + + /// Size of the vertex element in bytes. + size_t Size() const; + + /// Count of components in this element, eg. VET_FLOAT3 return 3. + size_t ComponentCount() const; + + /// Type as string. + std::string TypeToString(); + + /// Semantic as string. + std::string SemanticToString(); + + static size_t TypeSize(Type type); + static size_t ComponentCount(Type type); + static std::string TypeToString(Type type); + static std::string SemanticToString(Semantic semantic); + + uint16_t index; + uint16_t source; + uint16_t offset; + Type type; + Semantic semantic; +}; + +typedef std::vector VertexElementList; + +// Ogre Vertex Data +class VertexData +{ +public: + VertexData(); + ~VertexData(); + + /// Releases all memory that this data structure owns. + void Reset(); + + /// Get vertex size for @c source. + uint32_t VertexSize(uint16_t source) const; + + /// Get vertex buffer for @c source. + MemoryStream *VertexBuffer(uint16_t source); + + /// Get vertex element for @c semantic for @c index. + VertexElement *GetVertexElement(VertexElement::Semantic semantic, uint16_t index = 0); + + /// Vertex count. + uint32_t count; + + /// Vertex elements. + VertexElementList vertexElements; + + /// Vertex buffers mapped to bind index. + VertexBufferBindings vertexBindings; +}; + +// Ogre Index Data +class IndexData +{ +public: + IndexData(); + ~IndexData(); + + /// Releases all memory that this data structure owns. + void Reset(); + + /// Index size in bytes. + size_t IndexSize() const; + + /// Face size in bytes. + size_t FaceSize() const; + + /// Index count. + uint32_t count; + + /// Face count. + uint32_t faceCount; + + /// If has 32-bit indexes. + bool is32bit; + + /// Index buffer. + MemoryStreamPtr buffer; +}; + +/// Ogre Pose +class Pose +{ +public: + struct Vertex + { + uint32_t index; + aiVector3D offset; + aiVector3D normal; + }; + typedef std::map PoseVertexMap; + + Pose() : target(0), hasNormals(false) {} + + /// Name. + std::string name; + + /// Target. + uint16_t target; + + /// Does vertices map have normals. + bool hasNormals; + + /// Vertex offset and normals. + PoseVertexMap vertices; +}; + +/// Ogre Pose Key Frame Ref +struct PoseRef +{ + uint16_t index; + float influence; +}; + +/// Ogre Pose Key Frame +struct PoseKeyFrame +{ + /// Time position in the animation. + float timePos; + + std::vector references; +}; + +/// Ogre Morph Key Frame +struct MorphKeyFrame +{ + /// Time position in the animation. + float timePos; + + MemoryStreamPtr buffer; +}; + +/// Ogre Animation Track +struct VertexAnimationTrack +{ + enum Type + { + /// No animation + VAT_NONE = 0, + /// Morph animation is made up of many interpolated snapshot keyframes + VAT_MORPH = 1, + /// Pose animation is made up of a single delta pose keyframe + VAT_POSE = 2 + }; + + /// Vertex data target. + /** 0 == shared geometry + >0 == submesh index + 1 */ + uint16_t target; + Type type; + + std::vector poseKeyFrames; + std::vector morphKeyFrames; +}; + +/// Ogre Animation +/** @todo Port OgreImporter::Animation to this and rename this to Animation! */ +class Animation2 +{ +public: + Animation2(Mesh *_parentMesh); + + /// Returns the associated vertex data for a track in this animation. + VertexData *AssociatedVertexData(VertexAnimationTrack *track) const; + + /// Parent mesh. + Mesh *parentMesh; + + /// Animation name. + std::string name; + + /// Base animation name. + std::string baseName; + + /// Length in seconds. + float length; + + /// Base animation key time. + float baseTime; + + /// Animation tracks. + std::vector tracks; +}; + +/// Ogre Vertex Bone Assignment +struct VertexBoneAssignment +{ + uint32_t vertexIndex; + uint16_t boneIndex; + float weight; +}; + +/// Ogre SubMesh +/** @todo Port OgreImporter::SubMesh to this and rename this to SubMesh! */ +class SubMesh2 +{ +public: + /// @note Full list of Ogre types, not all of them are supported and exposed to Assimp. + enum OperationType + { + /// A list of points, 1 vertex per point + OT_POINT_LIST = 1, + /// A list of lines, 2 vertices per line + OT_LINE_LIST = 2, + /// A strip of connected lines, 1 vertex per line plus 1 start vertex + OT_LINE_STRIP = 3, + /// A list of triangles, 3 vertices per triangle + OT_TRIANGLE_LIST = 4, + /// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that + OT_TRIANGLE_STRIP = 5, + /// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that + OT_TRIANGLE_FAN = 6 + }; + + SubMesh2(); + ~SubMesh2(); + + /// Releases all memory that this data structure owns. + /** @note Vertex and index data contains shared ptrs + that are freed automatically. In practice the ref count + should be 0 after this reset. */ + void Reset(); + + /// Covert to Assimp mesh. + aiMesh *ConvertToAssimpMesh(Mesh *parent); + + /// SubMesh index. + unsigned int index; + + /// SubMesh name. + std::string name; + + /// Material used by this submesh. + std::string materialRef; + + /// Texture alias information. + std::string textureAliasName; + std::string textureAliasRef; + + /// Assimp scene material index used by this submesh. + /** -1 if no material or material could not be imported. */ + int materialIndex; + + /// Vertex data. + VertexData *vertexData; + + /// Index data. + IndexData *indexData; + + /// If submesh uses shared geometry from parent mesh. + bool usesSharedVertexData; + + /// Operation type. + OperationType operationType; + + /// Bone assignments. + std::vector boneAssignments; +}; + +/// Ogre Mesh +class Mesh +{ +public: + Mesh(); + ~Mesh(); + + /// Releases all memory that this data structure owns. + void Reset(); + + /// Returns number of subMeshes. + size_t NumSubMeshes() const; + + /// Returns submesh for @c index. + SubMesh2 *SubMesh(uint16_t index) const; + + /// Convert mesh to Assimp scene. + void ConvertToAssimpScene(aiScene* dest); + + /// Mesh has skeletal animations. + bool hasSkeletalAnimations; + + /// Skeleton reference. + std::string skeletonRef; + + /// Vertex data + VertexData *sharedVertexData; + + /// Sub meshes. + std::vector subMeshes; + + /// Animations + std::vector animations; + + /// Bone assignments. + std::vector boneAssignments; + + /// Poses + std::vector poses; +}; + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER +#endif // AI_OGRESTRUCTS_H_INC diff --git a/code/OgreXmlSerializer.cpp b/code/OgreXmlSerializer.cpp new file mode 100644 index 000000000..b2f44290a --- /dev/null +++ b/code/OgreXmlSerializer.cpp @@ -0,0 +1,42 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @todo Move XML related serialization from OgreImporter.cpp + here in a similar fashion as OgreBinarySerializer. */ diff --git a/code/OgreXmlSerializer.h b/code/OgreXmlSerializer.h new file mode 100644 index 000000000..b2f44290a --- /dev/null +++ b/code/OgreXmlSerializer.h @@ -0,0 +1,42 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @todo Move XML related serialization from OgreImporter.cpp + here in a similar fashion as OgreBinarySerializer. */