diff --git a/.gitignore b/.gitignore index 7fe107086..4ddf06e63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,34 @@ build .project *.kdev4* + +# Visual Studio +*.sln +*.ncb +*.vcproj + +# Output +bin/ +lib/ +contrib/ + +# Generated +assimp.pc +revision.h +contrib/zlib/zconf.h +contrib/zlib/zlib.pc + +# CMake +CMakeCache.txt +CMakeFiles +cmake_install.cmake +cmake_uninstall.cmake +*.dir/ +assimp-config.cmake +assimp-config-version.cmake + +# Tests +test/results + +# Python +__pycache__ diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index da39c10c4..8dbb0962f 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -322,11 +322,15 @@ 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 ) SOURCE_GROUP( Ogre FILES ${Ogre_SRCS}) diff --git a/code/OgreBinarySerializer.cpp b/code/OgreBinarySerializer.cpp new file mode 100644 index 000000000..6674f4cee --- /dev/null +++ b/code/OgreBinarySerializer.cpp @@ -0,0 +1,1110 @@ +/* +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 "OgreXmlSerializer.h" +#include "OgreParsingUtils.h" + +#include "TinyFormatter.h" + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +// Define as 1 to get verbose logging. +#define OGRE_BINARY_SERIALIZER_DEBUG 0 + +namespace Assimp +{ +namespace Ogre +{ + +const std::string MESH_VERSION_1_8 = "[MeshSerializer_v1.8]"; +const std::string SKELETON_VERSION_1_8 = "[Serializer_v1.80]"; +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<> +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); +} + +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 +{ + 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 (OGRE_BINARY_SERIALIZER_DEBUG == 1) + if (id != HEADER_CHUNK_ID) + { + DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh + ? MeshHeaderToString(static_cast(id)) : SkeletonHeaderToString(static_cast(id)))); + } +#endif + + return id; +} + +void OgreBinarySerializer::RollbackHeader() +{ + m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE); +} + +void OgreBinarySerializer::SkipBytes(size_t numBytes) +{ +#if (OGRE_BINARY_SERIALIZER_DEBUG == 1) + DefaultLogger::get()->debug(Formatter::format() << "Skipping " << numBytes << " bytes"); +#endif + + m_reader->IncPtr(numBytes); +} + +// Mesh + +Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) +{ + OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh); + + uint16_t id = serializer.ReadHeader(false); + if (id != HEADER_CHUNK_ID) { + throw DeadlyExportError("Invalid Ogre Mesh file header."); + } + + /// @todo Check what we can actually support. + std::string version = serializer.ReadLine(); + if (version != MESH_VERSION_1_8) + { + 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(); + 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("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->sharedVertexData); + break; + } + case M_SUBMESH: + { + ReadSubMesh(mesh); + break; + } + case M_MESH_SKELETON_LINK: + { + ReadMeshSkeletonLink(mesh); + break; + } + case M_MESH_BONE_ASSIGNMENT: + { + ReadBoneAssignment(mesh->sharedVertexData); + 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(); + } + + NormalizeBoneWeights(mesh->sharedVertexData); +} + +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(VertexData *dest) +{ + if (!dest) { + throw DeadlyImportError("Cannot read bone assignments, vertex data is null."); + } + + 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; + + SubMesh *submesh = new SubMesh(); + 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(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->vertexData); + break; + } + case M_SUBMESH_TEXTURE_ALIAS: + { + ReadSubMeshTextureAlias(submesh); + break; + } + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } + + NormalizeBoneWeights(submesh->vertexData); + + submesh->index = mesh->subMeshes.size(); + mesh->subMeshes.push_back(submesh); +} + +void OgreBinarySerializer::NormalizeBoneWeights(VertexData *vertexData) const +{ + if (!vertexData || vertexData->boneAssignments.empty()) + return; + + std::set influencedVertices; + for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) { + influencedVertices.insert(baIter->vertexIndex); + } + + /** Normalize bone weights. + Some exporters wont care if the sum of all bone weights + for a single vertex equals 1 or not, so validate here. */ + const float epsilon = 0.05f; + for(std::set::const_iterator iter=influencedVertices.begin(), end=influencedVertices.end(); iter != end; ++iter) + { + const uint32_t vertexIndex = (*iter); + + float sum = 0.0f; + for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) + { + if (baIter->vertexIndex == vertexIndex) + sum += baIter->weight; + } + if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) + { + for (VertexBoneAssignmentList::iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) + { + if (baIter->vertexIndex == vertexIndex) + baIter->weight /= sum; + } + } + } +} + +void OgreBinarySerializer::ReadSubMeshOperation(SubMesh *submesh) +{ + submesh->operationType = static_cast(Read()); +} + +void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *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) + { + uint16_t submeshIndex = Read(); + SubMesh *submesh = mesh->GetSubMesh(submeshIndex); + if (!submesh) { + throw DeadlyImportError(Formatter::format() << "Ogre Mesh does not include submesh " << submeshIndex << " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file."); + } + + submesh->name = ReadLine(); + DefaultLogger::get()->debug(Formatter::format() << " - SubMesh " << submesh->index << " name '" << submesh->name << "'"); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometry(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(dest); + break; + } + case M_GEOMETRY_VERTEX_BUFFER: + { + ReadGeometryVertexBuffer(dest); + break; + } + } + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometryVertexDeclaration(VertexData *dest) +{ + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT) + { + ReadGeometryVertexElement(dest); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadGeometryVertexElement(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(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) + { + Animation *anim = new Animation(mesh); + anim->name = ReadLine(); + anim->length = Read(); + + ReadAnimation(anim); + + mesh->animations.push_back(anim); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } +} + +void OgreBinarySerializer::ReadAnimation(Animation *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(Animation *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(); + } +} + +// 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(Read()); + 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(); ibones[i]; + if (!bone->IsParented()) + bone->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +void OgreBinarySerializer::ReadBone(Skeleton *skeleton) +{ + Bone *bone = new Bone(); + bone->name = ReadLine(); + bone->id = Read(); + + // 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 parentId = Read(); + + 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(); + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + if (id == SKELETON_ANIMATION_BASEINFO) + { + anim->baseName = ReadLine(); + anim->baseTime = Read(); + + // 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(); + 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(); + + // 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 +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreBinarySerializer.h b/code/OgreBinarySerializer.h new file mode 100644 index 000000000..69db4b722 --- /dev/null +++ b/code/OgreBinarySerializer.h @@ -0,0 +1,416 @@ +/* +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 +{ + +typedef Assimp::StreamReaderLE MemoryStreamReader; +typedef boost::shared_ptr 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. + @return If skeleton import was successful. */ + static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); + static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); + +private: + enum AssetMode + { + AM_Mesh, + AM_Skeleton + }; + + OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) : + m_reader(reader), + m_currentLen(0), + assetMode(mode) + { + } + + static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); + + // Header + + uint16_t ReadHeader(bool readLen = true); + void RollbackHeader(); + + // Mesh + + 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; + + // 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 + 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) + // 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 "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 +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER +#endif // AI_OGREBINARYSERIALIZER_H_INC diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index dbf6e8105..d28b2cf90 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -38,32 +38,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -#include "AssimpPCH.h" - #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER -#include -#include +#include "AssimpPCH.h" #include "OgreImporter.h" -#include "TinyFormatter.h" -#include "irrXMLWrapper.h" +#include "OgreBinarySerializer.h" +#include "OgreXmlSerializer.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; - namespace Assimp { namespace Ogre @@ -83,174 +78,67 @@ 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 + { + /// @todo Read and validate first header chunk? + return EndsWith(pFile, ".mesh", false); + } } void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) { - // -------------------- Initial file and XML operations -------------------- - - // Open - boost::scoped_ptr file(pIOHandler->Open(pFile)); - if (!file.get()) { + // Open source file + IOStream *f = pIOHandler->Open(pFile, "rb"); + if (!f) { throw DeadlyImportError("Failed to open file " + pFile); } - // Read - boost::scoped_ptr xmlStream(new CIrrXML_IOStreamReader(file.get())); - boost::scoped_ptr reader(irr::io::createIrrXMLReader(xmlStream.get())); - if (!reader) { - throw DeadlyImportError("Failed to create XML Reader for " + pFile); - } - - DefaultLogger::get()->debug("Opened a XML reader for " + pFile); - - // Read root node - NextNode(reader.get()); - if (!CurrentNodeNameEquals(reader.get(), "mesh")) { - throw DeadlyImportError("Root node is not but <" + string(reader->getNodeName()) + "> in " + pFile); - } - - // Node names - const string nnSharedGeometry = "sharedgeometry"; - const string nnVertexBuffer = "vertexbuffer"; - const string nnSubMeshes = "submeshes"; - const string nnSubMesh = "submesh"; - const string nnSubMeshNames = "submeshnames"; - const string nnSkeletonLink = "skeletonlink"; - - // -------------------- Shared Geometry -------------------- - // This can be used to share geometry between submeshes - - NextNode(reader.get()); - if (CurrentNodeNameEquals(reader.get(), nnSharedGeometry)) + // Binary .mesh import + if (EndsWith(pFile, ".mesh", false)) { - DefaultLogger::get()->debug("Reading shared geometry"); - unsigned int NumVertices = GetAttribute(reader.get(), "vertexcount"); + /// @note MemoryStreamReader takes ownership of f. + MemoryStreamReader reader(f); - NextNode(reader.get()); - while(CurrentNodeNameEquals(reader.get(), nnVertexBuffer)) { - ReadVertexBuffer(m_SharedGeometry, reader.get(), NumVertices); - } - } - - // -------------------- Sub Meshes -------------------- - - if (!CurrentNodeNameEquals(reader.get(), nnSubMeshes)) { - throw DeadlyImportError("Could not find node inside root node"); - } - - vector > subMeshes; - vector materials; - - NextNode(reader.get()); - while(CurrentNodeNameEquals(reader.get(), nnSubMesh)) - { - 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 (subMeshes.empty()) { - throw DeadlyImportError("Could not find node inside root node"); - } - - // This is really a internal error if we failed to create dummy materials. - if (subMeshes.size() != materials.size()) { - throw DeadlyImportError("Internal Error: Material count does not match the submesh count"); - } - - // Skip submesh names. - /// @todo Should these be read to scene etc. metadata? - if (CurrentNodeNameEquals(reader.get(), nnSubMeshNames)) - { - NextNode(reader.get()); - while(CurrentNodeNameEquals(reader.get(), nnSubMesh)) { - NextNode(reader.get()); - } - } - - // -------------------- Skeleton -------------------- - - vector Bones; - vector Animations; - - if (CurrentNodeNameEquals(reader.get(), nnSkeletonLink)) - { - string skeletonFile = GetAttribute(reader.get(), "name"); - if (!skeletonFile.empty()) - { - ReadSkeleton(pFile, pIOHandler, pScene, skeletonFile, Bones, Animations); - } - else - { - DefaultLogger::get()->debug("Found a unusual <" + nnSkeletonLink + "> with a empty file reference"); - } - NextNode(reader.get()); + // Import mesh + boost::scoped_ptr mesh = OgreBinarySerializer::ImportMesh(&reader); + + // Import skeleton + OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh); + + // Import mesh referenced materials + ReadMaterials(pFile, pIOHandler, pScene, mesh.get()); + + // Convert to Assimp + mesh->ConvertToAssimpScene(pScene); } + // XML .mesh.xml import else { - DefaultLogger::get()->debug("Mesh has no assigned skeleton with <" + nnSkeletonLink + ">"); + /// @note XmlReader does not take ownership of f, hence the scoped ptr. + boost::scoped_ptr scopedFile(f); + boost::scoped_ptr xmlStream(new CIrrXML_IOStreamReader(scopedFile.get())); + boost::scoped_ptr reader(irr::io::createIrrXMLReader(xmlStream.get())); + + // Import mesh + boost::scoped_ptr mesh = OgreXmlSerializer::ImportMesh(reader.get()); + + // Import skeleton + OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh); + + // Import mesh referenced materials + ReadMaterials(pFile, pIOHandler, pScene, mesh.get()); + + // Convert to Assimp + mesh->ConvertToAssimpScene(pScene); } - - // Now there might be for the shared geometry - if (CurrentNodeNameEquals(reader.get(), "boneassignments")) { - ReadBoneWeights(m_SharedGeometry, reader.get()); - } - - // -------------------- Process Results -------------------- - BOOST_FOREACH(boost::shared_ptr submesh, subMeshes) - { - ProcessSubMesh(*submesh.get(), m_SharedGeometry); - } - - // -------------------- Apply to aiScene -------------------- - - // Materials - pScene->mMaterials = new aiMaterial*[materials.size()]; - pScene->mNumMaterials = materials.size(); - - for(size_t i=0, len=materials.size(); imMaterials[i] = materials[i]; - } - - // Meshes - pScene->mMeshes = new aiMesh*[subMeshes.size()]; - pScene->mNumMeshes = subMeshes.size(); - - for(size_t i=0, len=subMeshes.size(); i submesh = subMeshes[i]; - pScene->mMeshes[i] = CreateAssimpSubMesh(pScene, *(submesh.get()), Bones); - } - - // Create the root node - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mMeshes = new unsigned int[subMeshes.size()]; - pScene->mRootNode->mNumMeshes = subMeshes.size(); - - for(size_t i=0, len=subMeshes.size(); imRootNode->mMeshes[i] = static_cast(i); - } - - // Skeleton and animations - CreateAssimpSkeleton(pScene, Bones, Animations); } } // Ogre diff --git a/code/OgreImporter.h b/code/OgreImporter.h index e40809073..892696407 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 @@ -12,58 +53,10 @@ namespace Assimp namespace Ogre { -struct Face; -struct BoneWeight; -struct Bone; -struct Animation; - -/// Ogre SubMesh -struct SubMesh -{ - bool UseSharedGeometry; - bool Use32bitIndexes; - - std::string Name; - std::string MaterialName; - - bool HasGeometry; - bool HasPositions; - bool HasNormals; - bool HasTangents; - - std::vector Faces; - std::vector Positions; - std::vector Normals; - std::vector Tangents; - - /// Arbitrary number of texcoords, they are nearly always 2d, but Assimp has always 3d texcoords, n vectors(outer) with texcoords for each vertex(inner). - std::vector > Uvs; - - /// A list(inner) of bones for each vertex(outer). - std::vector > Weights; - - /// The Index in the Assimp material array from the material witch is attached to this submesh. - int MaterialIndex; - - // The highest index of a bone from a bone weight, this is needed to create the Assimp bone struct. Converting from vertex-bones to bone-vertices. - unsigned int BonesUsed; - - SubMesh() : - UseSharedGeometry(false), - Use32bitIndexes(false), - HasGeometry(false), - HasPositions(false), - HasNormals(false), - HasTangents(false), - MaterialIndex(-1), - BonesUsed(0) - { - } -}; - /** Importer for Ogre mesh, skeleton and material formats. - @todo Support vertex colors - @todo Support multiple TexCoords (this is already done??) */ + @todo Support vertex colors. + @todo Support poses/animations from the mesh file. + Currently only skeleton file animations are supported. */ class OgreImporter : public BaseImporter { public: @@ -80,40 +73,11 @@ public: virtual void SetupProperties(const Importer *pImp); private: - //-------------------------------- OgreMesh.cpp ------------------------------- - - /// Helper Functions to read parts of the XML File. - void ReadSubMesh(const unsigned int submeshIndex, SubMesh &submesh, XmlReader *reader); - - /// Reads a single Vertexbuffer and writes its data in the Submesh. - static void ReadVertexBuffer(SubMesh &submesh, XmlReader *reader, const unsigned int numVertices); - - /// Reads bone weights are stores them into the given submesh. - static void ReadBoneWeights(SubMesh &submesh, XmlReader *reader); - - /// After Loading a SubMehs some work needs to be done (make all Vertexes unique, normalize weights). - static void ProcessSubMesh(SubMesh &submesh, SubMesh &sharedGeometry); - - /// Uses the bone data to convert a SubMesh into a aiMesh which will be created and returned. - aiMesh *CreateAssimpSubMesh(aiScene *pScene, const SubMesh &submesh, const std::vector &bones) const; - - //-------------------------------- OgreSkeleton.cpp ------------------------------- - - /// Writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it! - void ReadSkeleton(const std::string &pFile, Assimp::IOSystem *pIOHandler, const aiScene *pScene, - const std::string &skeletonFile, std::vector &Bones, std::vector &Animations) const; - - /// Converts the animations in aiAnimations and puts them into the scene. - void PutAnimationsInScene(aiScene *pScene, const std::vector &Bones, const std::vector &Animations); - - /// Creates the aiSkeleton in current scene. - void CreateAssimpSkeleton(aiScene *pScene, const std::vector &bones, const std::vector &animations); - - /// Recursively creates a filled aiNode from a given root bone. - static aiNode* CreateNodeFromBone(int boneId, const std::vector &bones, aiNode *parent); - - //-------------------------------- 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); + void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh); + void AssignMaterials(aiScene *pScene, std::vector &materials); + /// Reads material aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName); @@ -125,104 +89,8 @@ private: std::string m_userDefinedMaterialLibFile; bool m_detectTextureTypeFromFilename; - /// VertexBuffer for the sub meshes that use shader geometry. - SubMesh m_SharedGeometry; - std::map m_textures; }; - -/// Simplified face. -/** @todo Support other polygon types than just just triangles. Move to using aiFace. */ -struct Face -{ - unsigned int VertexIndices[3]; -}; - -/// Ogre Bone assignment -struct BoneAssignment -{ - /// Bone ID from Ogre. - unsigned int BoneId; - // Bone name for Assimp. - std::string BoneName; -}; - -/// Ogre Bone weight -struct BoneWeight -{ - /// Bone Id - unsigned int Id; - /// BoneWeight - float Value; -}; - - -/// Ogre Bone -struct Bone -{ - std::string Name; - - int Id; - int ParentId; - - aiVector3D Position; - aiVector3D RotationAxis; - float RotationAngle; - - aiMatrix4x4 BoneToWorldSpace; - - std::vector Children; - - Bone() : - Id(-1), - ParentId(-1), - RotationAngle(0.0f) - { - } - - /// Returns if this bone is parented. - bool IsParented() const { return (ParentId != -1); } - - /// This operator is needed to sort the bones by Id in a vector. - bool operator<(const Bone &other) const { return (Id < other.Id); } - - /// This operator is needed to find a bone by its name in a vector - bool operator==(const std::string& other) const { return Name == other; } - bool operator==(const aiString& other) const { return Name == std::string(other.data); } - - /// @note Implemented in OgreSkeleton.cpp - void CalculateBoneToWorldSpaceMatrix(std::vector& Bones); -}; - -/// Ogre animation key frame -/** Transformations for a frame. */ -struct KeyFrame -{ - float Time; - aiVector3D Position; - aiQuaternion Rotation; - aiVector3D Scaling; -}; - -/// Ogre animation track -/** Keyframes for one bone. */ -struct Track -{ - std::string BoneName; - std::vector Keyframes; -}; - -/// Ogre animation -struct Animation -{ - /// Name - std::string Name; - /// Length - float Length; - /// Tracks - std::vector Tracks; -}; - } // Ogre } // Assimp diff --git a/code/OgreMaterial.cpp b/code/OgreMaterial.cpp index b284dbb31..4ef4b44ec 100644 --- a/code/OgreMaterial.cpp +++ b/code/OgreMaterial.cpp @@ -42,12 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER -#include -#include - #include "OgreImporter.h" #include "TinyFormatter.h" +#include "fast_atof.h" + +#include +#include + using namespace std; namespace Assimp @@ -59,11 +61,66 @@ 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(); iGetSubMesh(i); + if (submesh && !submesh->materialRef.empty()) + { + aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef); + if (material) + { + submesh->materialIndex = materials.size(); + materials.push_back(material); + } + } + } + + AssignMaterials(pScene, materials); +} + +void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh) +{ + std::vector materials; + + // Create materials that can be found and parsed via the IOSystem. + for (size_t i=0, len=mesh->NumSubMeshes(); iGetSubMesh(i); + if (submesh && !submesh->materialRef.empty()) + { + aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef); + if (material) + { + submesh->materialIndex = materials.size(); + materials.push_back(material); + } + } + } + + AssignMaterials(pScene, materials); +} + +void OgreImporter::AssignMaterials(aiScene *pScene, std::vector &materials) +{ + 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 +174,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 @@ -162,8 +217,7 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste // Skip commented lines if (linePart == partComment) { - string postComment = NextAfterNewLine(ss, linePart); - DefaultLogger::get()->debug("//" + postComment + " (comment line ignored)"); + NextAfterNewLine(ss, linePart); continue; } if (linePart != partMaterial) @@ -306,8 +360,7 @@ bool OgreImporter::ReadTechnique(const std::string &techniqueName, stringstream // Skip commented lines if (linePart == partComment) { - string postComment = SkipLine(ss); - DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)"); + SkipLine(ss); continue; } @@ -347,8 +400,7 @@ bool OgreImporter::ReadPass(const std::string &passName, stringstream &ss, aiMat // Skip commented lines if (linePart == partComment) { - string postComment = SkipLine(ss); - DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)"); + SkipLine(ss); continue; } @@ -416,8 +468,7 @@ bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstr // Skip commented lines if (linePart == partComment) { - string postComment = SkipLine(ss); - DefaultLogger::get()->debug(" //" + postComment + " (comment line ignored)"); + SkipLine(ss); continue; } diff --git a/code/OgreMesh.cpp b/code/OgreMesh.cpp deleted file mode 100644 index ff481b1b4..000000000 --- a/code/OgreMesh.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* -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 "AssimpPCH.h" - -#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER - -#include "OgreImporter.h" -#include "TinyFormatter.h" - -using namespace std; - -namespace Assimp -{ -namespace Ogre -{ - -void OgreImporter::ReadSubMesh(const unsigned int submeshIndex, SubMesh &submesh, XmlReader *reader) -{ - if (reader->getAttributeValue("material")) { - submesh.MaterialName = GetAttribute(reader, "material"); - } - if (reader->getAttributeValue("use32bitindexes")) { - submesh.Use32bitIndexes = GetAttribute(reader, "use32bitindexes"); - } - if (reader->getAttributeValue("usesharedvertices")) { - submesh.UseSharedGeometry = GetAttribute(reader, "usesharedvertices"); - } - - DefaultLogger::get()->debug(Formatter::format() << "Reading submesh " << submeshIndex); - DefaultLogger::get()->debug(Formatter::format() << " - Material '" << submesh.MaterialName << "'"); - DefaultLogger::get()->debug(Formatter::format() << " - Shader geometry = " << (submesh.UseSharedGeometry ? "true" : "false") << - ", 32bit indexes = " << (submesh.Use32bitIndexes ? "true" : "false")); - - //TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order - //of faces and geometry changed, and not if we have more than one of one - /// @todo Fix above comment with better read logic below - - NextNode(reader); - string currentNodeName = reader->getNodeName(); - - const string nnFaces = "faces"; - const string nnFace = "face"; - const string nnGeometry = "geometry"; - const string nnBoneAssignments = "boneassignments"; - const string nnVertexBuffer = "vertexbuffer"; - - bool quadWarned = false; - - while(currentNodeName == nnFaces || - currentNodeName == nnGeometry || - currentNodeName == nnBoneAssignments) - { - if (currentNodeName == nnFaces) - { - unsigned int numFaces = GetAttribute(reader, "count"); - - NextNode(reader); - currentNodeName = reader->getNodeName(); - - while(currentNodeName == nnFace) - { - Face NewFace; - NewFace.VertexIndices[0] = GetAttribute(reader, "v1"); - NewFace.VertexIndices[1] = GetAttribute(reader, "v2"); - NewFace.VertexIndices[2] = GetAttribute(reader, "v3"); - - /// @todo Support quads - if (!quadWarned && reader->getAttributeValue("v4")) { - DefaultLogger::get()->warn("Submesh has quads, only triangles are supported at the moment!"); - } - - submesh.Faces.push_back(NewFace); - - // Advance - NextNode(reader); - currentNodeName = reader->getNodeName(); - } - - if (submesh.Faces.size() == numFaces) - { - DefaultLogger::get()->debug(Formatter::format() << " - Faces " << numFaces); - } - else - { - throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Faces.size() << " faces when should have read " << numFaces); - } - } - else if (currentNodeName == nnGeometry) - { - unsigned int numVertices = GetAttribute(reader, "vertexcount"); - - NextNode(reader); - while(string(reader->getNodeName()) == nnVertexBuffer) { - ReadVertexBuffer(submesh, reader, numVertices); - } - } - else if (reader->getNodeName() == nnBoneAssignments) - { - ReadBoneWeights(submesh, reader); - } - - currentNodeName = reader->getNodeName(); - } -} - -void OgreImporter::ReadVertexBuffer(SubMesh &submesh, XmlReader *reader, const unsigned int numVertices) -{ - DefaultLogger::get()->debug(Formatter::format() << "Reading vertex buffer with " << numVertices << " vertices"); - - submesh.HasGeometry = true; - - if (reader->getAttributeValue("positions") && GetAttribute(reader, "positions")) - { - submesh.HasPositions = true; - submesh.Positions.reserve(numVertices); - DefaultLogger::get()->debug(" - Has positions"); - } - if (reader->getAttributeValue("normals") && GetAttribute(reader, "normals")) - { - submesh.HasNormals = true; - submesh.Normals.reserve(numVertices); - DefaultLogger::get()->debug(" - Has normals"); - } - if (reader->getAttributeValue("tangents") && GetAttribute(reader, "tangents")) - { - submesh.HasTangents = true; - submesh.Tangents.reserve(numVertices); - DefaultLogger::get()->debug(" - Has tangents"); - } - if (reader->getAttributeValue("texture_coords")) - { - submesh.Uvs.resize(GetAttribute(reader, "texture_coords")); - for(size_t i=0, len=submesh.Uvs.size(); idebug(Formatter::format() << " - Has " << submesh.Uvs.size() << " texture coords"); - } - - if (!submesh.HasPositions) { - throw DeadlyImportError("Vertex buffer does not contain positions!"); - } - - const string nnVertex = "vertex"; - const string nnPosition = "position"; - const string nnNormal = "normal"; - const string nnTangent = "tangent"; - const string nnBinormal = "binormal"; - const string nnTexCoord = "texcoord"; - const string nnColorDiffuse = "colour_diffuse"; - const string nnColorSpecular = "colour_specular"; - - bool warnBinormal = true; - bool warnColorDiffuse = true; - bool warnColorSpecular = true; - - NextNode(reader); - string currentNodeName = reader->getNodeName(); - - /// @todo Make this loop nicer. - while(currentNodeName == nnVertex || - currentNodeName == nnPosition || - currentNodeName == nnNormal || - currentNodeName == nnTangent || - currentNodeName == nnBinormal || - currentNodeName == nnTexCoord || - currentNodeName == nnColorDiffuse || - currentNodeName == nnColorSpecular) - { - if (currentNodeName == nnVertex) - { - NextNode(reader); - currentNodeName = reader->getNodeName(); - } - - /// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular - - if (submesh.HasPositions && currentNodeName == nnPosition) - { - aiVector3D NewPos; - NewPos.x = GetAttribute(reader, "x"); - NewPos.y = GetAttribute(reader, "y"); - NewPos.z = GetAttribute(reader, "z"); - submesh.Positions.push_back(NewPos); - } - else if (submesh.HasNormals && currentNodeName == nnNormal) - { - aiVector3D NewNormal; - NewNormal.x = GetAttribute(reader, "x"); - NewNormal.y = GetAttribute(reader, "y"); - NewNormal.z = GetAttribute(reader, "z"); - submesh.Normals.push_back(NewNormal); - } - else if (submesh.HasTangents && currentNodeName == nnTangent) - { - aiVector3D NewTangent; - NewTangent.x = GetAttribute(reader, "x"); - NewTangent.y = GetAttribute(reader, "y"); - NewTangent.z = GetAttribute(reader, "z"); - submesh.Tangents.push_back(NewTangent); - } - else if (submesh.Uvs.size() > 0 && currentNodeName == nnTexCoord) - { - for(size_t i=0, len=submesh.Uvs.size(); i(reader, "u"); - NewUv.y = GetAttribute(reader, "v") * (-1)+1; //flip the uv vertikal, blender exports them so! (ahem... @todo ????) - submesh.Uvs[i].push_back(NewUv); - - NextNode(reader); - currentNodeName = reader->getNodeName(); - } - // Continue main loop as above already read next node - continue; - } - else - { - /// @todo Remove this stuff once implemented. We only want to log warnings once per element. - bool warn = true; - if (currentNodeName == nnBinormal) - { - if (warnBinormal) - { - warnBinormal = false; - } - else - { - warn = false; - } - } - else if (currentNodeName == nnColorDiffuse) - { - if (warnColorDiffuse) - { - warnColorDiffuse = false; - } - else - { - warn = false; - } - } - else if (currentNodeName == nnColorSpecular) - { - if (warnColorSpecular) - { - warnColorSpecular = false; - } - else - { - warn = false; - } - } - if (warn) { - DefaultLogger::get()->warn(string("Vertex buffer attribute read not implemented for element: ") + currentNodeName); - } - } - - // Advance - NextNode(reader); - currentNodeName = reader->getNodeName(); - } - - DefaultLogger::get()->debug(Formatter::format() << - " - Positions " << submesh.Positions.size() << - " Normals " << submesh.Normals.size() << - " TexCoords " << submesh.Uvs.size() << - " Tangents " << submesh.Tangents.size()); - - // Sanity checks - if (submesh.HasNormals && submesh.Normals.size() != numVertices) { - throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Normals.size() << " normals when should have read " << numVertices); - } - if (submesh.HasTangents && submesh.Tangents.size() != numVertices) { - throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Tangents.size() << " tangents when should have read " << numVertices); - } - for(unsigned int i=0; i(reader, "boneindex"); - weight.Value = GetAttribute(reader, "weight"); - - //calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0) - /// @todo This can probably be refactored to something else. - submesh.BonesUsed = max(submesh.BonesUsed, weight.Id+1); - - const unsigned int vertexId = GetAttribute(reader, "vertexindex"); - submesh.Weights[vertexId].push_back(weight); - - NextNode(reader); - } - DefaultLogger::get()->debug(Formatter::format() << " - Bone weights " << numRead); -} - -void OgreImporter::ProcessSubMesh(SubMesh &submesh, SubMesh &sharedGeometry) -{ - // Make all vertexes unique. Required by Assimp. - vector uniqueFaceList(submesh.Faces.size()); - unsigned int uniqueVertexCount = submesh.Faces.size() * 3; - - vector uniquePositions(uniqueVertexCount); - vector uniqueNormals(uniqueVertexCount); - vector uniqueTangents(uniqueVertexCount); - - vector > uniqueWeights(uniqueVertexCount); - vector > uniqueUvs(submesh.UseSharedGeometry ? sharedGeometry.Uvs.size() : submesh.Uvs.size()); - - for(size_t uvi=0; uvi &uv = vertexSource.Uvs[uvi]; - uniqueUvs[uvi][pos] = uv[v1]; - uniqueUvs[uvi][pos+1] = uv[v2]; - uniqueUvs[uvi][pos+2] = uv[v3]; - } - - if (!vertexSource.Weights.empty()) - { - uniqueWeights[pos] = vertexSource.Weights[v1]; - uniqueWeights[pos+1] = vertexSource.Weights[v2]; - uniqueWeights[pos+2] = vertexSource.Weights[v3]; - } - } - - // Now we have the unique data, but want them in the SubMesh, so we swap all the containers. - // If we don't have one of them, we just swap empty containers, so everything is ok. - submesh.Faces.swap(uniqueFaceList); - submesh.Positions.swap(uniquePositions); - submesh.Normals.swap(uniqueNormals); - submesh.Tangents.swap(uniqueTangents); - submesh.Uvs.swap(uniqueUvs); - submesh.Weights.swap(uniqueWeights); - - // Normalize bone weights - // For example the Blender exporter doesn't care about whether the sum of all bone - // weights for a single vertex equals 1 or not, so validate here. - for(size_t vertexId=0, wlen=submesh.Weights.size(); vertexId &weights = submesh.Weights[vertexId]; - - float sum = 0.0f; - for(size_t boneId=0, blen=weights.size(); boneId (1.0f + 0.05f))) - { - for(size_t boneId=0, blen=weights.size(); boneId& bones) const -{ - const size_t sizeVector3D = sizeof(aiVector3D); - - aiMesh *dest = new aiMesh(); - - // Material - dest->mMaterialIndex = submesh.MaterialIndex; - - // Positions - dest->mVertices = new aiVector3D[submesh.Positions.size()]; - dest->mNumVertices = submesh.Positions.size(); - memcpy(dest->mVertices, &submesh.Positions[0], submesh.Positions.size() * sizeVector3D); - - // Normals - if (submesh.HasNormals) - { - dest->mNormals = new aiVector3D[submesh.Normals.size()]; - memcpy(dest->mNormals, &submesh.Normals[0], submesh.Normals.size() * sizeVector3D); - } - - // Tangents - // Until we have support for bitangents, no tangents will be written - /// @todo Investigate why the above? - if (submesh.HasTangents) - { - DefaultLogger::get()->warn("Tangents found from Ogre mesh but writing to Assimp mesh not yet supported!"); - //dest->mTangents = new aiVector3D[submesh.Tangents.size()]; - //memcpy(dest->mTangents, &submesh.Tangents[0], submesh.Tangents.size() * sizeVector3D); - } - - // UVs - for (size_t i=0, len=submesh.Uvs.size(); imNumUVComponents[i] = 2; - dest->mTextureCoords[i] = new aiVector3D[submesh.Uvs[i].size()]; - memcpy(dest->mTextureCoords[i], &(submesh.Uvs[i][0]), submesh.Uvs[i].size() * sizeVector3D); - } - - // Bone weights. Convert internal vertex-to-bone mapping to bone-to-vertex. - vector > assimpWeights(submesh.BonesUsed); - for(size_t vertexId=0, len=submesh.Weights.size(); vertexId &vertexWeights = submesh.Weights[vertexId]; - for (size_t boneId=0, len=vertexWeights.size(); boneId assimpBones; - assimpBones.reserve(submesh.BonesUsed); - - for(size_t boneId=0, len=submesh.BonesUsed; boneId &boneWeights = assimpWeights[boneId]; - if (boneWeights.size() == 0) { - continue; - } - - // @note The bones list is sorted by id's, this was done in LoadSkeleton. - aiBone *assimpBone = new aiBone(); - assimpBone->mName = bones[boneId].Name; - assimpBone->mOffsetMatrix = bones[boneId].BoneToWorldSpace; - assimpBone->mNumWeights = boneWeights.size(); - assimpBone->mWeights = new aiVertexWeight[boneWeights.size()]; - memcpy(assimpBone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight)); - - assimpBones.push_back(assimpBone); - } - - if (!assimpBones.empty()) - { - dest->mBones = new aiBone*[assimpBones.size()]; - dest->mNumBones = assimpBones.size(); - - for(size_t i=0, len=assimpBones.size(); imBones[i] = assimpBones[i]; - } - } - - // Faces - dest->mFaces = new aiFace[submesh.Faces.size()]; - dest->mNumFaces = submesh.Faces.size(); - - for(size_t i=0, len=submesh.Faces.size(); imFaces[i].mNumIndices = 3; - dest->mFaces[i].mIndices = new unsigned int[3]; - - const Face &f = submesh.Faces[i]; - dest->mFaces[i].mIndices[0] = f.VertexIndices[0]; - dest->mFaces[i].mIndices[1] = f.VertexIndices[1]; - dest->mFaces[i].mIndices[2] = f.VertexIndices[2]; - } - - return dest; -} - -} // Ogre -} // Assimp - -#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreParsingUtils.h b/code/OgreParsingUtils.h index ac1e58173..d3a7aa8bf 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 @@ -5,144 +44,13 @@ #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER #include "ParsingUtils.h" -#include "irrXMLWrapper.h" -#include "fast_atof.h" #include + namespace Assimp { namespace Ogre { -typedef irr::io::IrrXMLReader XmlReader; - -static void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") -{ - if (!error.empty()) - { - throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); - } - else - { - throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); - } -} - -template -inline T GetAttribute(const XmlReader* reader, const std::string &name); - -template<> -inline int GetAttribute(const XmlReader* reader, const std::string &name) -{ - const char* value = reader->getAttributeValue(name.c_str()); - if (value) - { - return atoi(value); - } - else - { - ThrowAttibuteError(reader, name); - return 0; - } -} - -template<> -inline unsigned int GetAttribute(const XmlReader* reader, const std::string &name) -{ - const char* value = reader->getAttributeValue(name.c_str()); - if (value) - { - return static_cast(atoi(value)); ///< @todo Find a better way... - } - else - { - ThrowAttibuteError(reader, name); - return 0; - } -} - -template<> -inline float GetAttribute(const XmlReader* reader, const std::string &name) -{ - const char* value = reader->getAttributeValue(name.c_str()); - if (value) - { - return fast_atof(value); - } - else - { - ThrowAttibuteError(reader, name); - return 0.f; - } -} - -template<> -inline std::string GetAttribute(const XmlReader* reader, const std::string &name) -{ - const char* value = reader->getAttributeValue(name.c_str()); - if (value) - { - return std::string(value); - } - else - { - ThrowAttibuteError(reader, name); - return ""; - } -} - -template<> -inline bool GetAttribute(const XmlReader* reader, const std::string &name) -{ - std::string value = GetAttribute(reader, name); - if (ASSIMP_stricmp(value, "true") == 0) - { - return true; - } - else if (ASSIMP_stricmp(value, "false") == 0) - { - return false; - } - else - { - ThrowAttibuteError(reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'"); - return false; - } -} - -inline bool NextNode(XmlReader* reader) -{ - do - { - if (!reader->read()) { - return false; - } - } - while(reader->getNodeType() != irr::io::EXN_ELEMENT); - return true; -} - -inline bool CurrentNodeNameEquals(const XmlReader* reader, const std::string &name) -{ - return (ASSIMP_stricmp(std::string(reader->getNodeName()), name) == 0); -} - -/// Skips a line from current @ss position until a newline. Returns the skipped part. -static inline std::string SkipLine(std::stringstream &ss) -{ - std::string skipped; - getline(ss, skipped); - return skipped; -} - -/// Skips a line and reads next element from @c ss to @c nextElement. -/** @return Skipped line content until newline. */ -static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) -{ - std::string skipped = SkipLine(ss); - ss >> nextElement; - return skipped; -} - /// Returns a lower cased copy of @s. static inline std::string ToLower(std::string s) { @@ -207,6 +115,23 @@ static inline std::string &Trim(std::string &s, bool newlines = true) return TrimLeft(TrimRight(s, newlines), newlines); } +/// Skips a line from current @ss position until a newline. Returns the skipped part. +static inline std::string SkipLine(std::stringstream &ss) +{ + std::string skipped; + getline(ss, skipped); + return skipped; +} + +/// Skips a line and reads next element from @c ss to @c nextElement. +/** @return Skipped line content until newline. */ +static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) +{ + std::string skipped = SkipLine(ss); + ss >> nextElement; + return skipped; +} + } // Ogre } // Assimp diff --git a/code/OgreSkeleton.cpp b/code/OgreSkeleton.cpp deleted file mode 100644 index 3f0b7abb1..000000000 --- a/code/OgreSkeleton.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* -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, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of aSource 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 "AssimpPCH.h" - -#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER - -#include "OgreImporter.h" -#include "TinyFormatter.h" - -using namespace std; - -namespace Assimp -{ -namespace Ogre -{ - -void OgreImporter::ReadSkeleton(const std::string &pFile, Assimp::IOSystem *pIOHandler, const aiScene *pScene, - const std::string &skeletonFile, vector &Bones, vector &Animations) const -{ - string filename = skeletonFile; - 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."); - filename += ".xml"; - } - - if (!pIOHandler->Exists(filename)) - { - DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "', skeleton will be missing."); - return; - } - - boost::scoped_ptr file(pIOHandler->Open(filename)); - if (!file.get()) { - throw DeadlyImportError("Failed to open skeleton file " + filename); - } - - boost::scoped_ptr stream(new CIrrXML_IOStreamReader(file.get())); - XmlReader* reader = irr::io::createIrrXMLReader(stream.get()); - if (!reader) { - throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); - } - - DefaultLogger::get()->debug("Reading skeleton '" + filename + "'"); - - // Root - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "skeleton")) { - throw DeadlyImportError("Root node is not but <" + string(reader->getNodeName()) + "> in " + filename); - } - - // Bones - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "bones")) { - throw DeadlyImportError("No node in skeleton " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "bone")) - { - /** @todo Fix this mandatory ordering. Some exporters might just write rotation first etc. - There is no technical reason this has to be so strict. */ - - Bone bone; - bone.Id = GetAttribute(reader, "id"); - bone.Name = GetAttribute(reader, "name"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "position")) { - throw DeadlyImportError("Position is not first node in Bone!"); - } - - bone.Position.x = GetAttribute(reader, "x"); - bone.Position.y = GetAttribute(reader, "y"); - bone.Position.z = GetAttribute(reader, "z"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "rotation")) { - throw DeadlyImportError("Rotation is not the second node in Bone!"); - } - - bone.RotationAngle = GetAttribute(reader, "angle"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "axis")) { - throw DeadlyImportError("No axis specified for bone rotation!"); - } - - bone.RotationAxis.x = GetAttribute(reader, "x"); - bone.RotationAxis.y = GetAttribute(reader, "y"); - bone.RotationAxis.z = GetAttribute(reader, "z"); - - Bones.push_back(bone); - - NextNode(reader); - } - - // Order bones by Id - std::sort(Bones.begin(), Bones.end()); - - // Validate that bone indexes are not skipped. - /** @note Left this from original authors code, but not sure if this is strictly necessary - as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */ - for (size_t i=0, len=Bones.size(); i(Bones[i].Id) != static_cast(i)) { - throw DeadlyImportError("Bone Ids are not in sequence in " + skeletonFile); - } - } - - DefaultLogger::get()->debug(Formatter::format() << " - Bones " << Bones.size()); - - // Bone hierarchy - if (!CurrentNodeNameEquals(reader, "bonehierarchy")) { - throw DeadlyImportError("No node found after in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "boneparent")) - { - string childName = GetAttribute(reader, "bone"); - string parentName = GetAttribute(reader, "parent"); - - vector::iterator iterChild = find(Bones.begin(), Bones.end(), childName); - vector::iterator iterParent = find(Bones.begin(), Bones.end(), parentName); - - if (iterChild != Bones.end() && iterParent != Bones.end()) - { - iterChild->ParentId = iterParent->Id; - iterParent->Children.push_back(iterChild->Id); - } - else - { - DefaultLogger::get()->warn("Failed to find bones for parenting: Child " + childName + " Parent " + parentName); - } - - NextNode(reader); - } - - // Calculate bone matrices for root bones. Recursively does their children. - BOOST_FOREACH(Bone &theBone, Bones) - { - if (!theBone.IsParented()) { - theBone.CalculateBoneToWorldSpaceMatrix(Bones); - } - } - - aiVector3D zeroVec(0.f, 0.f, 0.f); - - // Animations - if (CurrentNodeNameEquals(reader, "animations")) - { - DefaultLogger::get()->debug(" - Animations"); - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "animation")) - { - Animation animation; - animation.Name = GetAttribute(reader, "name"); - animation.Length = GetAttribute(reader, "length"); - - // Tracks - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "tracks")) { - throw DeadlyImportError("No node found in animation '" + animation.Name + "' in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "track")) - { - Track track; - track.BoneName = GetAttribute(reader, "bone"); - - // Keyframes - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "keyframes")) { - throw DeadlyImportError("No node found in a track in animation '" + animation.Name + "' in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "keyframe")) - { - KeyFrame keyFrame; - keyFrame.Time = GetAttribute(reader, "time"); - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "translate") || CurrentNodeNameEquals(reader, "rotate") || CurrentNodeNameEquals(reader, "scale")) - { - if (CurrentNodeNameEquals(reader, "translate")) - { - keyFrame.Position.x = GetAttribute(reader, "x"); - keyFrame.Position.y = GetAttribute(reader, "y"); - keyFrame.Position.z = GetAttribute(reader, "z"); - } - else if (CurrentNodeNameEquals(reader, "rotate")) - { - float angle = GetAttribute(reader, "angle"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "axis")) { - throw DeadlyImportError("No axis for keyframe rotation in animation '" + animation.Name + "'"); - } - - aiVector3D axis; - axis.x = GetAttribute(reader, "x"); - axis.y = GetAttribute(reader, "y"); - axis.z = GetAttribute(reader, "z"); - - if (axis.Equal(zeroVec)) - { - axis.x = 1.0f; - if (angle != 0) { - DefaultLogger::get()->warn("Found invalid a key frame with a zero rotation axis in animation '" + animation.Name + "'"); - } - } - keyFrame.Rotation = aiQuaternion(axis, angle); - } - else if (CurrentNodeNameEquals(reader, "scale")) - { - keyFrame.Scaling.x = GetAttribute(reader, "x"); - keyFrame.Scaling.y = GetAttribute(reader, "y"); - keyFrame.Scaling.z = GetAttribute(reader, "z"); - } - NextNode(reader); - } - track.Keyframes.push_back(keyFrame); - } - animation.Tracks.push_back(track); - } - Animations.push_back(animation); - - DefaultLogger::get()->debug(Formatter::format() << " " << animation.Name << " (" << animation.Length << " sec, " << animation.Tracks.size() << " tracks)"); - } - } -} - -void OgreImporter::CreateAssimpSkeleton(aiScene *pScene, const std::vector &bones, const std::vector &animations) -{ - if (bones.empty()) { - return; - } - - if (!pScene->mRootNode) { - throw DeadlyImportError("Creating Assimp skeleton: No root node created!"); - } - if (pScene->mRootNode->mNumChildren > 0) { - throw DeadlyImportError("Creating Assimp skeleton: Root node already has children!"); - } - - // Bones - vector rootBones; - BOOST_FOREACH(const Bone &bone, bones) - { - if (!bone.IsParented()) { - rootBones.push_back(CreateNodeFromBone(bone.Id, bones, pScene->mRootNode)); - } - } - - if (!rootBones.empty()) - { - pScene->mRootNode->mChildren = new aiNode*[rootBones.size()]; - pScene->mRootNode->mNumChildren = rootBones.size(); - - for(size_t i=0, len=rootBones.size(); imRootNode->mChildren[i] = rootBones[i]; - } - } - - // TODO: Auf nicht vorhandene Animationskeys achten! - // @todo Pay attention to non-existing animation Keys (google translated from above german comment) - - // Animations - if (!animations.empty()) - { - pScene->mAnimations = new aiAnimation*[animations.size()]; - pScene->mNumAnimations = animations.size(); - - for(size_t ai=0, alen=animations.size(); aimName = aSource.Name; - animation->mDuration = aSource.Length; - animation->mTicksPerSecond = 1.0f; - - // Tracks - animation->mChannels = new aiNodeAnim*[aSource.Tracks.size()]; - animation->mNumChannels = aSource.Tracks.size(); - - for(size_t ti=0, tlen=aSource.Tracks.size(); timNodeName = tSource.BoneName; - - // We need this, to access the bones default pose. - // Which we need to make keys absolute to the default bone pose. - vector::const_iterator boneIter = find(bones.begin(), bones.end(), tSource.BoneName); - if (boneIter == bones.end()) - { - for(size_t createdAnimationIndex=0; createdAnimationIndexmAnimations[createdAnimationIndex]; - } - delete [] pScene->mAnimations; - pScene->mAnimations = NULL; - pScene->mNumAnimations = 0; - - DefaultLogger::get()->error("Failed to find bone for name " + tSource.BoneName + " when creating animation " + aSource.Name + - ". This is a serious error, animations wont be imported."); - return; - } - - aiMatrix4x4 t0, t1; - aiMatrix4x4 defaultBonePose = aiMatrix4x4::Translation(boneIter->Position, t1) * aiMatrix4x4::Rotation(boneIter->RotationAngle, boneIter->RotationAxis, t0); - - // Keyframes - unsigned int numKeyframes = tSource.Keyframes.size(); - - animationNode->mPositionKeys = new aiVectorKey[numKeyframes]; - animationNode->mRotationKeys = new aiQuatKey[numKeyframes]; - animationNode->mScalingKeys = new aiVectorKey[numKeyframes]; - animationNode->mNumPositionKeys = numKeyframes; - animationNode->mNumRotationKeys = numKeyframes; - animationNode->mNumScalingKeys = numKeyframes; - - //...and fill them - for(size_t kfi=0; kfimPositionKeys[kfi].mTime = static_cast(kfSource.Time); - animationNode->mRotationKeys[kfi].mTime = static_cast(kfSource.Time); - animationNode->mScalingKeys[kfi].mTime = static_cast(kfSource.Time); - - animationNode->mPositionKeys[kfi].mValue = kfPos; - animationNode->mRotationKeys[kfi].mValue = kfRot; - animationNode->mScalingKeys[kfi].mValue = kfScale; - } - animation->mChannels[ti] = animationNode; - } - pScene->mAnimations[ai] = animation; - } - } -} - -aiNode* OgreImporter::CreateNodeFromBone(int boneId, const std::vector &bones, aiNode* parent) -{ - aiMatrix4x4 t0,t1; - const Bone &source = bones[boneId]; - - aiNode* boneNode = new aiNode(source.Name); - boneNode->mParent = parent; - boneNode->mTransformation = aiMatrix4x4::Translation(source.Position, t0) * aiMatrix4x4::Rotation(source.RotationAngle, source.RotationAxis, t1); - - if (!source.Children.empty()) - { - boneNode->mChildren = new aiNode*[source.Children.size()]; - boneNode->mNumChildren = source.Children.size(); - - for(size_t i=0, len=source.Children.size(); imChildren[i] = CreateNodeFromBone(source.Children[i], bones, boneNode); - } - } - - return boneNode; -} - -void Bone::CalculateBoneToWorldSpaceMatrix(vector &Bones) -{ - aiMatrix4x4 t0, t1; - aiMatrix4x4 transform = aiMatrix4x4::Rotation(-RotationAngle, RotationAxis, t1) * aiMatrix4x4::Translation(-Position, t0); - - if (!IsParented()) - { - BoneToWorldSpace = transform; - } - else - { - BoneToWorldSpace = transform * Bones[ParentId].BoneToWorldSpace; - } - - // Recursively for all children now that the parent matrix has been calculated. - BOOST_FOREACH(int childId, Children) - { - Bones[childId].CalculateBoneToWorldSpaceMatrix(Bones); - } -} - -} // Ogre -} // Assimp - -#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreStructs.cpp b/code/OgreStructs.cpp new file mode 100644 index 000000000..cfedc2320 --- /dev/null +++ b/code/OgreStructs.cpp @@ -0,0 +1,1193 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "OgreStructs.h" +#include "TinyFormatter.h" + +namespace Assimp +{ +namespace Ogre +{ + +// VertexElement + +VertexElement::VertexElement() : + index(0), + source(0), + offset(0), + type(VET_FLOAT1), + semantic(VES_POSITION) +{ +} + +size_t VertexElement::Size() const +{ + return TypeSize(type); +} + +size_t VertexElement::ComponentCount() const +{ + return ComponentCount(type); +} + +size_t VertexElement::ComponentCount(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + case VET_FLOAT1: + case VET_DOUBLE1: + case VET_SHORT1: + case VET_USHORT1: + case VET_INT1: + case VET_UINT1: + return 1; + case VET_FLOAT2: + case VET_DOUBLE2: + case VET_SHORT2: + case VET_USHORT2: + case VET_INT2: + case VET_UINT2: + return 2; + case VET_FLOAT3: + case VET_DOUBLE3: + case VET_SHORT3: + case VET_USHORT3: + case VET_INT3: + case VET_UINT3: + return 3; + case VET_FLOAT4: + case VET_DOUBLE4: + case VET_SHORT4: + case VET_USHORT4: + case VET_INT4: + case VET_UINT4: + case VET_UBYTE4: + return 4; + } + return 0; +} + +size_t VertexElement::TypeSize(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + return sizeof(unsigned int); + case VET_FLOAT1: + return sizeof(float); + case VET_FLOAT2: + return sizeof(float)*2; + case VET_FLOAT3: + return sizeof(float)*3; + case VET_FLOAT4: + return sizeof(float)*4; + case VET_DOUBLE1: + return sizeof(double); + case VET_DOUBLE2: + return sizeof(double)*2; + case VET_DOUBLE3: + return sizeof(double)*3; + case VET_DOUBLE4: + return sizeof(double)*4; + case VET_SHORT1: + return sizeof(short); + case VET_SHORT2: + return sizeof(short)*2; + case VET_SHORT3: + return sizeof(short)*3; + case VET_SHORT4: + return sizeof(short)*4; + case VET_USHORT1: + return sizeof(unsigned short); + case VET_USHORT2: + return sizeof(unsigned short)*2; + case VET_USHORT3: + return sizeof(unsigned short)*3; + case VET_USHORT4: + return sizeof(unsigned short)*4; + case VET_INT1: + return sizeof(int); + case VET_INT2: + return sizeof(int)*2; + case VET_INT3: + return sizeof(int)*3; + case VET_INT4: + return sizeof(int)*4; + case VET_UINT1: + return sizeof(unsigned int); + case VET_UINT2: + return sizeof(unsigned int)*2; + case VET_UINT3: + return sizeof(unsigned int)*3; + case VET_UINT4: + return sizeof(unsigned int)*4; + case VET_UBYTE4: + return sizeof(unsigned char)*4; + } + return 0; +} + +std::string VertexElement::TypeToString() +{ + return TypeToString(type); +} + +std::string VertexElement::TypeToString(Type type) +{ + switch(type) + { + case VET_COLOUR: return "COLOUR"; + case VET_COLOUR_ABGR: return "COLOUR_ABGR"; + case VET_COLOUR_ARGB: return "COLOUR_ARGB"; + case VET_FLOAT1: return "FLOAT1"; + case VET_FLOAT2: return "FLOAT2"; + case VET_FLOAT3: return "FLOAT3"; + case VET_FLOAT4: return "FLOAT4"; + case VET_DOUBLE1: return "DOUBLE1"; + case VET_DOUBLE2: return "DOUBLE2"; + case VET_DOUBLE3: return "DOUBLE3"; + case VET_DOUBLE4: return "DOUBLE4"; + case VET_SHORT1: return "SHORT1"; + case VET_SHORT2: return "SHORT2"; + case VET_SHORT3: return "SHORT3"; + case VET_SHORT4: return "SHORT4"; + case VET_USHORT1: return "USHORT1"; + case VET_USHORT2: return "USHORT2"; + case VET_USHORT3: return "USHORT3"; + case VET_USHORT4: return "USHORT4"; + case VET_INT1: return "INT1"; + case VET_INT2: return "INT2"; + case VET_INT3: return "INT3"; + case VET_INT4: return "INT4"; + case VET_UINT1: return "UINT1"; + case VET_UINT2: return "UINT2"; + case VET_UINT3: return "UINT3"; + case VET_UINT4: return "UINT4"; + case VET_UBYTE4: return "UBYTE4"; + } + return "Uknown_VertexElement::Type"; +} + +std::string VertexElement::SemanticToString() +{ + return SemanticToString(semantic); +} + +std::string VertexElement::SemanticToString(Semantic semantic) +{ + switch(semantic) + { + case VES_POSITION: return "POSITION"; + case VES_BLEND_WEIGHTS: return "BLEND_WEIGHTS"; + case VES_BLEND_INDICES: return "BLEND_INDICES"; + case VES_NORMAL: return "NORMAL"; + case VES_DIFFUSE: return "DIFFUSE"; + case VES_SPECULAR: return "SPECULAR"; + case VES_TEXTURE_COORDINATES: return "TEXTURE_COORDINATES"; + case VES_BINORMAL: return "BINORMAL"; + case VES_TANGENT: return "TANGENT"; + } + return "Uknown_VertexElement::Semantic"; +} + +// IVertexData + +IVertexData::IVertexData() : + count(0) +{ +} + +bool IVertexData::HasBoneAssignments() const +{ + return !boneAssignments.empty(); +} + +void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex) +{ + BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]); + vertexIndexMapping[oldIndex].push_back(newIndex); +} + +void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const +{ + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + if (iter->vertexIndex == currentIndex) + { + VertexBoneAssignment a = (*iter); + a.vertexIndex = newIndex; + dest.push_back(a); + } + } +} + +AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices) +{ + AssimpVertexBoneWeightList weights; + for(size_t vi=0; vi &boneWeights = weights[iter->boneIndex]; + boneWeights.push_back(aiVertexWeight(vi, iter->weight)); + } + } + return weights; +} + +std::set IVertexData::ReferencedBonesByWeights() const +{ + std::set referenced; + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + referenced.insert(iter->boneIndex); + } + return referenced; +} + +// VertexData + +VertexData::VertexData() +{ +} + +VertexData::~VertexData() +{ + Reset(); +} + +void VertexData::Reset() +{ + // Releases shared ptr memory streams. + vertexBindings.clear(); + vertexElements.clear(); +} + +uint32_t VertexData::VertexSize(uint16_t source) const +{ + uint32_t size = 0; + for(VertexElementList::const_iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + if (iter->source == source) + size += iter->Size(); + } + return size; +} + +MemoryStream *VertexData::VertexBuffer(uint16_t source) +{ + if (vertexBindings.find(source) != vertexBindings.end()) + return vertexBindings[source]; + return 0; +} + +VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index) +{ + for(VertexElementList::iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + VertexElement &element = (*iter); + if (element.semantic == semantic && element.index == index) + return &element; + } + return 0; +} + +// VertexDataXml + +VertexDataXml::VertexDataXml() +{ +} + +bool VertexDataXml::HasPositions() const +{ + return !positions.empty(); +} + +bool VertexDataXml::HasNormals() const +{ + return !normals.empty(); +} + +bool VertexDataXml::HasTangents() const +{ + return !tangents.empty(); +} + +bool VertexDataXml::HasUvs() const +{ + return !uvs.empty(); +} + +size_t VertexDataXml::NumUvs() const +{ + return uvs.size(); +} + +// IndexData + +IndexData::IndexData() : + count(0), + faceCount(0), + is32bit(false) +{ +} + +IndexData::~IndexData() +{ + Reset(); +} + +void IndexData::Reset() +{ + // Release shared ptr memory stream. + buffer.reset(); +} + +size_t IndexData::IndexSize() const +{ + return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t)); +} + +size_t IndexData::FaceSize() const +{ + return IndexSize() * 3; +} + +// Mesh + +Mesh::Mesh() : + sharedVertexData(0), + skeleton(0), + hasSkeletalAnimations(false) +{ +} + +Mesh::~Mesh() +{ + Reset(); +} + +void Mesh::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); iindex == index) + return subMeshes[i]; + return 0; +} + +void Mesh::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; imNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); imRootNode->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(); imAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// ISubMesh + +ISubMesh::ISubMesh() : + index(0), + materialIndex(-1), + usesSharedVertexData(false), + operationType(OT_POINT_LIST) +{ +} + +// SubMesh + +SubMesh::SubMesh() : + vertexData(0), + indexData(new IndexData()) +{ +} + +SubMesh::~SubMesh() +{ + Reset(); +} + +void SubMesh::Reset() +{ + OGRE_SAFE_DELETE(vertexData) + OGRE_SAFE_DELETE(indexData) +} + +aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) +{ + if (operationType != OT_TRIANGLE_LIST) { + throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType); + } + + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Pick source vertex data from shader geometry or from internal geometry. + VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + + VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION); + VertexElement *normalsElement = src->GetVertexElement(VertexElement::VES_NORMAL); + VertexElement *uv1Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0); + VertexElement *uv2Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1); + + // Sanity checks + if (!positionsElement) { + throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!"); + } else if (positionsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + // Source streams + MemoryStream *positions = src->VertexBuffer(positionsElement->source); + MemoryStream *normals = (normalsElement ? src->VertexBuffer(normalsElement->source) : 0); + MemoryStream *uv1 = (uv1Element ? src->VertexBuffer(uv1Element->source) : 0); + MemoryStream *uv2 = (uv2Element ? src->VertexBuffer(uv2Element->source) : 0); + + // Element size + const size_t sizePosition = positionsElement->Size(); + const size_t sizeNormal = (normalsElement ? normalsElement->Size() : 0); + const size_t sizeUv1 = (uv1Element ? uv1Element->Size() : 0); + const size_t sizeUv2 = (uv2Element ? uv2Element->Size() : 0); + + // Vertex width + const size_t vWidthPosition = src->VertexSize(positionsElement->source); + const size_t vWidthNormal = (normalsElement ? src->VertexSize(normalsElement->source) : 0); + const size_t vWidthUv1 = (uv1Element ? src->VertexSize(uv1Element->source) : 0); + const size_t vWidthUv2 = (uv2Element ? src->VertexSize(uv2Element->source) : 0); + + bool boneAssignments = src->HasBoneAssignments(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs, ignoring incompatible UVs. + if (uv1) + { + if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[0] = uv1Element->ComponentCount(); + dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv1Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv1 = 0; + } + } + if (uv2) + { + if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[1] = uv2Element->ComponentCount(); + dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv2Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv2 = 0; + } + } + + aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : 0); + aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : 0); + + MemoryStream *faces = indexData->buffer.get(); + for (size_t fi=0, isize=indexData->IndexSize(), fsize=indexData->FaceSize(); + 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]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET); + positions->Read(&dest->mVertices[newIndex], sizePosition, 1); + + // Normal + if (normals) + { + normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET); + normals->Read(&dest->mNormals[newIndex], sizeNormal, 1); + } + // UV0 + if (uv1 && uv1Dest) + { + uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET); + uv1->Read(&uv1Dest[newIndex], sizeUv1, 1); + uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + // UV1 + if (uv2 && uv2Dest) + { + uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET); + uv2->Read(&uv2Dest[newIndex], sizeUv2, 1); + uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// MeshXml + +MeshXml::MeshXml() : + sharedVertexData(0), + skeleton(0) +{ +} + +MeshXml::~MeshXml() +{ + Reset(); +} + +void MeshXml::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); iindex == index) + return subMeshes[i]; + return 0; +} + +void MeshXml::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; imNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); imRootNode->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(); imAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// SubMeshXml + +SubMeshXml::SubMeshXml() : + vertexData(0), + indexData(new IndexDataXml()) +{ +} + +SubMeshXml::~SubMeshXml() +{ + Reset(); +} + +void SubMeshXml::Reset() +{ + OGRE_SAFE_DELETE(indexData) + OGRE_SAFE_DELETE(vertexData) +} + +aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent) +{ + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + bool boneAssignments = src->HasBoneAssignments(); + bool normals = src->HasNormals(); + size_t uvs = src->NumUvs(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs + for(size_t uvi=0; uvimNumUVComponents[uvi] = 2; + dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices]; + } + + for (size_t fi=0; fimNumFaces; ++fi) + { + // Source Ogre face + aiFace &ogreFace = indexData->faces[fi]; + + // Destination Assimp face + aiFace &face = dest->mFaces[fi]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + + const size_t pos = fi * 3; + for (size_t v=0; v<3; ++v) + { + const size_t newIndex = pos + v; + + // Write face index + face.mIndices[v] = newIndex; + + // Ogres vertex index to ref into the source buffers. + const size_t ogreVertexIndex = ogreFace.mIndices[v]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + dest->mVertices[newIndex] = src->positions[ogreVertexIndex]; + + // Normal + if (normals) + dest->mNormals[newIndex] = src->normals[ogreVertexIndex]; + + // UVs + for(size_t uvi=0; uvimTextureCoords[uvi]; + std::vector &uvSrc = src->uvs[uvi]; + uvDest[newIndex] = uvSrc[ogreVertexIndex]; + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// Animation + +Animation::Animation(Skeleton *parent) : + parentSkeleton(parent), + parentMesh(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +Animation::Animation(Mesh *parent) : + parentMesh(parent), + parentSkeleton(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const +{ + if (!parentMesh) + return 0; + + bool sharedGeom = (track->target == 0); + if (sharedGeom) + return parentMesh->sharedVertexData; + else + return parentMesh->GetSubMesh(track->target-1)->vertexData; +} + +aiAnimation *Animation::ConvertToAssimpAnimation() +{ + aiAnimation *anim = new aiAnimation(); + anim->mName = name; + anim->mDuration = static_cast(length); + anim->mTicksPerSecond = 1.0; + + // Tracks + if (!tracks.empty()) + { + anim->mNumChannels = tracks.size(); + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + + for(size_t i=0, len=tracks.size(); imChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton); + } + } + return anim; +} + +// Skeleton + +Skeleton::Skeleton() : + blendMode(ANIMBLEND_AVERAGE) +{ +} + +Skeleton::~Skeleton() +{ + Reset(); +} + +void Skeleton::Reset() +{ + for(size_t i=0, len=bones.size(); iIsParented()) + rootBones.push_back((*iter)); + } + return rootBones; +} + +size_t Skeleton::NumRootBones() const +{ + size_t num = 0; + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if (!(*iter)->IsParented()) + num++; + } + return num; +} + +Bone *Skeleton::BoneByName(const std::string &name) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->name == name) + return (*iter); + } + return 0; +} + +Bone *Skeleton::BoneById(uint16_t id) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->id == id) + return (*iter); + } + return 0; +} + +// Bone + +Bone::Bone() : + id(0), + parent(0), + parentId(-1), + scale(1.0f, 1.0f, 1.0f) +{ +} + +bool Bone::IsParented() const +{ + return (parentId != -1 && parent != 0); +} + +uint16_t Bone::ParentId() const +{ + return static_cast(parentId); +} + +void Bone::AddChild(Bone *bone) +{ + if (!bone) + return; + if (bone->IsParented()) + throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name); + + bone->parent = this; + bone->parentId = id; + children.push_back(bone->id); +} + +void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) +{ + if (!IsParented()) + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse(); + else + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix; + + defaultPose = aiMatrix4x4(scale, rotation, position); + + // Recursively for all children now that the parent matrix has been calculated. + for (size_t i=0, len=children.size(); iBoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + child->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) +{ + // Bone node + aiNode* node = new aiNode(name); + node->mParent = parentNode; + node->mTransformation = defaultPose; + + // Children + if (!children.empty()) + { + node->mNumChildren = children.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + + for(size_t i=0, len=children.size(); iBoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node); + } + } + return node; +} + +aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector &boneWeights) +{ + aiBone *bone = new aiBone(); + bone->mName = name; + bone->mOffsetMatrix = worldMatrix; + + if (!boneWeights.empty()) + { + bone->mNumWeights = boneWeights.size(); + bone->mWeights = new aiVertexWeight[boneWeights.size()]; + memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight)); + } + + return bone; +} + +// VertexAnimationTrack + +VertexAnimationTrack::VertexAnimationTrack() : + target(0), + type(VAT_NONE) +{ +} + +aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton) +{ + if (boneName.empty() || type != VAT_TRANSFORM) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM"); + } + + aiNodeAnim *nodeAnim = new aiNodeAnim(); + nodeAnim->mNodeName = boneName; + + Bone *bone = skeleton->BoneByName(boneName); + if (!bone) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton"); + } + + // Keyframes + size_t numKeyframes = transformKeyFrames.size(); + + nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes]; + nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mNumPositionKeys = numKeyframes; + nodeAnim->mNumRotationKeys = numKeyframes; + nodeAnim->mNumScalingKeys = numKeyframes; + + for(size_t kfi=0; kfidefaultPose * kfSource.Transform(); + finalTransform.Decompose(scale, rot, pos); + + double t = static_cast(kfSource.timePos); + nodeAnim->mPositionKeys[kfi].mTime = t; + nodeAnim->mRotationKeys[kfi].mTime = t; + nodeAnim->mScalingKeys[kfi].mTime = t; + + nodeAnim->mPositionKeys[kfi].mValue = pos; + nodeAnim->mRotationKeys[kfi].mValue = rot; + nodeAnim->mScalingKeys[kfi].mValue = scale; + } + + return nodeAnim; +} + +// TransformKeyFrame + +TransformKeyFrame::TransformKeyFrame() : + timePos(0.0f), + scale(1.0f, 1.0f, 1.0f) +{ +} + +aiMatrix4x4 TransformKeyFrame::Transform() +{ + return aiMatrix4x4(scale, rotation, position); +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreStructs.h b/code/OgreStructs.h new file mode 100644 index 000000000..75cadf4b7 --- /dev/null +++ b/code/OgreStructs.h @@ -0,0 +1,681 @@ +/* +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 MeshXml; +class SubMesh; +class SubMeshXml; +class Skeleton; + +#define OGRE_SAFE_DELETE(p) delete p; p=0; + +// Typedefs +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 Bone Assignment +struct VertexBoneAssignment +{ + uint32_t vertexIndex; + uint16_t boneIndex; + float weight; +}; +typedef std::vector VertexBoneAssignmentList; +typedef std::map VertexBoneAssignmentsMap; +typedef std::map > AssimpVertexBoneWeightList; + +// Ogre Vertex Data interface, inherited by the binary and XML implementations. +class IVertexData +{ +public: + IVertexData(); + + /// Returns if bone assignments are available. + bool HasBoneAssignments() const; + + /// Add vertex mapping from old to new index. + void AddVertexMapping(uint32_t oldIndex, uint32_t newIndex); + + /// Returns re-mapped bone assignments. + /** @note Uses mappings added via AddVertexMapping. */ + AssimpVertexBoneWeightList AssimpBoneWeights(size_t vertices); + + /// Returns a set of bone indexes that are referenced by bone assignments (weights). + std::set ReferencedBonesByWeights() const; + + /// Vertex count. + uint32_t count; + + /// Bone assignments. + VertexBoneAssignmentList boneAssignments; + +private: + void BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const; + + std::map > vertexIndexMapping; + VertexBoneAssignmentsMap boneAssignmentsMap; +}; + +// Ogre Vertex Data +class VertexData : public IVertexData +{ +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 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; +}; +typedef std::vector PoseList; + +/// Ogre Pose Key Frame Ref +struct PoseRef +{ + uint16_t index; + float influence; +}; +typedef std::vector PoseRefList; + +/// Ogre Pose Key Frame +struct PoseKeyFrame +{ + /// Time position in the animation. + float timePos; + + PoseRefList references; +}; +typedef std::vector PoseKeyFrameList; + +/// Ogre Morph Key Frame +struct MorphKeyFrame +{ + /// Time position in the animation. + float timePos; + + MemoryStreamPtr buffer; +}; +typedef std::vector MorphKeyFrameList; + +/// Ogre animation key frame +struct TransformKeyFrame +{ + TransformKeyFrame(); + + aiMatrix4x4 Transform(); + + float timePos; + + aiQuaternion rotation; + aiVector3D position; + aiVector3D scale; +}; +typedef std::vector TransformKeyFrameList; + +/// 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, + /// Keyframe that has its on pos, rot and scale for a time position + VAT_TRANSFORM = 3 + }; + + VertexAnimationTrack(); + + /// Convert to Assimp node animation. + aiNodeAnim *ConvertToAssimpAnimationNode(Skeleton *skeleton); + + // Animation type. + Type type; + + /// Vertex data target. + /** 0 == shared geometry + >0 == submesh index + 1 */ + uint16_t target; + + /// Only valid for VAT_TRANSFORM. + std::string boneName; + + /// Only one of these will contain key frames, depending on the type enum. + PoseKeyFrameList poseKeyFrames; + MorphKeyFrameList morphKeyFrames; + TransformKeyFrameList transformKeyFrames; +}; +typedef std::vector VertexAnimationTrackList; + +/// Ogre Animation +class Animation +{ +public: + Animation(Skeleton *parent); + Animation(Mesh *parent); + + /// Returns the associated vertex data for a track in this animation. + /** @note Only valid to call when parent Mesh is set. */ + VertexData *AssociatedVertexData(VertexAnimationTrack *track) const; + + /// Convert to Assimp animation. + aiAnimation *ConvertToAssimpAnimation(); + + /// Parent mesh. + /** @note Set only when animation is read from a mesh. */ + Mesh *parentMesh; + + /// Parent skeleton. + /** @note Set only when animation is read from a skeleton. */ + Skeleton *parentSkeleton; + + /// Animation name. + std::string name; + + /// Base animation name. + std::string baseName; + + /// Length in seconds. + float length; + + /// Base animation key time. + float baseTime; + + /// Animation tracks. + VertexAnimationTrackList tracks; +}; +typedef std::vector AnimationList; + +/// Ogre Bone +class Bone +{ +public: + Bone(); + + /// Returns if this bone is parented. + bool IsParented() const; + + /// Parent index as uint16_t. Internally int32_t as -1 means unparented. + uint16_t ParentId() const; + + /// Add child bone. + void AddChild(Bone *bone); + + /// Calculates the world matrix for bone and its children. + void CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton); + + /// Convert to Assimp node (animation nodes). + aiNode *ConvertToAssimpNode(Skeleton *parent, aiNode *parentNode = 0); + + /// Convert to Assimp bone (mesh bones). + aiBone *ConvertToAssimpBone(Skeleton *parent, const std::vector &boneWeights); + + uint16_t id; + std::string name; + + Bone *parent; + int32_t parentId; + std::vector children; + + aiVector3D position; + aiQuaternion rotation; + aiVector3D scale; + + aiMatrix4x4 worldMatrix; + aiMatrix4x4 defaultPose; +}; +typedef std::vector BoneList; + +/// Ogre Skeleton +class Skeleton +{ +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(); + + /// Releases all memory that this data structure owns. + void Reset(); + + /// Returns unparented root bones. + BoneList RootBones() const; + + /// Returns number of unparented root bones. + size_t NumRootBones() const; + + /// Get bone by name. + Bone *BoneByName(const std::string &name) const; + + /// Get bone by id. + Bone *BoneById(uint16_t id) const; + + BoneList bones; + AnimationList animations; + + /// @todo Take blend mode into account, but where? + BlendMode blendMode; +}; + +/// Ogre Sub Mesh interface, inherited by the binary and XML implementations. +class ISubMesh +{ +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 + }; + + ISubMesh(); + + /// 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; + + /// If submesh uses shared geometry from parent mesh. + bool usesSharedVertexData; + + /// Operation type. + OperationType operationType; +}; + +/// Ogre SubMesh +class SubMesh : public ISubMesh +{ +public: + SubMesh(); + ~SubMesh(); + + /// 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); + + /// Vertex data. + VertexData *vertexData; + + /// Index data. + IndexData *indexData; +}; +typedef std::vector SubMeshList; + +/// 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. + SubMesh *GetSubMesh(uint16_t index) const; + + /// Convert mesh to Assimp scene. + void ConvertToAssimpScene(aiScene* dest); + + /// Mesh has skeletal animations. + bool hasSkeletalAnimations; + + /// Skeleton reference. + std::string skeletonRef; + + /// Skeleton. + Skeleton *skeleton; + + /// Vertex data + VertexData *sharedVertexData; + + /// Sub meshes. + SubMeshList subMeshes; + + /// Animations + AnimationList animations; + + /// Poses + PoseList poses; +}; + +/// Ogre XML Vertex Data +class VertexDataXml : public IVertexData +{ +public: + VertexDataXml(); + + bool HasPositions() const; + bool HasNormals() const; + bool HasTangents() const; + bool HasUvs() const; + size_t NumUvs() const; + + std::vector positions; + std::vector normals; + std::vector tangents; + std::vector > uvs; +}; + +/// Ogre XML Index Data +class IndexDataXml +{ +public: + IndexDataXml() : faceCount(0) {} + + /// Face count. + uint32_t faceCount; + + std::vector faces; +}; + +/// Ogre XML SubMesh +class SubMeshXml : public ISubMesh +{ +public: + SubMeshXml(); + ~SubMeshXml(); + + /// Releases all memory that this data structure owns. + void Reset(); + + aiMesh *ConvertToAssimpMesh(MeshXml *parent); + + IndexDataXml *indexData; + VertexDataXml *vertexData; +}; +typedef std::vector SubMeshXmlList; + +/// Ogre XML Mesh +class MeshXml +{ +public: + MeshXml(); + ~MeshXml(); + + /// Releases all memory that this data structure owns. + void Reset(); + + /// Returns number of subMeshes. + size_t NumSubMeshes() const; + + /// Returns submesh for @c index. + SubMeshXml *GetSubMesh(uint16_t index) const; + + /// Convert mesh to Assimp scene. + void ConvertToAssimpScene(aiScene* dest); + + /// Skeleton reference. + std::string skeletonRef; + + /// Skeleton. + Skeleton *skeleton; + + /// Vertex data + VertexDataXml *sharedVertexData; + + /// Sub meshes. + SubMeshXmlList subMeshes; +}; + +} // 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..733e36c03 --- /dev/null +++ b/code/OgreXmlSerializer.cpp @@ -0,0 +1,1003 @@ +/* +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 "OgreXmlSerializer.h" +#include "OgreBinarySerializer.h" +#include "OgreParsingUtils.h" + +#include "TinyFormatter.h" + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +// Define as 1 to get verbose logging. +#define OGRE_XML_SERIALIZER_DEBUG 0 + +namespace Assimp +{ +namespace Ogre +{ + +void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") +{ + if (!error.empty()) + { + throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); + } + else + { + throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); + } +} + +template<> +int32_t OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + return static_cast(m_reader->getAttributeValueAsInt(name.c_str())); + } + else + { + ThrowAttibuteError(m_reader, name); + return 0; + } +} + +template<> +uint32_t OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + /** @note This is hackish. But we are never expecting unsigned values that go outside the + int32_t range. Just monitor for negative numbers and kill the import. */ + int32_t temp = ReadAttribute(name); + if (temp >= 0) + { + return static_cast(temp); + } + else + { + ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value"); + } + } + else + { + ThrowAttibuteError(m_reader, name); + } + return 0; +} + +template<> +uint16_t OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + return static_cast(ReadAttribute(name)); + } + else + { + ThrowAttibuteError(m_reader, name); + } + return 0; +} + +template<> +float OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + return m_reader->getAttributeValueAsFloat(name.c_str()); + } + else + { + ThrowAttibuteError(m_reader, name); + return 0; + } +} + +template<> +std::string OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + const char* value = m_reader->getAttributeValue(name.c_str()); + if (value) + { + return std::string(value); + } + else + { + ThrowAttibuteError(m_reader, name); + return ""; + } +} + +template<> +bool OgreXmlSerializer::ReadAttribute(const std::string &name) const +{ + std::string value = Ogre::ToLower(ReadAttribute(name)); + if (ASSIMP_stricmp(value, "true") == 0) + { + return true; + } + else if (ASSIMP_stricmp(value, "false") == 0) + { + return false; + } + else + { + ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'"); + return false; + } +} + +bool OgreXmlSerializer::HasAttribute(const std::string &name) const +{ + return (m_reader->getAttributeValue(name.c_str()) != 0); +} + +std::string &OgreXmlSerializer::NextNode() +{ + do + { + if (!m_reader->read()) + { + m_currentNodeName = ""; + return m_currentNodeName; + } + } + while(m_reader->getNodeType() != irr::io::EXN_ELEMENT); + + CurrentNodeName(true); +#if (OGRE_XML_SERIALIZER_DEBUG == 1) + DefaultLogger::get()->debug("<" + m_currentNodeName + ">"); +#endif + return m_currentNodeName; +} + +bool OgreXmlSerializer::CurrentNodeNameEquals(const std::string &name) const +{ + return (ASSIMP_stricmp(m_currentNodeName, name) == 0); +} + +std::string OgreXmlSerializer::CurrentNodeName(bool forceRead) +{ + if (forceRead) + m_currentNodeName = std::string(m_reader->getNodeName()); + return m_currentNodeName; +} + +std::string &OgreXmlSerializer::SkipCurrentNode() +{ +#if (OGRE_XML_SERIALIZER_DEBUG == 1) + DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">"); +#endif + + for(;;) + { + if (!m_reader->read()) + { + m_currentNodeName = ""; + return m_currentNodeName; + } + if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END) + continue; + else if (std::string(m_reader->getNodeName()) == m_currentNodeName) + break; + } + return NextNode(); +} + +// Mesh XML constants + +// +const std::string nnMesh = "mesh"; +const std::string nnSharedGeometry = "sharedgeometry"; +const std::string nnSubMeshes = "submeshes"; +const std::string nnSubMesh = "submesh"; +const std::string nnSubMeshNames = "submeshnames"; +const std::string nnSkeletonLink = "skeletonlink"; +const std::string nnLOD = "levelofdetail"; +const std::string nnExtremes = "extremes"; +const std::string nnPoses = "poses"; +const std::string nnAnimations = "animations"; + +// +const std::string nnFaces = "faces"; +const std::string nnFace = "face"; +const std::string nnGeometry = "geometry"; +const std::string nnTextures = "textures"; + +// +const std::string nnBoneAssignments = "boneassignments"; + +// +const std::string nnVertexBuffer = "vertexbuffer"; + +// +const std::string nnVertex = "vertex"; +const std::string nnPosition = "position"; +const std::string nnNormal = "normal"; +const std::string nnTangent = "tangent"; +const std::string nnBinormal = "binormal"; +const std::string nnTexCoord = "texcoord"; +const std::string nnColorDiffuse = "colour_diffuse"; +const std::string nnColorSpecular = "colour_specular"; + +// +const std::string nnVertexBoneAssignment = "vertexboneassignment"; + +// Skeleton XML constants + +// +const std::string nnSkeleton = "skeleton"; +const std::string nnBones = "bones"; +const std::string nnBoneHierarchy = "bonehierarchy"; +const std::string nnAnimationLinks = "animationlinks"; + +// +const std::string nnBone = "bone"; +const std::string nnRotation = "rotation"; +const std::string nnAxis = "axis"; +const std::string nnScale = "scale"; + +// +const std::string nnBoneParent = "boneparent"; + +// +const std::string nnAnimation = "animation"; +const std::string nnTracks = "tracks"; + +// +const std::string nnTrack = "track"; +const std::string nnKeyFrames = "keyframes"; +const std::string nnKeyFrame = "keyframe"; +const std::string nnTranslate = "translate"; +const std::string nnRotate = "rotate"; + +// Common XML constants + +const std::string anX = "x"; +const std::string anY = "y"; +const std::string anZ = "z"; + +// Mesh + +MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) +{ + OgreXmlSerializer serializer(reader); + + MeshXml *mesh = new MeshXml(); + serializer.ReadMesh(mesh); + return mesh; +} + +void OgreXmlSerializer::ReadMesh(MeshXml *mesh) +{ + if (NextNode() != nnMesh) { + throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); + } + + DefaultLogger::get()->debug("Reading Mesh"); + + NextNode(); + + // Root level nodes + while(m_currentNodeName == nnSharedGeometry || + m_currentNodeName == nnSubMeshes || + m_currentNodeName == nnSkeletonLink || + m_currentNodeName == nnBoneAssignments || + m_currentNodeName == nnLOD || + m_currentNodeName == nnSubMeshNames || + m_currentNodeName == nnExtremes || + m_currentNodeName == nnPoses || + m_currentNodeName == nnAnimations) + { + if (m_currentNodeName == nnSharedGeometry) + { + mesh->sharedVertexData = new VertexDataXml(); + ReadGeometry(mesh->sharedVertexData); + } + else if (m_currentNodeName == nnSubMeshes) + { + NextNode(); + while(m_currentNodeName == nnSubMesh) { + ReadSubMesh(mesh); + } + } + else if (m_currentNodeName == nnBoneAssignments) + { + ReadBoneAssignments(mesh->sharedVertexData); + } + else if (m_currentNodeName == nnSkeletonLink) + { + mesh->skeletonRef = ReadAttribute("name"); + DefaultLogger::get()->debug("Read skeleton link " + mesh->skeletonRef); + NextNode(); + } + // Assimp incompatible/ignored nodes + else + SkipCurrentNode(); + } +} + +void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) +{ + dest->count = ReadAttribute("vertexcount"); + DefaultLogger::get()->debug(Formatter::format() << " - Reading geometry of " << dest->count << " vertices"); + + NextNode(); + while(m_currentNodeName == nnVertexBuffer) { + ReadGeometryVertexBuffer(dest); + } +} + +void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) +{ + bool positions = (HasAttribute("positions") && ReadAttribute("positions")); + bool normals = (HasAttribute("normals") && ReadAttribute("normals")); + bool tangents = (HasAttribute("tangents") && ReadAttribute("tangents")); + uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute("texture_coords") : 0); + + // Not having positions is a error only if a previous vertex buffer did not have them. + if (!positions && !dest->HasPositions()) { + throw DeadlyImportError("Vertex buffer does not contain positions!"); + } + + if (positions) + { + DefaultLogger::get()->debug(" - Contains positions"); + dest->positions.reserve(dest->count); + } + if (normals) + { + DefaultLogger::get()->debug(" - Contains normals"); + dest->normals.reserve(dest->count); + } + if (tangents) + { + DefaultLogger::get()->debug(" - Contains tangents"); + dest->tangents.reserve(dest->count); + } + if (uvs > 0) + { + DefaultLogger::get()->debug(Formatter::format() << " - Contains " << uvs << " texture coords"); + dest->uvs.resize(uvs); + for(size_t i=0, len=dest->uvs.size(); iuvs[i].reserve(dest->count); + } + } + + bool warnBinormal = true; + bool warnColorDiffuse = true; + bool warnColorSpecular = true; + + NextNode(); + + while(m_currentNodeName == nnVertex || + m_currentNodeName == nnPosition || + m_currentNodeName == nnNormal || + m_currentNodeName == nnTangent || + m_currentNodeName == nnBinormal || + m_currentNodeName == nnTexCoord || + m_currentNodeName == nnColorDiffuse || + m_currentNodeName == nnColorSpecular) + { + if (m_currentNodeName == nnVertex) { + NextNode(); + } + + /// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular + + if (positions && m_currentNodeName == nnPosition) + { + aiVector3D pos; + pos.x = ReadAttribute(anX); + pos.y = ReadAttribute(anY); + pos.z = ReadAttribute(anZ); + dest->positions.push_back(pos); + } + else if (normals && m_currentNodeName == nnNormal) + { + aiVector3D normal; + normal.x = ReadAttribute(anX); + normal.y = ReadAttribute(anY); + normal.z = ReadAttribute(anZ); + dest->normals.push_back(normal); + } + else if (tangents && m_currentNodeName == nnTangent) + { + aiVector3D tangent; + tangent.x = ReadAttribute(anX); + tangent.y = ReadAttribute(anY); + tangent.z = ReadAttribute(anZ); + dest->tangents.push_back(tangent); + } + else if (uvs > 0 && m_currentNodeName == nnTexCoord) + { + for(size_t i=0, len=dest->uvs.size(); i("u"); + uv.y = (ReadAttribute("v") * -1) + 1; // Flip UV from Ogre to Assimp form + dest->uvs[i].push_back(uv); + + NextNode(); + } + // Continue main loop as above already read next node + continue; + } + else + { + /// @todo Remove this stuff once implemented. We only want to log warnings once per element. + bool warn = true; + if (m_currentNodeName == nnBinormal) + { + if (warnBinormal) + { + warnBinormal = false; + } + else + { + warn = false; + } + } + else if (m_currentNodeName == nnColorDiffuse) + { + if (warnColorDiffuse) + { + warnColorDiffuse = false; + } + else + { + warn = false; + } + } + else if (m_currentNodeName == nnColorSpecular) + { + if (warnColorSpecular) + { + warnColorSpecular = false; + } + else + { + warn = false; + } + } + if (warn) { + DefaultLogger::get()->warn("Vertex buffer attribute read not implemented for element: " + m_currentNodeName); + } + } + + // Advance + NextNode(); + } + + // Sanity checks + if (dest->positions.size() != dest->count) { + throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count); + } + if (normals && dest->normals.size() != dest->count) { + throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count); + } + if (tangents && dest->tangents.size() != dest->count) { + throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count); + } + for(unsigned int i=0; iuvs.size(); ++i) + { + if (dest->uvs[i].size() != dest->count) { + throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() + << " uvs for uv index " << i << " when should have read " << dest->count); + } + } +} + +void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) +{ + static const std::string anMaterial = "material"; + static const std::string anUseSharedVertices = "usesharedvertices"; + static const std::string anCount = "count"; + static const std::string anV1 = "v1"; + static const std::string anV2 = "v2"; + static const std::string anV3 = "v3"; + static const std::string anV4 = "v4"; + + SubMeshXml* submesh = new SubMeshXml(); + + if (HasAttribute(anMaterial)) { + submesh->materialRef = ReadAttribute(anMaterial); + } + if (HasAttribute(anUseSharedVertices)) { + submesh->usesSharedVertexData = ReadAttribute(anUseSharedVertices); + } + + 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")); + + // TODO: maybe we have always just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order + // of faces and geometry changed, and not if we have more than one of one + /// @todo Fix above comment with better read logic below + + bool quadWarned = false; + + NextNode(); + while(m_currentNodeName == nnFaces || + m_currentNodeName == nnGeometry || + m_currentNodeName == nnTextures || + m_currentNodeName == nnBoneAssignments) + { + if (m_currentNodeName == nnFaces) + { + submesh->indexData->faceCount = ReadAttribute(anCount); + submesh->indexData->faces.reserve(submesh->indexData->faceCount); + + NextNode(); + while(m_currentNodeName == nnFace) + { + aiFace face; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = ReadAttribute(anV1); + face.mIndices[1] = ReadAttribute(anV2); + face.mIndices[2] = ReadAttribute(anV3); + + /// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it) + if (!quadWarned && HasAttribute(anV4)) { + DefaultLogger::get()->warn("Submesh has quads with , only triangles are supported at the moment!"); + quadWarned = true; + } + + submesh->indexData->faces.push_back(face); + + // Advance + NextNode(); + } + + if (submesh->indexData->faces.size() == submesh->indexData->faceCount) + { + DefaultLogger::get()->debug(Formatter::format() << " - Faces " << submesh->indexData->faceCount); + } + else + { + throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount); + } + } + else if (m_currentNodeName == nnGeometry) + { + if (submesh->usesSharedVertexData) { + throw DeadlyImportError("Found in when use shared geometry is true. Invalid mesh file."); + } + + submesh->vertexData = new VertexDataXml(); + ReadGeometry(submesh->vertexData); + } + else if (m_currentNodeName == nnBoneAssignments) + { + ReadBoneAssignments(submesh->vertexData); + } + // Assimp incompatible/ignored nodes + else + SkipCurrentNode(); + } + + submesh->index = mesh->subMeshes.size(); + mesh->subMeshes.push_back(submesh); +} + +void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) +{ + if (!dest) { + throw DeadlyImportError("Cannot read bone assignments, vertex data is null."); + } + + static const std::string anVertexIndex = "vertexindex"; + static const std::string anBoneIndex = "boneindex"; + static const std::string anWeight = "weight"; + + std::set influencedVertices; + + NextNode(); + while(m_currentNodeName == nnVertexBoneAssignment) + { + VertexBoneAssignment ba; + ba.vertexIndex = ReadAttribute(anVertexIndex); + ba.boneIndex = ReadAttribute(anBoneIndex); + ba.weight = ReadAttribute(anWeight); + + dest->boneAssignments.push_back(ba); + influencedVertices.insert(ba.vertexIndex); + + NextNode(); + } + + /** Normalize bone weights. + Some exporters wont care if the sum of all bone weights + for a single vertex equals 1 or not, so validate here. */ + const float epsilon = 0.05f; + for(std::set::const_iterator iter=influencedVertices.begin(), end=influencedVertices.end(); iter != end; ++iter) + { + const uint32_t vertexIndex = (*iter); + + float sum = 0.0f; + for (VertexBoneAssignmentList::const_iterator baIter=dest->boneAssignments.begin(), baEnd=dest->boneAssignments.end(); baIter != baEnd; ++baIter) + { + if (baIter->vertexIndex == vertexIndex) + sum += baIter->weight; + } + if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) + { + for (VertexBoneAssignmentList::iterator baIter=dest->boneAssignments.begin(), baEnd=dest->boneAssignments.end(); baIter != baEnd; ++baIter) + { + if (baIter->vertexIndex == vertexIndex) + baIter->weight /= sum; + } + } + } + + DefaultLogger::get()->debug(Formatter::format() << " - " << dest->boneAssignments.size() << " bone assignments"); +} + +// Skeleton + +bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh) +{ + if (!mesh || mesh->skeletonRef.empty()) + return false; + + // Highly unusual to see in read world cases but support + // XML mesh referencing a binary skeleton file. + if (EndsWith(mesh->skeletonRef, ".skeleton", false)) + { + if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh)) + return true; + + /** 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 might depends on it. */ + mesh->skeletonRef = mesh->skeletonRef + ".xml"; + } + + XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); + if (!reader.get()) + return false; + + Skeleton *skeleton = new Skeleton(); + OgreXmlSerializer serializer(reader.get()); + serializer.ReadSkeleton(skeleton); + mesh->skeleton = skeleton; + return true; +} + +bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) +{ + if (!mesh || mesh->skeletonRef.empty()) + return false; + + XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); + if (!reader.get()) + return false; + + Skeleton *skeleton = new Skeleton(); + OgreXmlSerializer serializer(reader.get()); + serializer.ReadSkeleton(skeleton); + mesh->skeleton = skeleton; + return true; +} + +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)) + { + DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh."); + return XmlReaderPtr(); + } + + boost::scoped_ptr file(pIOHandler->Open(filename)); + if (!file.get()) { + throw DeadlyImportError("Failed to open skeleton file " + filename); + } + + boost::scoped_ptr stream(new CIrrXML_IOStreamReader(file.get())); + XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); + if (!reader.get()) { + throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); + } + return reader; +} + +void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) +{ + if (NextNode() != nnSkeleton) { + throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); + } + + DefaultLogger::get()->debug("Reading Skeleton"); + + // Optional blend mode from root node + if (HasAttribute("blendmode")) { + skeleton->blendMode = (ToLower(ReadAttribute("blendmode")) == "cumulative" + ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); + } + + NextNode(); + + // Root level nodes + while(m_currentNodeName == nnBones || + m_currentNodeName == nnBoneHierarchy || + m_currentNodeName == nnAnimations || + m_currentNodeName == nnAnimationLinks) + { + if (m_currentNodeName == nnBones) + ReadBones(skeleton); + else if (m_currentNodeName == nnBoneHierarchy) + ReadBoneHierarchy(skeleton); + else if (m_currentNodeName == nnAnimations) + ReadAnimations(skeleton); + else + SkipCurrentNode(); + } +} + +void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) +{ + if (skeleton->bones.empty()) { + throw DeadlyImportError("Cannot read for a Skeleton without bones"); + } + + DefaultLogger::get()->debug(" - Animations"); + + NextNode(); + while(m_currentNodeName == nnAnimation) + { + Animation *anim = new Animation(skeleton); + anim->name = ReadAttribute("name"); + anim->length = ReadAttribute("length"); + + if (NextNode() != nnTracks) { + throw DeadlyImportError(Formatter::format() << "No found in " << anim->name); + } + + ReadAnimationTracks(anim); + skeleton->animations.push_back(anim); + + DefaultLogger::get()->debug(Formatter::format() << " " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)"); + } +} + +void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) +{ + NextNode(); + while(m_currentNodeName == nnTrack) + { + VertexAnimationTrack track; + track.type = VertexAnimationTrack::VAT_TRANSFORM; + track.boneName = ReadAttribute("bone"); + + if (NextNode() != nnKeyFrames) { + throw DeadlyImportError(Formatter::format() << "No found in " << dest->name); + } + + ReadAnimationKeyFrames(dest, &track); + + dest->tracks.push_back(track); + } +} + +void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) +{ + const aiVector3D zeroVec(0.f, 0.f, 0.f); + + NextNode(); + while(m_currentNodeName == nnKeyFrame) + { + TransformKeyFrame keyframe; + keyframe.timePos = ReadAttribute("time"); + + NextNode(); + while(m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale) + { + if (m_currentNodeName == nnTranslate) + { + keyframe.position.x = ReadAttribute(anX); + keyframe.position.y = ReadAttribute(anY); + keyframe.position.z = ReadAttribute(anZ); + } + else if (m_currentNodeName == nnRotate) + { + float angle = ReadAttribute("angle"); + + if (NextNode() != nnAxis) { + throw DeadlyImportError("No axis specified for keyframe rotation in animation " + anim->name); + } + + aiVector3D axis; + axis.x = ReadAttribute(anX); + axis.y = ReadAttribute(anY); + axis.z = ReadAttribute(anZ); + if (axis.Equal(zeroVec)) + { + axis.x = 1.0f; + if (angle != 0) { + DefaultLogger::get()->warn("Found invalid a key frame with a zero rotation axis in animation: " + anim->name); + } + } + keyframe.rotation = aiQuaternion(axis, angle); + } + else if (m_currentNodeName == nnScale) + { + keyframe.scale.x = ReadAttribute(anX); + keyframe.scale.y = ReadAttribute(anY); + keyframe.scale.z = ReadAttribute(anZ); + } + + NextNode(); + } + + dest->transformKeyFrames.push_back(keyframe); + } +} + +void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) +{ + if (skeleton->bones.empty()) { + throw DeadlyImportError("Cannot read for a Skeleton without bones"); + } + + while(NextNode() == nnBoneParent) + { + const std::string name = ReadAttribute("bone"); + const std::string parentName = ReadAttribute("parent"); + + Bone *bone = skeleton->BoneByName(name); + Bone *parent = skeleton->BoneByName(parentName); + + if (bone && parent) + parent->AddChild(bone); + else + throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); + } + + // Calculate bone matrices for root bones. Recursively calculates their children. + for (size_t i=0, len=skeleton->bones.size(); ibones[i]; + if (!bone->IsParented()) + bone->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +bool BoneCompare(Bone *a, Bone *b) +{ + return (a->id < b->id); +} + +void OgreXmlSerializer::ReadBones(Skeleton *skeleton) +{ + DefaultLogger::get()->debug(" - Bones"); + + NextNode(); + while(m_currentNodeName == nnBone) + { + Bone *bone = new Bone(); + bone->id = ReadAttribute("id"); + bone->name = ReadAttribute("name"); + + NextNode(); + while(m_currentNodeName == nnPosition || + m_currentNodeName == nnRotation || + m_currentNodeName == nnScale) + { + if (m_currentNodeName == nnPosition) + { + bone->position.x = ReadAttribute(anX); + bone->position.y = ReadAttribute(anY); + bone->position.z = ReadAttribute(anZ); + } + else if (m_currentNodeName == nnRotation) + { + float angle = ReadAttribute("angle"); + + if (NextNode() != nnAxis) { + throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id); + } + + aiVector3D axis; + axis.x = ReadAttribute(anX); + axis.y = ReadAttribute(anY); + axis.z = ReadAttribute(anZ); + + bone->rotation = aiQuaternion(axis, angle); + } + else if (m_currentNodeName == nnScale) + { + /// @todo Implement taking scale into account in matrix/pose calculations! + if (HasAttribute("factor")) + { + float factor = ReadAttribute("factor"); + bone->scale.Set(factor, factor, factor); + } + else + { + if (HasAttribute(anX)) + bone->scale.x = ReadAttribute(anX); + if (HasAttribute(anY)) + bone->scale.y = ReadAttribute(anY); + if (HasAttribute(anZ)) + bone->scale.z = ReadAttribute(anZ); + } + } + + NextNode(); + } + + skeleton->bones.push_back(bone); + } + + // Order bones by Id + std::sort(skeleton->bones.begin(), skeleton->bones.end(), BoneCompare); + + // Validate that bone indexes are not skipped. + /** @note Left this from original authors code, but not sure if this is strictly necessary + as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */ + for (size_t i=0, len=skeleton->bones.size(); ibones[i]; + DefaultLogger::get()->debug(Formatter::format() << " " << b->id << " " << b->name); + + if (b->id != static_cast(i)) { + throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i); + } + } +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/code/OgreXmlSerializer.h b/code/OgreXmlSerializer.h new file mode 100644 index 000000000..62257f81c --- /dev/null +++ b/code/OgreXmlSerializer.h @@ -0,0 +1,116 @@ +/* +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_OGREXMLSERIALIZER_H_INC +#define AI_OGREXMLSERIALIZER_H_INC + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "OgreStructs.h" +#include "irrXMLWrapper.h" + +namespace Assimp +{ +namespace Ogre +{ + +typedef irr::io::IrrXMLReader XmlReader; +typedef boost::shared_ptr XmlReaderPtr; + +class OgreXmlSerializer +{ +public: + /// Imports mesh and returns the result. + /** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ + static MeshXml *ImportMesh(XmlReader *reader); + + /// Imports skeleton to @c mesh. + /** If mesh does not have a skeleton reference or the skeleton file + cannot be found it is not a fatal DeadlyImportError. + @return If skeleton import was successful. */ + static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); + static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); + +private: + OgreXmlSerializer(XmlReader *reader) : + m_reader(reader) + { + } + + static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); + + // Mesh + void ReadMesh(MeshXml *mesh); + void ReadSubMesh(MeshXml *mesh); + + void ReadGeometry(VertexDataXml *dest); + void ReadGeometryVertexBuffer(VertexDataXml *dest); + + void ReadBoneAssignments(VertexDataXml *dest); + + // Skeleton + void ReadSkeleton(Skeleton *skeleton); + + void ReadBones(Skeleton *skeleton); + void ReadBoneHierarchy(Skeleton *skeleton); + + void ReadAnimations(Skeleton *skeleton); + void ReadAnimationTracks(Animation *dest); + void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest); + + template + T ReadAttribute(const std::string &name) const; + bool HasAttribute(const std::string &name) const; + + std::string &NextNode(); + std::string &SkipCurrentNode(); + + bool CurrentNodeNameEquals(const std::string &name) const; + std::string CurrentNodeName(bool forceRead = false); + + XmlReader *m_reader; + std::string m_currentNodeName; +}; + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER +#endif // AI_OGREXMLSERIALIZER_H_INC diff --git a/test/models-nonbsd/Ogre/Animationtest/Arm.skeleton.xml b/test/models-nonbsd/Ogre/Animationtest/Arm.skeleton.xml deleted file mode 100644 index 475735cab..000000000 --- a/test/models-nonbsd/Ogre/Animationtest/Arm.skeleton.xml +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Animationtest/Cube.mesh.xml b/test/models-nonbsd/Ogre/Animationtest/Cube.mesh.xml deleted file mode 100644 index ca124b159..000000000 --- a/test/models-nonbsd/Ogre/Animationtest/Cube.mesh.xml +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Animationtest/Scene.material b/test/models-nonbsd/Ogre/Animationtest/Scene.material deleted file mode 100644 index c0e448cd1..000000000 --- a/test/models-nonbsd/Ogre/Animationtest/Scene.material +++ /dev/null @@ -1,14 +0,0 @@ -material Material -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.640000 0.640000 0.640000 1.000000 - specular 0.500000 0.500000 0.500000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - } - } -} diff --git a/test/models-nonbsd/Ogre/Assassine/Axt.mesh.xml b/test/models-nonbsd/Ogre/Assassine/Axt.mesh.xml deleted file mode 100644 index 74647fd49..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Axt.mesh.xml +++ /dev/null @@ -1,779 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/Axt.skeleton.xml b/test/models-nonbsd/Ogre/Assassine/Axt.skeleton.xml deleted file mode 100644 index a7439de7c..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Axt.skeleton.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/DesertEagle.tga b/test/models-nonbsd/Ogre/Assassine/DesertEagle.tga deleted file mode 100644 index 371e96ef6..000000000 Binary files a/test/models-nonbsd/Ogre/Assassine/DesertEagle.tga and /dev/null differ diff --git a/test/models-nonbsd/Ogre/Assassine/Koerper.mesh.xml b/test/models-nonbsd/Ogre/Assassine/Koerper.mesh.xml deleted file mode 100644 index 33fd29b33..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Koerper.mesh.xml +++ /dev/null @@ -1,6694 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/Koerper.skeleton.xml b/test/models-nonbsd/Ogre/Assassine/Koerper.skeleton.xml deleted file mode 100644 index 15b061f45..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Koerper.skeleton.xml +++ /dev/null @@ -1,33243 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/Pistol.mesh.xml b/test/models-nonbsd/Ogre/Assassine/Pistol.mesh.xml deleted file mode 100644 index 3bbee02ed..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Pistol.mesh.xml +++ /dev/null @@ -1,943 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/Pistol.skeleton.xml b/test/models-nonbsd/Ogre/Assassine/Pistol.skeleton.xml deleted file mode 100644 index c550a3a4c..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Pistol.skeleton.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Assassine/PlayerTextur.tga b/test/models-nonbsd/Ogre/Assassine/PlayerTextur.tga deleted file mode 100644 index 92d0bcdc3..000000000 Binary files a/test/models-nonbsd/Ogre/Assassine/PlayerTextur.tga and /dev/null differ diff --git a/test/models-nonbsd/Ogre/Assassine/Scene.material b/test/models-nonbsd/Ogre/Assassine/Scene.material deleted file mode 100644 index 82b8c7795..000000000 --- a/test/models-nonbsd/Ogre/Assassine/Scene.material +++ /dev/null @@ -1,62 +0,0 @@ -material Player -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.800000 0.800000 0.800000 1.000000 - specular 0.000000 0.000000 0.000000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - texture_unit - { - texture PlayerTextur.tga - tex_address_mode wrap - filtering trilinear - colour_op alpha_blend - } - } - } -} -material Pistol -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.640000 0.640000 0.640000 1.000000 - specular 0.500000 0.500000 0.500000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - texture_unit - { - texture DesertEagle.tga - tex_address_mode wrap - filtering trilinear - colour_op alpha_blend - } - } - } -} -material Axt -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.640000 0.640000 0.640000 1.000000 - specular 0.500000 0.500000 0.500000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - texture_unit - { - texture axt.tga - tex_address_mode wrap - filtering trilinear - } - } - } -} diff --git a/test/models-nonbsd/Ogre/Assassine/axt.tga b/test/models-nonbsd/Ogre/Assassine/axt.tga deleted file mode 100644 index e28490452..000000000 Binary files a/test/models-nonbsd/Ogre/Assassine/axt.tga and /dev/null differ diff --git a/test/models-nonbsd/Ogre/Gravestone/Sarg.material b/test/models-nonbsd/Ogre/Gravestone/Sarg.material deleted file mode 100644 index f463f60fb..000000000 --- a/test/models-nonbsd/Ogre/Gravestone/Sarg.material +++ /dev/null @@ -1,20 +0,0 @@ -material Sarg -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.640000 0.640000 0.640000 1.000000 - specular 0.500000 0.500000 0.500000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - texture_unit - { - texture SargTextur.tga - tex_address_mode wrap - filtering linear linear none - } - } - } -} diff --git a/test/models-nonbsd/Ogre/Gravestone/Sarg.mesh.xml b/test/models-nonbsd/Ogre/Gravestone/Sarg.mesh.xml deleted file mode 100644 index c1c6ef0ab..000000000 --- a/test/models-nonbsd/Ogre/Gravestone/Sarg.mesh.xml +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/Gravestone/SargTextur.tga b/test/models-nonbsd/Ogre/Gravestone/SargTextur.tga deleted file mode 100644 index 45c9e5a9f..000000000 Binary files a/test/models-nonbsd/Ogre/Gravestone/SargTextur.tga and /dev/null differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/LICENSE b/test/models-nonbsd/Ogre/OgreSDK/LICENSE new file mode 100644 index 000000000..e7e8f4280 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/LICENSE @@ -0,0 +1,21 @@ +OGRE (www.ogre3d.org) is made available under the MIT License. + +Copyright (c) 2000-2013 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/test/models-nonbsd/Ogre/OgreSDK/README.md b/test/models-nonbsd/Ogre/OgreSDK/README.md new file mode 100644 index 000000000..e7a838cb0 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/README.md @@ -0,0 +1,10 @@ +The assets found in this folder are copied from the Ogre3D SDK samples. + +This asset set is used to test the full functionality of both binary and XML Assimp scene import of the Ogre mesh and skeleton file formats and in addition the text based material parser. + +* Binary mesh and skeleton files have not been modified. +* XML mesh and skeleton files were produced from the binary versions with the `OgreXMLConverter` tool. +* Material file was created by copying the relevant material parts from the sample sources. See the file for further information. +* Some textures were converted from .png to .jpg to reduce the file size. + +See the LICENSE file in this folder for further copyright information about these assets. \ No newline at end of file diff --git a/test/models-nonbsd/Ogre/OgreSDK/Scene.material b/test/models-nonbsd/Ogre/OgreSDK/Scene.material new file mode 100644 index 000000000..30142cade --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/Scene.material @@ -0,0 +1,52 @@ +// Materials copied from the Ogre3D SDK +// from location Samples/Media/materials/scripts + +// fish.mesh + +material Examples/Fish +{ + technique + { + pass + { + texture_unit + { + texture fish.jpg + } + } + } +} + +// ninja.mesh + +material Examples/Ninja +{ + technique + { + pass + { + + texture_unit + { + texture ninja.jpg + } + } + } +} + +// razor.mesh + +material Material__25 +{ + technique + { + pass + { + + texture_unit + { + texture razor.jpg + } + } + } +} \ No newline at end of file diff --git a/test/models-nonbsd/Ogre/OgreSDK/fish.jpg b/test/models-nonbsd/Ogre/OgreSDK/fish.jpg new file mode 100644 index 000000000..04cbf2f83 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/fish.jpg differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/fish.mesh b/test/models-nonbsd/Ogre/OgreSDK/fish.mesh new file mode 100644 index 000000000..e20f1644d Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/fish.mesh differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/fish.mesh.xml b/test/models-nonbsd/Ogre/OgreSDK/fish.mesh.xml new file mode 100644 index 000000000..b1345b9e6 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/fish.mesh.xml @@ -0,0 +1,5295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton b/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton new file mode 100644 index 000000000..7a970fda2 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton.xml b/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton.xml new file mode 100644 index 000000000..0266a02a5 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/fish.skeleton.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models-nonbsd/Ogre/OgreSDK/ninja.jpg b/test/models-nonbsd/Ogre/OgreSDK/ninja.jpg new file mode 100644 index 000000000..9397f5d91 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/ninja.jpg differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh b/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh new file mode 100644 index 000000000..0032c5589 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh.xml b/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh.xml new file mode 100644 index 000000000..7a0142580 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/ninja.mesh.xml @@ -0,0 +1,7773 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton b/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton new file mode 100644 index 000000000..787f5f753 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton.xml b/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton.xml new file mode 100644 index 000000000..b180562fa --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/ninja.skeleton.xml @@ -0,0 +1,13299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models-nonbsd/Ogre/OgreSDK/razor.jpg b/test/models-nonbsd/Ogre/OgreSDK/razor.jpg new file mode 100644 index 000000000..8acc84d77 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/razor.jpg differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/razor.mesh b/test/models-nonbsd/Ogre/OgreSDK/razor.mesh new file mode 100644 index 000000000..da4f9c8a8 Binary files /dev/null and b/test/models-nonbsd/Ogre/OgreSDK/razor.mesh differ diff --git a/test/models-nonbsd/Ogre/OgreSDK/razor.mesh.xml b/test/models-nonbsd/Ogre/OgreSDK/razor.mesh.xml new file mode 100644 index 000000000..4b5cdf948 --- /dev/null +++ b/test/models-nonbsd/Ogre/OgreSDK/razor.mesh.xml @@ -0,0 +1,3420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend b/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend deleted file mode 100644 index c3c5edef9..000000000 Binary files a/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend and /dev/null differ diff --git a/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend1 b/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend1 deleted file mode 100644 index df3e30299..000000000 Binary files a/test/models-nonbsd/Ogre/animationtest2/Animationtest2.blend1 and /dev/null differ diff --git a/test/models-nonbsd/Ogre/animationtest2/Cube.mesh.xml b/test/models-nonbsd/Ogre/animationtest2/Cube.mesh.xml deleted file mode 100644 index 59c109239..000000000 --- a/test/models-nonbsd/Ogre/animationtest2/Cube.mesh.xml +++ /dev/null @@ -1,762 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/animationtest2/Cube.skeleton.xml b/test/models-nonbsd/Ogre/animationtest2/Cube.skeleton.xml deleted file mode 100644 index fb0da67f9..000000000 --- a/test/models-nonbsd/Ogre/animationtest2/Cube.skeleton.xml +++ /dev/null @@ -1,456 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/models-nonbsd/Ogre/animationtest2/Scene.material b/test/models-nonbsd/Ogre/animationtest2/Scene.material deleted file mode 100644 index c0e448cd1..000000000 --- a/test/models-nonbsd/Ogre/animationtest2/Scene.material +++ /dev/null @@ -1,14 +0,0 @@ -material Material -{ - receive_shadows on - technique - { - pass - { - ambient 0.500000 0.500000 0.500000 1.000000 - diffuse 0.640000 0.640000 0.640000 1.000000 - specular 0.500000 0.500000 0.500000 1.000000 12.500000 - emissive 0.000000 0.000000 0.000000 1.000000 - } - } -} diff --git a/test/regression/db.zip b/test/regression/db.zip index fdb6e9d9e..12f4a18ba 100644 Binary files a/test/regression/db.zip and b/test/regression/db.zip differ diff --git a/test/regression/gen_db.py b/test/regression/gen_db.py index ade796e5f..ef10a298d 100644 --- a/test/regression/gen_db.py +++ b/test/regression/gen_db.py @@ -188,6 +188,7 @@ if __name__ == "__main__": stdout=subprocess.PIPE).communicate() ext_list = str(ext_list).lower().split(";") + # todo: Fix for multi dot extensions like .skeleton.xml ext_list = list(filter(lambda f: not f in settings.exclude_extensions, map(clean, ext_list))) diff --git a/test/regression/run.py b/test/regression/run.py index 01cefdb07..caa3a6bd0 100644 --- a/test/regression/run.py +++ b/test/regression/run.py @@ -172,6 +172,12 @@ def process_dir(d, outfile_results, zipin, result): #print("Didn't find "+fullpath+" (Hash is "+filehash+") in database") continue + # Ignore extensions via settings.py configured list + # todo: Fix for multi dot extensions like .skeleton.xml + ext = os.path.splitext(fullpath)[1].lower() + if ext != "" and ext in settings.exclude_extensions: + continue + print("-"*60 + "\n " + os.path.realpath(fullpath) + " pp: " + pppreset) outfile_actual = mkoutputdir_andgetpath(fullpath, filehash, "ACTUAL") diff --git a/test/regression/settings.py b/test/regression/settings.py index 5e2fca583..4f81cc66e 100644 --- a/test/regression/settings.py +++ b/test/regression/settings.py @@ -46,11 +46,16 @@ test scripts rely on this) """ import os + # ------------------------------------------------------------------------------- # List of file extensions to be excluded from the regression suite # File extensions are case insensitive # ------------------------------------------------------------------------------- -exclude_extensions = [".lws",".assbin",".assxml",".txt",".jpeg",".jpg",".png",".gif",".tga",".bmp"] +exclude_extensions = [ + ".lws", ".assbin", ".assxml", ".txt", ".md", + ".jpeg", ".jpg", ".png", ".gif", ".tga", ".bmp", + ".skeleton", ".skeleton.xml" +] # ------------------------------------------------------------------------------- # Post processing configurations to be included in the test. The @@ -93,8 +98,8 @@ database_name = "db" # List of directories to be processed. Paths are processed recursively. # ------------------------------------------------------------------------------- model_directories = [ -os.path.join("..","models"), -os.path.join("..","models-nonbsd") + os.path.join("..","models"), + os.path.join("..","models-nonbsd") ] # ------------------------------------------------------------------------------- @@ -114,5 +119,8 @@ dump_header_skip = 500 # ------------------------------------------------------------------------------- results = os.path.join("..","results") +# Create results directory if it does not exist +if not os.path.exists(results): + os.makedirs(results) # vim: ai ts=4 sts=4 et sw=4 diff --git a/test/regression/utils.py b/test/regression/utils.py index 0efebcd2b..931aacedf 100644 --- a/test/regression/utils.py +++ b/test/regression/utils.py @@ -87,20 +87,28 @@ def find_assimp_or_die(): global assimp_bin_path if os.name == "nt": + search_x86 = [ + os.path.join("..","..","bin","assimpcmd_release-dll_Win32","assimp.exe"), + os.path.join("..","..","bin","x86","assimp"), + os.path.join("..","..","bin","Release","assimp.exe") + ] if platform.machine() == "x86": - search = [os.path.join("..","..","bin","assimpcmd_release-dll_Win32","assimp.exe"), - os.path.join("..","..","bin","x86","assimp")] - + search = search_x86 else: # amd64, hopefully - search = [os.path.join("..","..","bin","assimpcmd_release-dll_x64","assimp.exe"), - os.path.join("..","..","bin","x64","assimp")] + search = [ + os.path.join("..","..","bin","assimpcmd_release-dll_x64","assimp.exe"), + os.path.join("..","..","bin","x64","assimp") + ] + # x64 platform does not guarantee a x64 build. Also look for x86 as last paths. + search += search_x86 assimp_bin_path = locate_file(search) if assimp_bin_path is None: print("Can't locate assimp_cmd binary") + print("Looked in", search) sys.exit(-5) - print("Located assimp/assimp_cmd binary at ",assimp_bin_path) + print("Located assimp/assimp_cmd binary from", assimp_bin_path) elif os.name == "posix": #search = [os.path.join("..","..","bin","gcc","assimp"), # os.path.join("/usr","local","bin",'assimp')] @@ -110,8 +118,6 @@ def find_assimp_or_die(): print("Unsupported operating system") sys.exit(-5) - - if __name__ == '__main__': find_assimp_or_die()