diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2014-06-27 09:31:11 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2014-07-17 10:14:00 +0200 |
commit | 09687cfaade1e3baa693f02861722ea860f3c716 (patch) | |
tree | 4d1084ee95ec45e880739ddf709ae32fe73d3caa /src/3rdparty | |
parent | 22829fba69a36e447a14dcd59149164d482b3fe3 (diff) |
Upgrade to Assimp 3.1.1
https://github.com/assimp/assimp/releases/tag/v3.1.1
This commit imports assimp 3.1.1, including CHANGES, CREDITS, LICENSE,
README, Readme.md, and code, contrib, include directories. contrib/zlib,
contrib/cppunit-1.12.1/, contrib/cppunit_note.txt were excluded in this
change.
assimp.pri was also updated.
revision.h was generated from revision.h.in.
Change-Id: I7c0597eae9eee7f06a1170968b5fef6fd46b6f0d
Reviewed-by: Liang Qi <liang.qi@digia.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/3rdparty')
56 files changed, 5025 insertions, 3059 deletions
diff --git a/src/3rdparty/assimp/CREDITS b/src/3rdparty/assimp/CREDITS index 33f4acce4..070a15431 100644 --- a/src/3rdparty/assimp/CREDITS +++ b/src/3rdparty/assimp/CREDITS @@ -3,8 +3,8 @@ Open Asset Import Library (Assimp) Developers and Contributors =============================================================== -The following is the list of all constributors. -Thanks for your help! +The following is a non-exhaustive list of all constributors over the years. +If you think your name should be listed here, drop us a line and we'll add you. - Alexander Gessler, 3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design). @@ -41,7 +41,7 @@ Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 w - Andreas Nagel First Assimp testing & verification under Windows Vista 64 Bit. -- Marius Schröder +- Marius Schr�der Allowed us to use many of his models for screenshots and testing. - Christian Schubert @@ -92,7 +92,7 @@ Contributed the 'SimpleTexturedOpenGl' sample. - Matthias Fauconneau Contributed a fix for the Q3-BSP loader. -- Jørgen P. Tjernø +- J�rgen P. Tjern� Contributed updated and improved xcode workspaces - drparallax @@ -137,7 +137,7 @@ GCC/Linux fixes for the SimpleOpenGL sample. - Brian Miller Bugfix for a compiler fix for iOS on arm. -- Séverin Lemaignan +- S�verin Lemaignan Rewrite of PyAssimp, distutils and Python3 support - albert-wang @@ -145,3 +145,6 @@ Bugfixes for the collada parser - Ya ping Jin Bugfixes for uv-tanget calculation. + +- Jonne Nauha +Ogre Binary format support diff --git a/src/3rdparty/assimp/Readme.md b/src/3rdparty/assimp/Readme.md index 380e4386f..214417798 100644 --- a/src/3rdparty/assimp/Readme.md +++ b/src/3rdparty/assimp/Readme.md @@ -1,9 +1,7 @@ Open Asset Import Library (assimp) ======== -Open Asset Import Library is a Open Source library designed to load various __3d file formats and convert them into a single, in-memory format__. It supports more than __30 file formats__ for import and a growing selection of file formats for export. Additionally, assimp features various __post processing tools__ to refine the imported data: _normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials_ and many more. - -Its short name under which it is commonly known is __assimp__. +Open Asset Import Library is a Open Source library designed to load various __3d file formats and convert them into a shared, in-memory format__. It supports more than __30 file formats__ for import and a growing selection of file formats for export. Additionally, assimp features various __post processing tools__ to refine the imported data: _normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials_ and many more. This is the development trunk of assimp containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories. According to [Travis-CI] (https://travis-ci.org/), the current build status of the trunk is [![Build Status](https://travis-ci.org/assimp/assimp.png)](https://travis-ci.org/assimp/assimp) @@ -43,6 +41,7 @@ The library provides importers for a lot of file formats, including: - BVH - B3D - NDO +- Ogre Binary - Ogre XML - Q3D @@ -56,6 +55,7 @@ Exporters include: - STL - OBJ - PLY +- JSON (for WebGl, via https://github.com/acgessler/assimp2json) See [the full list here](http://assimp.sourceforge.net/main_features_formats.html). diff --git a/src/3rdparty/assimp/assimp.pri b/src/3rdparty/assimp/assimp.pri index bf7fc2fdc..634a8e611 100644 --- a/src/3rdparty/assimp/assimp.pri +++ b/src/3rdparty/assimp/assimp.pri @@ -117,7 +117,6 @@ HEADERS += revision.h \ code/LWOFileData.h \ code/LWOLoader.h \ code/LWSLoader.h \ - code/M3Importer.h \ code/MakeVerboseFormat.h \ code/MaterialSystem.h \ code/MD2FileData.h \ @@ -145,8 +144,6 @@ HEADERS += revision.h \ code/ObjFileParser.h \ code/ObjTools.h \ code/OFFLoader.h \ - code/OgreImporter.hpp \ - code/OgreXmlHelper.hpp \ code/OptimizeGraph.h \ code/OptimizeMeshes.h \ code/ParsingUtils.h \ @@ -157,7 +154,6 @@ HEADERS += revision.h \ code/PretransformVertices.h \ code/ProcessHelper.h \ code/Profiler.h \ - code/pstdint.h \ code/Q3BSPFileData.h \ code/Q3BSPFileImporter.h \ code/Q3BSPFileParser.h \ @@ -246,6 +242,17 @@ HEADERS += revision.h \ include/assimp/vector2.h \ include/assimp/vector3.h \ include/assimp/version.h \ + include/assimp/vector2.inl \ + include/assimp/vector3.inl \ + include/assimp/color4.inl \ + include/assimp/quaternion.inl \ + include/assimp/matrix3x3.inl \ + include/assimp/matrix4x4.inl \ + include/assimp/material.inl \ + include/assimp/metadata.h \ + include/assimp/Compiler/poppack1.h \ + include/assimp/Compiler/pushpack1.h \ + include/assimp/Compiler/pstdint.h \ code/BoostWorkaround/boost/foreach.hpp \ code/BoostWorkaround/boost/format.hpp \ code/BoostWorkaround/boost/lexical_cast.hpp \ @@ -259,8 +266,6 @@ HEADERS += revision.h \ code/BoostWorkaround/boost/static_assert.hpp \ code/BoostWorkaround/boost/timer.hpp \ contrib/poly2tri/poly2tri/poly2tri.h \ - include/assimp/Compiler/poppack1.h \ - include/assimp/Compiler/pushpack1.h \ code/BoostWorkaround/boost/math/common_factor_rt.hpp \ code/BoostWorkaround/boost/tuple/tuple.hpp \ contrib/poly2tri/poly2tri/common/shapes.h \ @@ -269,13 +274,6 @@ HEADERS += revision.h \ contrib/poly2tri/poly2tri/sweep/cdt.h \ contrib/poly2tri/poly2tri/sweep/sweep.h \ contrib/poly2tri/poly2tri/sweep/sweep_context.h \ - include/assimp/vector2.inl \ - include/assimp/vector3.inl \ - include/assimp/color4.inl \ - include/assimp/quaternion.inl \ - include/assimp/matrix3x3.inl \ - include/assimp/matrix4x4.inl \ - include/assimp/material.inl \ code/SmoothingGroups.inl \ code/BlenderDNA.inl \ code/FBXConverter.h \ @@ -291,7 +289,9 @@ HEADERS += revision.h \ code/OgreParsingUtils.h \ code/FBXCompileConfig.h \ code/STEPFileEncoding.h \ - include/assimp/metadata.h + code/OgreBinarySerializer.h \ + code/OgreStructs.h \ + code/OgreXmlSerializer.h SOURCES += code/3DSConverter.cpp \ code/3DSLoader.cpp \ @@ -353,7 +353,6 @@ SOURCES += code/3DSConverter.cpp \ code/LWOLoader.cpp \ code/LWOMaterial.cpp \ code/LWSLoader.cpp \ - code/M3Importer.cpp \ code/MakeVerboseFormat.cpp \ code/MaterialSystem.cpp \ code/MD2Loader.cpp \ @@ -373,8 +372,6 @@ SOURCES += code/3DSConverter.cpp \ code/OFFLoader.cpp \ code/OgreImporter.cpp \ code/OgreMaterial.cpp \ - code/OgreMesh.cpp \ - code/OgreSkeleton.cpp \ code/OptimizeGraph.cpp \ code/OptimizeMeshes.cpp \ code/PlyExporter.cpp \ @@ -442,6 +439,10 @@ SOURCES += code/3DSConverter.cpp \ code/IFCBoolean.cpp \ code/IFCOpenings.cpp \ code/FBXConverter.cpp \ - code/STEPFileEncoding.cpp + code/STEPFileEncoding.cpp \ + code/OgreBinarySerializer.cpp \ + code/OgreStructs.cpp \ + code/OgreXmlSerializer.cpp + diff --git a/src/3rdparty/assimp/code/AssimpPCH.cpp b/src/3rdparty/assimp/code/AssimpPCH.cpp index 59e2620f8..1f61feb2c 100644 --- a/src/3rdparty/assimp/code/AssimpPCH.cpp +++ b/src/3rdparty/assimp/code/AssimpPCH.cpp @@ -63,7 +63,7 @@ ASSIMP_API unsigned int aiGetCompileFlags () { } // include current build revision, which is even updated from time to time -- :-) -#include "../revision.h" +#include "revision.h" // ------------------------------------------------------------------------------------------------ ASSIMP_API unsigned int aiGetVersionRevision () diff --git a/src/3rdparty/assimp/code/AssimpPCH.h b/src/3rdparty/assimp/code/AssimpPCH.h index 2c7a6bee4..624ecc39b 100644 --- a/src/3rdparty/assimp/code/AssimpPCH.h +++ b/src/3rdparty/assimp/code/AssimpPCH.h @@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw #if defined( _MSC_VER) && (_MSC_VER < 1600) -# include "pstdint.h" +# include "../include/assimp/Compiler/pstdint.h" #else # include <stdint.h> #endif diff --git a/src/3rdparty/assimp/code/BlenderLoader.cpp b/src/3rdparty/assimp/code/BlenderLoader.cpp index 0b5c71333..8f9b85b26 100644 --- a/src/3rdparty/assimp/code/BlenderLoader.cpp +++ b/src/3rdparty/assimp/code/BlenderLoader.cpp @@ -999,7 +999,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co } // ------------------------------------------------------------------------------------------------ -aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* /*camera*/, ConversionData& /*conv_data*/) +aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* camera, ConversionData& /*conv_data*/) { ScopeGuard<aiCamera> out(new aiCamera()); out->mName = obj->id.name+2; @@ -1010,7 +1010,7 @@ aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, } // ------------------------------------------------------------------------------------------------ -aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/) +aiLight* BlenderImporter::ConvertLight(const Scene& in, const Object* obj, const Lamp* lamp, ConversionData& conv_data) { ScopeGuard<aiLight> out(new aiLight()); out->mName = obj->id.name+2; diff --git a/src/3rdparty/assimp/code/BlenderModifier.cpp b/src/3rdparty/assimp/code/BlenderModifier.cpp index afb6181b0..6ed31271c 100644 --- a/src/3rdparty/assimp/code/BlenderModifier.cpp +++ b/src/3rdparty/assimp/code/BlenderModifier.cpp @@ -248,6 +248,15 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co } } + // Only reverse the winding order if an odd number of axes were mirrored. + if (xs * ys * zs < 0) { + for( unsigned int i = 0; i < mesh->mNumFaces; i++) { + aiFace& face = mesh->mFaces[i]; + for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi) + std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]); + } + } + conv_data.meshes->push_back(mesh); } unsigned int* nind = new unsigned int[out.mNumMeshes*2]; diff --git a/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_array.hpp b/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_array.hpp index 872d57665..9847d9f82 100644 --- a/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_array.hpp +++ b/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_array.hpp @@ -2,7 +2,7 @@ #ifndef INCLUDED_AI_BOOST_SHARED_ARRAY #define INCLUDED_AI_BOOST_SHARED_ARRAY -#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED +#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED // ------------------------------ // Internal stub diff --git a/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_ptr.hpp b/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_ptr.hpp index bba9d0674..fe9dcd8be 100644 --- a/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_ptr.hpp +++ b/src/3rdparty/assimp/code/BoostWorkaround/boost/shared_ptr.hpp @@ -2,7 +2,7 @@ #ifndef INCLUDED_AI_BOOST_SHARED_PTR #define INCLUDED_AI_BOOST_SHARED_PTR -#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED // ------------------------------ // Internal stub @@ -254,4 +254,4 @@ inline shared_ptr<T> const_pointer_cast( shared_ptr<U> ptr) #else # error "shared_ptr.h was already included" #endif -#endif // INCLUDED_AI_BOOST_SCOPED_PTR +#endif // INCLUDED_AI_BOOST_SHARED_PTR diff --git a/src/3rdparty/assimp/code/BoostWorkaround/boost/tuple/tuple.hpp b/src/3rdparty/assimp/code/BoostWorkaround/boost/tuple/tuple.hpp index 7820aa60a..0ff61d9c3 100644 --- a/src/3rdparty/assimp/code/BoostWorkaround/boost/tuple/tuple.hpp +++ b/src/3rdparty/assimp/code/BoostWorkaround/boost/tuple/tuple.hpp @@ -100,7 +100,7 @@ namespace boost { }; // dummy - list_elem& operator = (const list_elem& /*other*/) { + list_elem& operator = (const list_elem& other) { return *this; } diff --git a/src/3rdparty/assimp/code/CMakeLists.txt b/src/3rdparty/assimp/code/CMakeLists.txt index 994904fdc..796711316 100644 --- a/src/3rdparty/assimp/code/CMakeLists.txt +++ b/src/3rdparty/assimp/code/CMakeLists.txt @@ -10,7 +10,7 @@ SET( HEADER_PATH ../include/assimp ) SET( COMPILER_HEADERS ${HEADER_PATH}/Compiler/pushpack1.h ${HEADER_PATH}/Compiler/poppack1.h - pstdint.h + ${HEADER_PATH}/Compiler/pstdint.h ) SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS}) @@ -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/src/3rdparty/assimp/code/ColladaLoader.cpp b/src/3rdparty/assimp/code/ColladaLoader.cpp index 86406aad9..058baf9c9 100644 --- a/src/3rdparty/assimp/code/ColladaLoader.cpp +++ b/src/3rdparty/assimp/code/ColladaLoader.cpp @@ -133,6 +133,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I mLights.clear(); mCameras.clear(); mTextures.clear(); + mAnims.clear(); // parse the input file ColladaParser parser( pIOHandler, pFile); @@ -904,6 +905,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars pScene->mAnimations = new aiAnimation*[mAnims.size()]; std::copy( mAnims.begin(), mAnims.end(), pScene->mAnimations); } + + mAnims.clear(); } // ------------------------------------------------------------------------------------------------ diff --git a/src/3rdparty/assimp/code/FBXAnimation.cpp b/src/3rdparty/assimp/code/FBXAnimation.cpp index 3bf60acd4..ccf1d82f4 100644 --- a/src/3rdparty/assimp/code/FBXAnimation.cpp +++ b/src/3rdparty/assimp/code/FBXAnimation.cpp @@ -59,7 +59,7 @@ namespace FBX { using namespace Util; // ------------------------------------------------------------------------------------------------ -AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/) +AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc) : Object(id, element, name) { const Scope& sc = GetRequiredScope(element); diff --git a/src/3rdparty/assimp/code/FBXConverter.cpp b/src/3rdparty/assimp/code/FBXConverter.cpp index 82f552576..89854fc8e 100644 --- a/src/3rdparty/assimp/code/FBXConverter.cpp +++ b/src/3rdparty/assimp/code/FBXConverter.cpp @@ -121,7 +121,7 @@ public: if(mat) { if (materials_converted.find(mat) == materials_converted.end()) { - ConvertMaterial(*mat); + ConvertMaterial(*mat, 0); } } } @@ -783,8 +783,8 @@ private: data->Set(index++, prop.first, interpreted->Value()); else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >()) data->Set(index++, prop.first, interpreted->Value()); - else if (const TypedProperty<aiString>* interpreted = prop.second->As<TypedProperty<aiString> >()) - data->Set(index++, prop.first, interpreted->Value()); + else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >()) + data->Set(index++, prop.first, aiString(interpreted->Value())); else if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >()) data->Set(index++, prop.first, interpreted->Value()); else @@ -1320,7 +1320,7 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl, + void ConvertCluster(std::vector<aiBone*>& bones, const Model& model, const Cluster& cl, std::vector<size_t>& out_indices, std::vector<size_t>& index_out_indices, std::vector<size_t>& count_out_indices, @@ -1363,7 +1363,7 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& /*geo*/, + void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, MatIndexArray::value_type materialIndex) { // locate source materials for this mesh @@ -1381,7 +1381,7 @@ private: return; } - out->mMaterialIndex = ConvertMaterial(*mat); + out->mMaterialIndex = ConvertMaterial(*mat, &geo); materials_converted[mat] = out->mMaterialIndex; } @@ -1411,7 +1411,7 @@ private: // ------------------------------------------------------------------------------------------------ // Material -> aiMaterial - unsigned int ConvertMaterial(const Material& material) + unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh) { const PropertyTable& props = material.Props(); @@ -1440,8 +1440,8 @@ private: SetShadingPropertiesCommon(out_mat,props); // texture assignments - SetTextureProperties(out_mat,material.Textures()); - SetTextureProperties(out_mat,material.LayeredTextures()); + SetTextureProperties(out_mat,material.Textures(), mesh); + SetTextureProperties(out_mat,material.LayeredTextures(), mesh); return static_cast<unsigned int>(materials.size() - 1); } @@ -1450,7 +1450,7 @@ private: // ------------------------------------------------------------------------------------------------ void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const std::string& propName, - aiTextureType target) + aiTextureType target, const MeshGeometry* const mesh) { TextureMap::const_iterator it = textures.find(propName); if(it == textures.end()) { @@ -1495,18 +1495,48 @@ private: std::find(materials.begin(),materials.end(),out_mat) )); - uvIndex = -1; - BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { - const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first); - if(!mesh) { - continue; - } - - const MatIndexArray& mats = mesh->GetMaterialIndices(); - if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { - continue; - } + uvIndex = -1; + if (!mesh) + { + BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { + const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first); + if(!mesh) { + continue; + } + + const MatIndexArray& mats = mesh->GetMaterialIndices(); + if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if(mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if(name == uvSet) { + index = static_cast<int>(i); + break; + } + } + if(index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if(uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + } + else + { int index = -1; for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { if(mesh->GetTextureCoords(i).empty()) { @@ -1520,17 +1550,12 @@ private: } if(index == -1) { FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; } if(uvIndex == -1) { uvIndex = index; } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } + } if(uvIndex == -1) { FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); @@ -1546,7 +1571,7 @@ private: // ------------------------------------------------------------------------------------------------ void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const std::string& propName, - aiTextureType target) + aiTextureType target, const MeshGeometry* const mesh) { LayeredTextureMap::const_iterator it = layeredTextures.find(propName); if(it == layeredTextures.end()) { @@ -1590,18 +1615,47 @@ private: std::find(materials.begin(),materials.end(),out_mat) )); - uvIndex = -1; - BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { - const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first); - if(!mesh) { - continue; - } + uvIndex = -1; + if (!mesh) + { + BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { + const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first); + if(!mesh) { + continue; + } - const MatIndexArray& mats = mesh->GetMaterialIndices(); - if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { - continue; - } + const MatIndexArray& mats = mesh->GetMaterialIndices(); + if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { + continue; + } + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if(mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if(name == uvSet) { + index = static_cast<int>(i); + break; + } + } + if(index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if(uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + } + else + { int index = -1; for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { if(mesh->GetTextureCoords(i).empty()) { @@ -1615,17 +1669,12 @@ private: } if(index == -1) { FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; } if(uvIndex == -1) { uvIndex = index; } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } + } if(uvIndex == -1) { FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); @@ -1638,33 +1687,33 @@ private: } // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures) + void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh) { - TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE); - TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT); - TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE); - TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR); - TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY); - TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION); - TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT); - TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS); - TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT); - TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS); + TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); + TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh); + TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); + TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh); + TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh); + TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); + TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh); + TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh); + TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh); } // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures) + void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) { - TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE); - TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT); - TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR); - TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY); - TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION); - TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT); - TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS); - TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT); - TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS); + TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh); } @@ -2298,8 +2347,8 @@ private: // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, - const Model& /*target*/, + aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, + const Model& target, const std::vector<const AnimationCurveNode*>& curves, const LayerMap& layer_map, double& max_time, @@ -2329,8 +2378,8 @@ private: // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, - const Model& /*target*/, + aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, + const Model& target, const std::vector<const AnimationCurveNode*>& curves, const LayerMap& layer_map, double& max_time, @@ -2782,7 +2831,7 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/, + void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& layers, double& maxTime, double& minTime) { @@ -2803,7 +2852,7 @@ private: // ------------------------------------------------------------------------------------------------ void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, + const LayerMap& layers, double& maxTime, double& minTime) { @@ -2821,7 +2870,7 @@ private: // ------------------------------------------------------------------------------------------------ void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, + const LayerMap& layers, double& maxTime, double& minTime, Model::RotOrder order) diff --git a/src/3rdparty/assimp/code/FBXImportSettings.h b/src/3rdparty/assimp/code/FBXImportSettings.h index 47fc1d6a6..2020273d7 100644 --- a/src/3rdparty/assimp/code/FBXImportSettings.h +++ b/src/3rdparty/assimp/code/FBXImportSettings.h @@ -53,7 +53,7 @@ struct ImportSettings ImportSettings() : strictMode(true) , readAllLayers(true) - , readAllMaterials() + , readAllMaterials(false) , readMaterials(true) , readCameras(true) , readLights(true) diff --git a/src/3rdparty/assimp/code/FBXMaterial.cpp b/src/3rdparty/assimp/code/FBXMaterial.cpp index fffa14fd3..a5e2a1169 100644 --- a/src/3rdparty/assimp/code/FBXMaterial.cpp +++ b/src/3rdparty/assimp/code/FBXMaterial.cpp @@ -207,7 +207,7 @@ Texture::~Texture() } -LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name) +LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Object(id,element,name) ,texture(0) ,blendMode(BlendMode_Modulate) diff --git a/src/3rdparty/assimp/code/FBXParser.cpp b/src/3rdparty/assimp/code/FBXParser.cpp index 3274bca11..f6dc2e7e2 100644 --- a/src/3rdparty/assimp/code/FBXParser.cpp +++ b/src/3rdparty/assimp/code/FBXParser.cpp @@ -364,14 +364,24 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out) } if (data[0] == 'F') { - ai_assert(t.end() - data == 5); - // no byte swapping needed for ieee floats - return *reinterpret_cast<const float*>(data+1); + // Actual size validation happens during Tokenization so + // this is valid as an assertion. + ai_assert(t.end() - data == sizeof(float) + 1); + // Initially, we did reinterpret_cast, breaking strict aliasing rules. + // This actually caused trouble on Android, so let's be safe this time. + // https://github.com/assimp/assimp/issues/24 + + float out_float; + ::memcpy(&out_float, data+1, sizeof(float)); + return out_float; } else { - ai_assert(t.end() - data == 9); - // no byte swapping needed for ieee floats - return static_cast<float>(*reinterpret_cast<const double*>(data+1)); + ai_assert(t.end() - data == sizeof(double) + 1); + + // Same + double out_double; + ::memcpy(&out_double, data+1, sizeof(double)); + return static_cast<float>(out_double); } } @@ -496,7 +506,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, std::vector<char>& buff, - const Element& /*el*/) + const Element& el) { ai_assert(static_cast<size_t>(end-data) >= 4); // runtime check for this happens at tokenization stage diff --git a/src/3rdparty/assimp/code/FBXProperties.h b/src/3rdparty/assimp/code/FBXProperties.h index 6e121cd4c..9219c3eea 100644 --- a/src/3rdparty/assimp/code/FBXProperties.h +++ b/src/3rdparty/assimp/code/FBXProperties.h @@ -146,7 +146,6 @@ inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue, bool ignoreTemplate = false) { - (void)ignoreTemplate; // Unused const Property* const prop = in.Get(name); if(!prop) { return defaultValue; @@ -168,7 +167,6 @@ inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool ignoreTemplate = false) { - (void)ignoreTemplate; // Unused const Property* const prop = in.Get(name); if(!prop) { result = false; diff --git a/src/3rdparty/assimp/code/IFCBoolean.cpp b/src/3rdparty/assimp/code/IFCBoolean.cpp index 7d3840710..8573e4d62 100644 --- a/src/3rdparty/assimp/code/IFCBoolean.cpp +++ b/src/3rdparty/assimp/code/IFCBoolean.cpp @@ -85,7 +85,7 @@ Intersect IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const I // ------------------------------------------------------------------------------------------------ void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result, const TempMesh& first_operand, - ConversionData& /*conv*/) + ConversionData& conv) { ai_assert(hs != NULL); diff --git a/src/3rdparty/assimp/code/IFCLoader.cpp b/src/3rdparty/assimp/code/IFCLoader.cpp index 84ff9e318..9963ce70a 100644 --- a/src/3rdparty/assimp/code/IFCLoader.cpp +++ b/src/3rdparty/assimp/code/IFCLoader.cpp @@ -686,7 +686,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion } // add an output node for this spatial structure - std::unique_ptr<aiNode> nd(new aiNode()); + std::auto_ptr<aiNode> nd(new aiNode()); nd->mName.Set(el.GetClassName()+"_"+(el.Name?el.Name.Get():"Unnamed")+"_"+el.GlobalId); nd->mParent = parent; @@ -773,7 +773,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion const IfcFeatureElementSubtraction& open = fills->RelatedOpeningElement; // move opening elements to a separate node since they are semantically different than elements that are just 'contained' - std::unique_ptr<aiNode> nd_aggr(new aiNode()); + std::auto_ptr<aiNode> nd_aggr(new aiNode()); nd_aggr->mName.Set("$RelVoidsElement"); nd_aggr->mParent = nd.get(); @@ -818,7 +818,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion } // move aggregate elements to a separate node since they are semantically different than elements that are just 'contained' - std::unique_ptr<aiNode> nd_aggr(new aiNode()); + std::auto_ptr<aiNode> nd_aggr(new aiNode()); nd_aggr->mName.Set("$RelAggregates"); nd_aggr->mParent = nd.get(); diff --git a/src/3rdparty/assimp/code/IFCMaterial.cpp b/src/3rdparty/assimp/code/IFCMaterial.cpp index 520590965..4708cdd84 100644 --- a/src/3rdparty/assimp/code/IFCMaterial.cpp +++ b/src/3rdparty/assimp/code/IFCMaterial.cpp @@ -159,7 +159,7 @@ unsigned int ProcessMaterials(const IFC::IfcRepresentationItem& item, Conversion IFCImporter::LogWarn("ignoring surface side marker on IFC::IfcSurfaceStyle: " + side); } - std::unique_ptr<aiMaterial> mat(new aiMaterial()); + std::auto_ptr<aiMaterial> mat(new aiMaterial()); FillMaterial(mat.get(),surf,conv); diff --git a/src/3rdparty/assimp/code/IFCOpenings.cpp b/src/3rdparty/assimp/code/IFCOpenings.cpp index e212097f1..c26574cc3 100644 --- a/src/3rdparty/assimp/code/IFCOpenings.cpp +++ b/src/3rdparty/assimp/code/IFCOpenings.cpp @@ -259,7 +259,7 @@ BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly) // ------------------------------------------------------------------------------------------------ void InsertWindowContours(const ContourVector& contours, - const std::vector<TempOpening>& /*openings*/, + const std::vector<TempOpening>& openings, TempMesh& curmesh) { // fix windows - we need to insert the real, polygonal shapes into the quadratic holes that we have now @@ -1741,4 +1741,4 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std: #undef from_int64 #undef one_vec -#endif +#endif
\ No newline at end of file diff --git a/src/3rdparty/assimp/code/IFCProfile.cpp b/src/3rdparty/assimp/code/IFCProfile.cpp index 1e2f47cbd..48ccd568e 100644 --- a/src/3rdparty/assimp/code/IFCProfile.cpp +++ b/src/3rdparty/assimp/code/IFCProfile.cpp @@ -101,7 +101,7 @@ void ProcessOpenProfile(const IfcArbitraryOpenProfileDef& def, TempMesh& meshout } // ------------------------------------------------------------------------------------------------ -void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& /*conv*/) +void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& conv) { if(const IfcRectangleProfileDef* const cprofile = def.ToPtr<IfcRectangleProfileDef>()) { const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f; diff --git a/src/3rdparty/assimp/code/IFCReaderGen.cpp b/src/3rdparty/assimp/code/IFCReaderGen.cpp index 23361164a..c17805172 100644 --- a/src/3rdparty/assimp/code/IFCReaderGen.cpp +++ b/src/3rdparty/assimp/code/IFCReaderGen.cpp @@ -1045,7 +1045,7 @@ void IFC::GetSchema(EXPRESS::ConversionSchema& out) namespace STEP { // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill<NotImplemented>(const STEP::DB& /*db*/, const LIST& /*params*/, NotImplemented* /*in*/) +template <> size_t GenericFill<NotImplemented>(const STEP::DB& db, const LIST& params, NotImplemented* in) { return 0; } @@ -1253,7 +1253,7 @@ template <> size_t GenericFill<IfcPerformanceHistory>(const DB& db, const LIST& return base; } // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill<IfcRepresentationItem>(const DB& /*db*/, const LIST& /*params*/, IfcRepresentationItem* /*in*/) +template <> size_t GenericFill<IfcRepresentationItem>(const DB& db, const LIST& params, IfcRepresentationItem* in) { size_t base = 0; return base; @@ -1715,7 +1715,7 @@ template <> size_t GenericFill<IfcPlateType>(const DB& db, const LIST& params, I return base; } // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill<IfcObjectPlacement>(const DB& /*db*/, const LIST& /*params*/, IfcObjectPlacement* /*in*/) +template <> size_t GenericFill<IfcObjectPlacement>(const DB& db, const LIST& params, IfcObjectPlacement* in) { size_t base = 0; return base; diff --git a/src/3rdparty/assimp/code/LWOAnimation.cpp b/src/3rdparty/assimp/code/LWOAnimation.cpp index ff7270267..e1ef576ed 100644 --- a/src/3rdparty/assimp/code/LWOAnimation.cpp +++ b/src/3rdparty/assimp/code/LWOAnimation.cpp @@ -54,8 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "LWOFileData.h" -#include <functional> - using namespace Assimp; using namespace Assimp::LWO; diff --git a/src/3rdparty/assimp/code/M3Importer.cpp b/src/3rdparty/assimp/code/M3Importer.cpp deleted file mode 100644 index dfbbe076e..000000000 --- a/src/3rdparty/assimp/code/M3Importer.cpp +++ /dev/null @@ -1,371 +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_M3_IMPORTER - -#include "M3Importer.h" -#include <sstream> - -namespace Assimp { -namespace M3 { - -static const aiImporterDesc desc = { - "StarCraft M3 Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "m3" -}; - -// ------------------------------------------------------------------------------------------------ -// Constructor. -M3Importer::M3Importer() : - m_pHead( NULL ), - m_pRefs( NULL ), - m_Buffer() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor. -M3Importer::~M3Importer() -{ - m_pHead = NULL; - m_pRefs = NULL; -} - -// ------------------------------------------------------------------------------------------------ -// Check for readable file format. -bool M3Importer::CanRead( const std::string &rFile, IOSystem* /*pIOHandler*/, bool checkSig ) const -{ - if ( !checkSig ) { - return SimpleExtensionCheck( rFile, "m3" ); - } - - return false; -} - -// ------------------------------------------------------------------------------------------------ -const aiImporterDesc* M3Importer::GetInfo () const -{ - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -void M3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) -{ - ai_assert( !pFile.empty() ); - - const std::string mode = "rb"; - boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode ) ); - if ( NULL == file.get() ) { - throw DeadlyImportError( "Failed to open file " + pFile + "."); - } - - // Get the file-size and validate it, throwing an exception when it fails - const size_t filesize = file->FileSize(); - if( filesize < 1 ) { - throw DeadlyImportError( "M3-file is too small."); - } - - m_Buffer.resize( filesize ); - size_t readsize = file->Read( &m_Buffer[ 0 ], sizeof( unsigned char ), filesize ); - ai_assert( readsize == filesize ); - - m_pHead = reinterpret_cast<MD33*>( &m_Buffer[ 0 ] ); - m_pRefs = reinterpret_cast<ReferenceEntry*>( &m_Buffer[ 0 ] + m_pHead->ofsRefs ); - - MODL20* pMODL20( NULL ); - MODL23* pMODL23( NULL ); - - VertexExt* pVerts1( NULL ); - Vertex* pVerts2( NULL ); - - DIV *pViews( NULL ); - Region* regions( NULL ); - uint16* faces( NULL ); - - uint32 nVertices = 0; - - bool ok = true; - switch( m_pRefs[ m_pHead->MODL.ref ].type ) { - case 20: - pMODL20 = GetEntries<MODL20>( m_pHead->MODL ); - if ( ( pMODL20->flags & 0x20000) != 0 ) { // Has vertices - if( (pMODL20->flags & 0x40000) != 0 ) { // Has extra 4 byte - pVerts1 = GetEntries<VertexExt>( pMODL20->vertexData ); - nVertices = pMODL20->vertexData.nEntries/sizeof(VertexExt); - } - else { - pVerts2 = GetEntries<Vertex>( pMODL20->vertexData ); - nVertices = pMODL20->vertexData.nEntries / sizeof( Vertex ); - } - } - pViews = GetEntries<DIV>( pMODL20->views ); - break; - - case 23: - pMODL23 = GetEntries<MODL23>(m_pHead->MODL ); - if( (pMODL23->flags & 0x20000) != 0 ) { // Has vertices - if( (pMODL23->flags & 0x40000) != 0 ) { // Has extra 4 byte - pVerts1 = GetEntries<VertexExt>( pMODL23->vertexData ); - nVertices = pMODL23->vertexData.nEntries/sizeof( VertexExt ); - } - else { - pVerts2 = GetEntries<Vertex>( pMODL23->vertexData ); - nVertices = pMODL23->vertexData.nEntries/sizeof( Vertex ); - } - } - pViews = GetEntries<DIV>( pMODL23->views ); - break; - - default: - ok = false; - break; - } - - // Everything ok, if not throw an exception - if ( !ok ) { - throw DeadlyImportError( "Failed to open file " + pFile + "."); - } - - // Get all region data - regions = GetEntries<Region>( pViews->regions ); - - // Get the face data - faces = GetEntries<uint16>( pViews->faces ); - - // Convert the vertices - std::vector<aiVector3D> vertices; - vertices.resize( nVertices ); - unsigned int offset = 0; - for ( unsigned int i = 0; i < nVertices; i++ ) { - if ( pVerts1 ) { - vertices[ offset ].Set( pVerts1[ i ].pos.x, pVerts1[ i ].pos.y, pVerts1[ i ].pos.z ); - ++offset; - } - - if ( pVerts2 ) { - vertices[ offset ].Set( pVerts2[ i ].pos.x, pVerts2[ i ].pos.y, pVerts2[ i ].pos.z ); - ++offset; - } - } - - // Write the UV coordinates - offset = 0; - std::vector<aiVector3D> uvCoords; - uvCoords.resize( nVertices ); - for( unsigned int i = 0; i < nVertices; ++i ) { - if( pVerts1 ) { - float u = (float) pVerts1[ i ].uv[ 0 ] / 2048; - float v = (float) pVerts1[ i ].uv[ 1 ] / 2048; - uvCoords[ offset ].Set( u, v, 0.0f ); - ++offset; - } - - if( pVerts2 ) { - float u = (float) pVerts2[ i ].uv[ 0 ] / 2048; - float v = (float) pVerts2[ i ].uv[ 1 ] / 2048; - uvCoords[ offset ].Set( u, v, 0.0f ); - ++offset; - } - } - - // Compute the normals - std::vector<aiVector3D> normals; - normals.resize( nVertices ); - float w = 0.0f; - Vec3D norm; - offset = 0; - for( unsigned int i = 0; i < nVertices; i++ ) { - w = 0.0f; - if( pVerts1 ) { - norm.x = (float) 2*pVerts1[ i ].normal[ 0 ]/255.0f - 1; - norm.y = (float) 2*pVerts1[ i ].normal[ 1 ]/255.0f - 1; - norm.z = (float) 2*pVerts1[ i ].normal[ 2 ]/255.0f - 1; - w = (float) pVerts1[ i ].normal[ 3 ]/255.0f; - } - - if( pVerts2 ) { - norm.x = (float) 2*pVerts2[ i ].normal[ 0 ]/255.0f - 1; - norm.y = (float) 2*pVerts2[ i ].normal[ 1 ]/255.0f - 1; - norm.z = (float) 2*pVerts2[ i ].normal[ 2 ]/255.0f - 1; - w = (float) pVerts2[ i ].normal[ 3 ] / 255.0f; - } - - if ( w ) { - const float invW = 1.0f / w; - norm.x = norm.x * invW; - norm.y = norm.y * invW; - norm.z = norm.z * invW; - normals[ offset ].Set( norm.x, norm.y, norm.z ); - ++offset; - } - } - - // Convert the data into the assimp specific data structures - convertToAssimp( pFile, pScene, pViews, regions, faces, vertices, uvCoords, normals ); -} - -// ------------------------------------------------------------------------------------------------ -// -void M3Importer::convertToAssimp( const std::string& pFile, aiScene* pScene, DIV *pViews, - Region *pRegions, uint16 *pFaces, - const std::vector<aiVector3D> &vertices, - const std::vector<aiVector3D> &uvCoords, - const std::vector<aiVector3D> &normals ) -{ - std::vector<aiMesh*> MeshArray; - - // Create the root node - pScene->mRootNode = createNode( NULL ); - - // Set the name of the scene - pScene->mRootNode->mName.Set( pFile ); - - aiNode *pRootNode = pScene->mRootNode; - aiNode *pCurrentNode = NULL; - - // Lets create the nodes - pRootNode->mNumChildren = pViews->regions.nEntries; - if ( pRootNode->mNumChildren > 0 ) { - pRootNode->mChildren = new aiNode*[ pRootNode->mNumChildren ]; - } - - for ( unsigned int i=0; i<pRootNode->mNumChildren; ++i ) { - //pRegions[ i ]. - // Create a new node - pCurrentNode = createNode( pRootNode ); - std::stringstream stream; - stream << "Node_" << i; - pCurrentNode->mName.Set( stream.str().c_str() ); - pRootNode->mChildren[ i ] = pCurrentNode; - - // Loop over the faces of the nodes - unsigned int numFaces = ( ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ) - pRegions[ i ].ofsIndices ) / 3; - aiMesh *pMesh = new aiMesh; - MeshArray.push_back( pMesh ); - pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - pMesh->mNumFaces = numFaces; - pMesh->mFaces = new aiFace[ pMesh->mNumFaces ]; - aiFace *pCurrentFace = NULL; - unsigned int faceIdx = 0; - for ( unsigned int j = pRegions[ i ].ofsIndices; j < ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ); j += 3 ) { - pCurrentFace = &( pMesh->mFaces[ faceIdx ] ); - faceIdx++; - pCurrentFace->mNumIndices = 3; - pCurrentFace->mIndices = new unsigned int[ 3 ]; - pCurrentFace->mIndices[ 0 ] = pFaces[ j ]; - pCurrentFace->mIndices[ 1 ] = pFaces[ j+1 ]; - pCurrentFace->mIndices[ 2 ] = pFaces[ j+2 ]; - } - // Now we can create the vertex data itself - pCurrentNode->mNumMeshes = 1; - pCurrentNode->mMeshes = new unsigned int[ 1 ]; - const unsigned int meshIdx = MeshArray.size() - 1; - pCurrentNode->mMeshes[ 0 ] = meshIdx; - createVertexData( pMesh, vertices, uvCoords, normals ); - } - - // Copy the meshes into the scene - pScene->mNumMeshes = MeshArray.size(); - pScene->mMeshes = new aiMesh*[ MeshArray.size() ]; - unsigned int pos = 0; - for ( std::vector<aiMesh*>::iterator it = MeshArray.begin(); it != MeshArray.end(); ++it ) { - pScene->mMeshes[ pos ] = *it; - ++pos; - } -} - -// ------------------------------------------------------------------------------------------------ -// -void M3Importer::createVertexData( aiMesh *pMesh, const std::vector<aiVector3D> &vertices, - const std::vector<aiVector3D> &uvCoords, - const std::vector<aiVector3D> &normals ) -{ - pMesh->mNumVertices = pMesh->mNumFaces * 3; - pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ]; - pMesh->mNumUVComponents[ 0 ] = 2; - pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ]; - pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ]; - unsigned int pos = 0; - for ( unsigned int currentFace = 0; currentFace < pMesh->mNumFaces; currentFace++ ) { - aiFace *pFace = &( pMesh->mFaces[ currentFace ] ); - for ( unsigned int currentIdx=0; currentIdx<pFace->mNumIndices; currentIdx++ ) { - const unsigned int idx = pFace->mIndices[ currentIdx ]; - if ( vertices.size() > idx ) { - pMesh->mVertices[ pos ] = vertices[ idx ]; - pMesh->mNormals[ pos ] = normals[ idx ]; - pMesh->mTextureCoords[ 0 ]->x = uvCoords[ idx ].x; - pMesh->mTextureCoords[ 0 ]->y = uvCoords[ idx ].y; - pFace->mIndices[ currentIdx ] = pos; - pos++; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// -aiNode *M3Importer::createNode( aiNode *pParent ) -{ - aiNode *pNode = new aiNode; - if ( pParent ) - pNode->mParent = pParent; - else - pNode->mParent = NULL; - - return pNode; -} - -// ------------------------------------------------------------------------------------------------ - -} // Namespace M3 -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_M3_IMPORTER diff --git a/src/3rdparty/assimp/code/M3Importer.h b/src/3rdparty/assimp/code/M3Importer.h deleted file mode 100644 index 8e079c9ca..000000000 --- a/src/3rdparty/assimp/code/M3Importer.h +++ /dev/null @@ -1,726 +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. - ----------------------------------------------------------------------- -*/ -#ifndef AI_M3LOADER_H_INCLUDED -#define AI_M3LOADER_H_INCLUDED - -#include <vector> - -namespace Assimp { - -namespace M3 { - -// ------------------------------------------------------------------------------------------------ -// The following data definitions are from http://code.google.com/p/libm3/, many thanks for that -// help. -// ------------------------------------------------------------------------------------------------ -typedef unsigned char uint8; -typedef char int8; -typedef unsigned short uint16; -typedef short int16; -typedef unsigned int uint32; -typedef int int32; - -class Vec3D -{ -public: - float x,y,z; - - Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {} - - Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {} - - void reset() - { - x = y = z = 0.0f; - } - - Vec3D& operator= (const Vec3D &v) - { - x = v.x; - y = v.y; - z = v.z; - return *this; - } - - Vec3D operator+ (const Vec3D &v) const - { - Vec3D r(x+v.x,y+v.y,z+v.z); - return r; - } - - Vec3D operator- (const Vec3D &v) const - { - Vec3D r(x-v.x,y-v.y,z-v.z); - return r; - } - - float operator* (const Vec3D &v) const - { - return x*v.x + y*v.y + z*v.z; - } - - Vec3D operator* (float d) const - { - Vec3D r(x*d,y*d,z*d); - return r; - } - - Vec3D operator/ (float d) const - { - Vec3D r(x/d,y/d,z/d); - return r; - } - - friend Vec3D operator* (float d, const Vec3D& v) - { - return v * d; - } - - // Cross Product - Vec3D operator% (const Vec3D &v) const - { - Vec3D r(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); - return r; - } - - Vec3D& operator+= (const Vec3D &v) - { - x += v.x; - y += v.y; - z += v.z; - return *this; - } - - Vec3D& operator-= (const Vec3D &v) - { - x -= v.x; - y -= v.y; - z -= v.z; - return *this; - } - - Vec3D& operator*= (float d) - { - x *= d; - y *= d; - z *= d; - return *this; - } - - float lengthSquared() const - { - return x*x+y*y+z*z; - } - - float length() const - { - return sqrtf(x*x+y*y+z*z); - } - - Vec3D& normalize() - { - this->operator*= (1.0f/length()); - return *this; - } - - Vec3D operator~ () const - { - Vec3D r(*this); - r.normalize(); - return r; - } - - operator float*() - { - return (float*)this; - } -}; - - -class Vec2D -{ -public: - float x,y; - - Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {} - - Vec2D(const Vec2D& v) : x(v.x), y(v.y) {} - - Vec2D& operator= (const Vec2D &v) - { - x = v.x; - y = v.y; - return *this; - } - - Vec2D operator+ (const Vec2D &v) const - { - Vec2D r(x+v.x,y+v.y); - return r; - } - - Vec2D operator- (const Vec2D &v) const - { - Vec2D r(x-v.x,y-v.y); - return r; - } - - float operator* (const Vec2D &v) const - { - return x*v.x + y*v.y; - } - - Vec2D operator* (float d) const - { - Vec2D r(x*d,y*d); - return r; - } - - friend Vec2D operator* (float d, const Vec2D& v) - { - return v * d; - } - - Vec2D& operator+= (const Vec2D &v) - { - x += v.x; - y += v.y; - return *this; - } - - Vec2D& operator-= (const Vec2D &v) - { - x -= v.x; - y -= v.y; - return *this; - } - - Vec2D& operator*= (float d) - { - x *= d; - y *= d; - return *this; - } - - float lengthSquared() const - { - return x*x+y*y; - } - - float length() const - { - return sqrtf(x*x+y*y); - } - - Vec2D& normalize() - { - this->operator*= (1.0f/length()); - return *this; - } - - Vec2D operator~ () const - { - Vec2D r(*this); - r.normalize(); - return r; - } - - operator float*() - { - return (float*)this; - } -}; - -inline -void rotate(float x0, float y0, float *x, float *y, float angle) -{ - float xa = *x - x0, ya = *y - y0; - *x = xa*cosf(angle) - ya*sinf(angle) + x0; - *y = xa*sinf(angle) + ya*cosf(angle) + y0; -} - -struct Reference -{ - uint32 nEntries; // Code 0x00 - uint32 ref; // Code 0x04 -}; - -struct ReferenceEntry -{ - char id[ 4 ]; // Code 0x00 - uint32 offset; // Code 0x04 - uint32 nEntries; // Code 0x08 - uint32 type; // Code 0x0C -}; - -struct MD33 -{ - char id[4]; // Code 0x00 - uint32 ofsRefs; // Code 0x04 - uint32 nRefs; // Code 0x08 - Reference MODL; // Code 0x0C -}; - -enum ModelType -{ - Type1 = 20, - Type2 = 23 -}; - -enum VertexFormat -{ - Vertex_Standard, - Vertex_Extended -}; - -struct MODL23 -{ - Reference name; // Code 0x00 - uint32 version; // Code 0x08 - Reference sequenceHeader; // Code 0x0C - Reference sequenceData; // Code 0x14 - Reference sequenceLookup; // Code 0x1C - uint32 d2; // Code 0x24 - uint32 d3; // Code 0x28 - uint32 d4; // Code 0x2C - Reference STS; // Code 0x30 - Reference bones; // Code 0x38 - uint32 d5; // Code 0x40 - uint32 flags; // Code 0x44 - Reference vertexData; // Code 0x48 - Reference views; // Code 0x50 - Reference B; // Code 0x58 - - Vec3D extents[2]; // Code 0x60 - float radius; // Code 0x78 - - uint32 d7; // Code 0x7C - uint32 d8; // Code 0x80 - uint32 d9; // Code 0x84 - uint32 d10; // Code 0x88 - uint32 d11; // Code 0x8C - uint32 d12; // Code 0x90 - uint32 d13; // Code 0x94 - uint32 d14; // Code 0x98 - uint32 d15; // Code 0x9C - uint32 d16; // Code 0xA0 - uint32 d17; // Code 0xA4 - uint32 d18; // Code 0xA8 - uint32 d19; // Code 0xAC - - Reference attachments; // Code 0xB0 - Reference attachmentLookup; // Code 0xB8 - Reference lights; // Code 0xC0 - Reference SHBX; // Code 0xC8 - Reference cameras; // Code 0xD0 - Reference D; // Code 0xD8 - Reference materialLookup; // Code 0xE0 - Reference materials; // Code 0xE8 - Reference DIS; // Code 0xF0 - Reference CMP; // Code 0xF8 - - Reference TER; // Code 0x10 - Reference VOL; // Code 0x10 - uint32 d21; // Code 0x11 - uint32 d22; // Code 0x11 - Reference CREP; // Code 0x11 - Reference PAR; // Code 0x12 - Reference PARC; // Code 0x12 - Reference RIB; // Code 0x13 - Reference PROJ; // Code 0x13 - Reference FOR; // Code 0x14 - Reference WRP; // Code 0x14 - uint32 d24; // Code 0x15 - uint32 d25; // Code 0x15 - Reference PHRB; // Code 0x15 - uint32 d27; // Code 0x16 - uint32 d28; // Code 0x16 - uint32 d29; // Code 0x16 - uint32 d30; // Code 0x16 - uint32 d32; // Code 0x17 - uint32 d33; // Code 0x17 - Reference IKJT; // Code 0x17 - uint32 d35; // Code 0x18 - uint32 d36; // Code 0x18 - Reference PATU; // Code 0x18 - Reference TRGD; // Code 0x19 - Reference IREF; // Code 0x19 - Reference E; // Code 0x1A - float matrix[4][4]; // Code 0x1A - Vec3D extent[2]; // Code 0x1E - float rad; // Code 0x20 - Reference SSGS; // Code 0x20 - Reference ATVL; // Code 0x20 - uint32 d61; // Code 0x21 - Reference F; // uint16, Code6 0x21 - Reference G; // uint16, Code 0x21 - Reference BBSC; // Code 0x22 - Reference TMD; // Code 0x22 - uint32 d62; // Code 0x23 - uint32 d63; // Code 0x23 - uint32 d64; // Code 0x23 -}; - -struct MODL20 -{ - Reference name; // Code 0x00 - uint32 version; // Code 0x08 - Reference sequenceHeader; // Code 0x0C - Reference sequenceData; // Code 0x14 - Reference sequenceLookup; // Code 0x1C - uint32 d2; // Code 0x24 - uint32 d3; // Code 0x28 - uint32 d4; // Code 0x2C - Reference STS; // Code 0x30 - Reference bones; // Code 0x38 - uint32 d5; // Code 0x44 - uint32 flags; // Code 0x44 - Reference vertexData; // uint8, Code 0x48 - Reference views; // Code 0x50 - Reference B; // uint16, Code 0x58 - - Vec3D extents[2]; // Code 0x60 - float radius; // Code 0x78 - - uint32 d7; // Code 0x7C - uint32 d8; // Code 0x80 - uint32 d9; // Code 0x84 - uint32 d10; // Code 0x88 - uint32 d11; // Code 0x8C - uint32 d12; // Code 0x90 - uint32 d13; // Code 0x94 - uint32 d14; // Code 0x98 - uint32 d15; // Code 0x9C - uint32 d16; // Code 0xA0 - uint32 d17; // Code 0xA4 - uint32 d18; // Code 0xA8 - uint32 d19; // Code 0xAC - - Reference attachments; // Code 0xB0 - Reference attachmentLookup; // uint16, Code 0xB8 - Reference lights; // Code 0xC0 - Reference cameras; // Code 0xC8 - Reference D; // uint16, Code 0xD0 - Reference materialLookup; // Code 0xD8 - Reference materials; // Code 0xE0 - Reference DIS; // Code 0xE8 - Reference CMP; // Code 0xF0 - Reference TER; // Code 0xF8 - - uint32 d20; // Code 0x10 - uint32 d21; // Code 0x10 - uint32 d22; // Code 0x10 - uint32 d23; // Code 0x10 - Reference CREP; // Code 0x11 - Reference PAR; // Code 0x11 - Reference PARC; // Code 0x12 - Reference RIB; // Code 0x12 - Reference PROJ; // Code 0x13 - Reference FOR; // Code 0x13 - uint32 d25; // Code 0x14 - uint32 d26; // Code 0x14 - uint32 d27; // Code 0x14 - uint32 d28; // Code 0x14 - Reference PHRB; // Code 0x15 - uint32 d30; // Code 0x15 - uint32 d31; // Code 0x15 - uint32 d32; // Code 0x16 - uint32 d33; // Code 0x16 - uint32 d34; // Code 0x16 - uint32 d35; // Code 0x16 - Reference IKJT; // Code 0x17 - uint32 d36; // Code 0x17 - uint32 d37; // Code 0x17 - Reference PATU; // Code 0x18 - Reference TRGD; // Code 0x18 - Reference IREF; // Code 0x19 - Reference E; // int32, Code 0x19 - - float matrix[4][4]; // Code 0x1A - Vec3D extent[2]; // Code 0x1E - float rad; // Code 0x1F - - Reference SSGS; // Code 0x1F - uint32 d38; // Code 0x20 - uint32 d39; // Code 0x20 - Reference BBSC; // Code 0x20 - - uint32 d40; // Code 0x21 - uint32 d41; // Code 0x21 - uint32 d42; // Code 0x21 - uint32 d43; // Code 0x22 - uint32 d44; // Code 0x22 -}; - -struct BONE -{ - int32 d1; // Keybone? - Reference name; - uint32 flags; - int16 parent; - int16 s1; - - float floats[ 34 ]; -}; - -struct VertexExt // 36 byte -{ - Vec3D pos; - uint8 boneWeight[ 4 ]; - uint8 boneIndex[ 4 ]; - uint8 normal[ 4 ]; //normal_x = (float)normal[0]/255.0f... - int16 uv[ 2 ]; - uint32 d1; - uint8 tangent[ 4 ]; -}; - -struct Vertex // 32 byte -{ - Vec3D pos; - uint8 boneWeight[4]; - uint8 boneIndex[4]; - uint8 normal[4]; //normal_x = (float)normal[0]/255.0f... - int16 uv[2]; - uint8 tangent[4]; -}; - -struct MATM -{ - uint32 d1; - uint32 d2; // Index into MAT-table? -}; - -struct MAT -{ - Reference name; - int ukn1[ 8 ]; - float x, y; //always 1.0f - Reference layers[13]; - int ukn2[15]; -}; - -struct LAYR -{ - int unk; - Reference name; - float unk2[85]; -}; - -struct DIV -{ - Reference faces; // Code 0x00 - Reference regions; // Code 0x08 - Reference BAT; // Code 0x10 - Reference MSEC; // Code 0x18 -}; - -struct Region -{ - uint32 unk; - uint16 ofsVertices; - uint16 nVertices; - uint32 ofsIndices; - uint32 nIndices; // reference into DIV.faces - uint8 unknown[12]; -}; - -struct CAM -{ - int32 d1; // Code 0x00 - Reference name; // Code 0x04 - uint16 flags1; // Code 0x0C - uint16 flags2; // Code 0x0E -}; - -struct EVNT -{ - Reference name; // Code 0x00 - int16 unk1[4]; // Code 0x08 - float matrix[4][4]; // Code 0x10 - int32 unk2[4]; // Code 0x50 -}; - -struct ATT -{ - int32 unk; // Code 0x00 - Reference name; // Code 0x04 - int32 bone; // Code 0x0C -}; - -struct PHSH -{ - float m[ 4 ][ 4 ]; - float f1; - float f2; - Reference refs[ 5 ]; - float f3; -}; - -struct SEQS -{ - int32 d1; // Code 0x00 - int32 d2; // Code 0x04 - Reference name; // Code 0x08 - int32 d3; // Code 0x10 - uint32 length; // Code 0x14 - int32 d4; // Code 0x18 - uint32 flags; // Code 0x1C - int32 unk[5]; // Code 0x20 - Vec3D extents[2]; // Code 0x34 - float radius; // Code 0x4C - int32 d5; // Code 0x50 - int32 d6; // Code 0x54 -}; - -struct STC -{ - Reference name; // Code 0x00 - uint16 s1; // Code 0x08 - uint16 s2; // Code 0x0A - uint16 s3; // Code 0x0C - uint16 s4; // Code 0x0E - Reference unk2; // uint32 // Code 0x12 - Reference unk3; // uint32 // Code 0x1A - uint32 d3; // Code 0x22 - Reference evt; // Code 0x24 - Reference unk4[11]; // Seems to be transformation data // Code 0x2C - Reference bnds; // Code 0x84 -}; - -struct STS -{ - Reference unk1; // uint32 // Code 0x00 - int32 unk[3]; // Code 0x08 - int16 s1; // Code 0x14 - int16 s2; // Code 0x16 -}; - -struct STG -{ - Reference name; // Code 0x00 - Reference stcID; // Code 0x08 -}; - -struct SD -{ - Reference timeline; // Code 0x00 - uint32 flags; // Code 0x08 - uint32 length; // Code 0x0C - Reference data; // Code 0x10 -}; - -struct BNDS -{ - Vec3D extents1[2]; // Code 0x00 - float radius1; // Code 0x18 - Vec3D extents2[2]; // Code 0x1C - float radius2; // Code 0x34 -}; - -struct VEC2 -{ - float x, y; -}; - -struct VEC3 -{ - float x, y, z; -}; - -struct VEC4 -{ - float x, y, z, w; -}; - -struct QUAT -{ - float x, y, z, w; -}; - -// ------------------------------------------------------------------------------------------------ -/** Loader to import M3-models. - */ -// ------------------------------------------------------------------------------------------------ -class M3Importer : public BaseImporter -{ - friend class Importer; - -public: - /// @brief The default constructor. - M3Importer(); - - /// @brief The destructor. - ~M3Importer(); - - /// @brief Returns whether the class can handle the format of the given file. - /// @remark See BaseImporter::CanRead() for details. - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const; - -private: - const aiImporterDesc* GetInfo () const; - void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ); - void convertToAssimp( const std::string& pFile, aiScene* pScene, DIV *pViews, Region *pRegions, uint16 *pFaces, - const std::vector<aiVector3D> &vertices, const std::vector<aiVector3D> &uvCoords, const std::vector<aiVector3D> &normals ); - void createVertexData( aiMesh *pMesh, const std::vector<aiVector3D> &vertices, const std::vector<aiVector3D> &uvCoords, - const std::vector<aiVector3D> &normals ); - aiNode *createNode( aiNode *pParent ); - template<typename T> - T* GetEntries( Reference ref ); - -private: - MD33 *m_pHead; - ReferenceEntry *m_pRefs; - std::vector<unsigned char> m_Buffer; -}; - -// ------------------------------------------------------------------------------------------------ -template<typename T> -inline -T* M3Importer::GetEntries( Reference ref ) -{ - return (T*) ( &m_Buffer[ 0 ] + m_pRefs[ ref.ref ].offset ); -} - -// ------------------------------------------------------------------------------------------------ - -} // Namespace M3 -} // Namespace Assimp - -#endif // AI_M3LOADER_H_INCLUDED diff --git a/src/3rdparty/assimp/code/ObjFileImporter.cpp b/src/3rdparty/assimp/code/ObjFileImporter.cpp index 97781aff4..af0038a31 100644 --- a/src/3rdparty/assimp/code/ObjFileImporter.cpp +++ b/src/3rdparty/assimp/code/ObjFileImporter.cpp @@ -139,7 +139,23 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, { strModelName = pFile; } - + + // process all '\' + std::vector<char> ::iterator iter = m_Buffer.begin(); + while (iter != m_Buffer.end()) + { + if (*iter == '\\') + { + // remove '\' + iter = m_Buffer.erase(iter); + // remove next character + while (*iter == '\r' || *iter == '\n') + iter = m_Buffer.erase(iter); + } + else + ++iter; + } + // parse the file into a temporary representation ObjFileParser parser(m_Buffer, strModelName, pIOHandler); diff --git a/src/3rdparty/assimp/code/OgreBinarySerializer.cpp b/src/3rdparty/assimp/code/OgreBinarySerializer.cpp new file mode 100644 index 000000000..6674f4cee --- /dev/null +++ b/src/3rdparty/assimp/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<bool>() +{ + return (m_reader->GetU1() > 0); +} + +template<> +inline char OgreBinarySerializer::Read<char>() +{ + return static_cast<char>(m_reader->GetU1()); +} + +template<> +inline uint8_t OgreBinarySerializer::Read<uint8_t>() +{ + return m_reader->GetU1(); +} + +template<> +inline uint16_t OgreBinarySerializer::Read<uint16_t>() +{ + return m_reader->GetU2(); +} + +template<> +inline uint32_t OgreBinarySerializer::Read<uint32_t>() +{ + return m_reader->GetU4(); +} + +template<> +inline float OgreBinarySerializer::Read<float>() +{ + return m_reader->GetF4(); +} + +void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes) +{ + ReadBytes(static_cast<void*>(dest), numBytes); +} + +void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes) +{ + ReadBytes(static_cast<void*>(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<char>(); + if (c == '\n') + break; + str += c; + } + return str; +} + +uint16_t OgreBinarySerializer::ReadHeader(bool readLen) +{ + uint16_t id = Read<uint16_t>(); + if (readLen) + m_currentLen = Read<uint32_t>(); + +#if (OGRE_BINARY_SERIALIZER_DEBUG == 1) + if (id != HEADER_CHUNK_ID) + { + DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh + ? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(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<bool>(); + + 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<uint16_t>(); + bool manual = Read<bool>(); + + /// @note Main mesh is considered as LOD 0, start from index 1. + for (size_t i=1; i<numLods; ++i) + { + uint16_t id = ReadHeader(); + if (id != M_MESH_LOD_USAGE) { + throw DeadlyImportError("M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level"); + } + + m_reader->IncPtr(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<silen; ++si) + { + id = ReadHeader(); + if (id != M_MESH_LOD_GENERATED) { + throw DeadlyImportError("Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED"); + } + + uint32_t indexCount = Read<uint32_t>(); + bool is32bit = Read<bool>(); + + 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<uint32_t>(); + ba.boneIndex = Read<uint16_t>(); + ba.weight = Read<float>(); + + dest->boneAssignments.push_back(ba); +} + +void OgreBinarySerializer::ReadSubMesh(Mesh *mesh) +{ + uint16_t id = 0; + + SubMesh *submesh = new SubMesh(); + submesh->materialRef = ReadLine(); + submesh->usesSharedVertexData = Read<bool>(); + + submesh->indexData->count = Read<uint32_t>(); + submesh->indexData->faceCount = static_cast<uint32_t>(submesh->indexData->count / 3); + submesh->indexData->is32bit = Read<bool>(); + + 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<uint32_t> 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<uint32_t>::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<SubMesh::OperationType>(Read<uint16_t>()); +} + +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<uint16_t>(); + 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<uint32_t>(); + + 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<uint16_t>(); + element.type = static_cast<VertexElement::Type>(Read<uint16_t>()); + element.semantic = static_cast<VertexElement::Semantic>(Read<uint16_t>()); + element.offset = Read<uint16_t>(); + element.index = Read<uint16_t>(); + + 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>(); + uint16_t vertexSize = Read<uint16_t>(); + + 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<bool>(); + + if (!manual) + { + m_reader->IncPtr(sizeof(uint8_t)); + uint32_t numTriangles = Read<uint32_t>(); + uint32_t numEdgeGroups = Read<uint32_t>(); + + size_t skipBytes = (sizeof(uint32_t) * 8 + sizeof(float) * 4) * numTriangles; + m_reader->IncPtr(skipBytes); + + for (size_t i=0; i<numEdgeGroups; ++i) + { + uint16_t id = ReadHeader(); + if (id != M_EDGE_GROUP) + throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD"); + + m_reader->IncPtr(sizeof(uint32_t) * 3); + uint32_t numEdges = Read<uint32_t>(); + for (size_t j=0; j<numEdges; ++j) + { + m_reader->IncPtr(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<uint16_t>(); + pose->hasNormals = Read<bool>(); + + 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<uint32_t>(); + 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<float>(); + + 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<float>(); + + // Advance to first track + id = ReadHeader(); + } + + while (!AtEnd() && id == M_ANIMATION_TRACK) + { + VertexAnimationTrack track; + track.type = static_cast<VertexAnimationTrack::Type>(Read<uint16_t>()); + track.target = Read<uint16_t>(); + + 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<float>(); + bool hasNormals = Read<bool>(); + + 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<float>(); + + if (!AtEnd()) + { + id = ReadHeader(); + while (!AtEnd() && id == M_ANIMATION_POSE_REF) + { + PoseRef pr; + pr.index = Read<uint16_t>(); + pr.influence = Read<float>(); + 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<Skeleton::BlendMode>(Read<uint16_t>()); + break; + } + case SKELETON_BONE: + { + if (firstBone) + { + DefaultLogger::get()->debug(" - Bones"); + firstBone = false; + } + + ReadBone(skeleton); + break; + } + case SKELETON_BONE_PARENT: + { + ReadBoneParent(skeleton); + break; + } + case SKELETON_ANIMATION: + { + if (firstAnim) + { + DefaultLogger::get()->debug(" - Animations"); + firstAnim = false; + } + + ReadSkeletonAnimation(skeleton); + break; + } + case SKELETON_ANIMATION_LINK: + { + ReadSkeletonAnimationLink(skeleton); + break; + } + } + } + + // Calculate bone matrices for root bones. Recursively calculates their children. + for (size_t i=0, len=skeleton->bones.size(); i<len; ++i) + { + Bone *bone = skeleton->bones[i]; + if (!bone->IsParented()) + bone->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +void OgreBinarySerializer::ReadBone(Skeleton *skeleton) +{ + Bone *bone = new Bone(); + bone->name = ReadLine(); + bone->id = Read<uint16_t>(); + + // Pos and rot + ReadVector(bone->position); + ReadQuaternion(bone->rotation); + + // Scale (optional) + if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE) + ReadVector(bone->scale); + + // Bone indexes need to start from 0 and be contiguous + if (bone->id != skeleton->bones.size()) { + throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id); + } + + DefaultLogger::get()->debug(Formatter::format() << " " << bone->id << " " << bone->name); + + skeleton->bones.push_back(bone); +} + +void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton) +{ + uint16_t childId = Read<uint16_t>(); + uint16_t parentId = Read<uint16_t>(); + + Bone *child = skeleton->BoneById(childId); + Bone *parent = skeleton->BoneById(parentId); + + if (child && parent) + parent->AddChild(child); + else + throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId); +} + +void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) +{ + Animation *anim = new Animation(skeleton); + anim->name = ReadLine(); + anim->length = Read<float>(); + + if (!AtEnd()) + { + uint16_t id = ReadHeader(); + if (id == SKELETON_ANIMATION_BASEINFO) + { + anim->baseName = ReadLine(); + anim->baseTime = Read<float>(); + + // Advance to first track + id = ReadHeader(); + } + + while (!AtEnd() && id == SKELETON_ANIMATION_TRACK) + { + ReadSkeletonAnimationTrack(skeleton, anim); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + } + + skeleton->animations.push_back(anim); + + DefaultLogger::get()->debug(Formatter::format() << " " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)"); +} + +void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest) +{ + uint16_t boneId = Read<uint16_t>(); + Bone *bone = dest->parentSkeleton->BoneById(boneId); + if (!bone) { + throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton"); + } + + VertexAnimationTrack track; + track.type = VertexAnimationTrack::VAT_TRANSFORM; + track.boneName = bone->name; + + uint16_t id = ReadHeader(); + while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME) + { + ReadSkeletonAnimationKeyFrame(&track); + + if (!AtEnd()) + id = ReadHeader(); + } + if (!AtEnd()) + RollbackHeader(); + + dest->tracks.push_back(track); +} + +void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest) +{ + TransformKeyFrame keyframe; + keyframe.timePos = Read<float>(); + + // Rot and pos + ReadQuaternion(keyframe.rotation); + ReadVector(keyframe.position); + + // Scale (optional) + if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE) + ReadVector(keyframe.scale); + + dest->transformKeyFrames.push_back(keyframe); +} + +void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton *skeleton) +{ + // Skip bounds, not compatible with Assimp. + ReadLine(); // skeleton name + SkipBytes(sizeof(float) * 3); // scale +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/src/3rdparty/assimp/code/OgreBinarySerializer.h b/src/3rdparty/assimp/code/OgreBinarySerializer.h new file mode 100644 index 000000000..69db4b722 --- /dev/null +++ b/src/3rdparty/assimp/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<MemoryStreamReader> MemoryStreamReaderPtr; + +class OgreBinarySerializer +{ +public: + /// Imports mesh and returns the result. + /** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ + static Mesh *ImportMesh(MemoryStreamReader *reader); + + /// Imports skeleton to @c mesh into Mesh::skeleton. + /** If mesh does not have a skeleton reference or the skeleton file + cannot be found it is not a fatal DeadlyImportError. + @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<typename T> + inline T Read(); + + void ReadBytes(char *dest, size_t numBytes); + void ReadBytes(uint8_t *dest, size_t numBytes); + void ReadBytes(void *dest, size_t numBytes); + uint8_t *ReadBytes(size_t numBytes); + + void ReadVector(aiVector3D &vec); + void ReadQuaternion(aiQuaternion &quat); + + std::string ReadString(size_t len); + std::string ReadLine(); + + void SkipBytes(size_t numBytes); + + uint32_t m_currentLen; + MemoryStreamReader *m_reader; + + AssetMode assetMode; +}; + +enum MeshChunkId +{ + M_HEADER = 0x1000, + // char* version : Version number check + M_MESH = 0x3000, + // bool skeletallyAnimated // important flag which affects h/w buffer policies + // Optional M_GEOMETRY chunk + M_SUBMESH = 0x4000, + // char* materialName + // bool useSharedVertices + // unsigned int indexCount + // bool indexes32Bit + // unsigned int* faceVertexIndices (indexCount) + // OR + // unsigned short* faceVertexIndices (indexCount) + // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false) + M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing + // unsigned short operationType + M_SUBMESH_BONE_ASSIGNMENT = 0x4100, + // Optional bone weights (repeating section) + // 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/src/3rdparty/assimp/code/OgreImporter.cpp b/src/3rdparty/assimp/code/OgreImporter.cpp index 94c7701ba..1760fceea 100644 --- a/src/3rdparty/assimp/code/OgreImporter.cpp +++ b/src/3rdparty/assimp/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 <vector> -#include <sstream> +#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[] = { "<mesh>" }; - return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + if (EndsWith(pFile, ".mesh.xml", false)) + { + const char* tokens[] = { "<mesh>" }; + 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<IOStream> 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<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(file.get())); - boost::scoped_ptr<XmlReader> 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 <mesh> 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)) - { - DefaultLogger::get()->debug("Reading shared geometry"); - unsigned int NumVertices = GetAttribute<unsigned int>(reader.get(), "vertexcount"); - - 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 <submeshes> node inside root <mesh> node"); - } - - vector<boost::shared_ptr<SubMesh> > subMeshes; - vector<aiMaterial*> materials; - - NextNode(reader.get()); - while(CurrentNodeNameEquals(reader.get(), nnSubMesh)) + // Binary .mesh import + if (EndsWith(pFile, ".mesh", false)) { - SubMesh* submesh = new SubMesh(); - ReadSubMesh(subMeshes.size(), *submesh, reader.get()); + /// @note MemoryStreamReader takes ownership of f. + MemoryStreamReader reader(f); - // 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(); + // Import mesh + boost::scoped_ptr<Mesh> mesh(OgreBinarySerializer::ImportMesh(&reader)); - subMeshes.push_back(boost::shared_ptr<SubMesh>(submesh)); + // Import skeleton + OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh.get()); - /** @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); - } + // Import mesh referenced materials + ReadMaterials(pFile, pIOHandler, pScene, mesh.get()); - if (subMeshes.empty()) { - throw DeadlyImportError("Could not find <submeshes> node inside root <mesh> 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<Bone> Bones; - vector<Animation> Animations; - - if (CurrentNodeNameEquals(reader.get(), nnSkeletonLink)) - { - string skeletonFile = GetAttribute<string>(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()); + // 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<IOStream> scopedFile(f); + boost::scoped_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get())); + boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get())); - // Now there might be <boneassignments> for the shared geometry - if (CurrentNodeNameEquals(reader.get(), "boneassignments")) { - ReadBoneWeights(m_SharedGeometry, reader.get()); - } + // Import mesh + boost::scoped_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(reader.get())); + + // Import skeleton + OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get()); - // -------------------- Process Results -------------------- - BOOST_FOREACH(boost::shared_ptr<SubMesh> submesh, subMeshes) - { - ProcessSubMesh(*submesh.get(), m_SharedGeometry); - } - - // -------------------- Apply to aiScene -------------------- + // Import mesh referenced materials + ReadMaterials(pFile, pIOHandler, pScene, mesh.get()); - // Materials - pScene->mMaterials = new aiMaterial*[materials.size()]; - pScene->mNumMaterials = materials.size(); - - for(size_t i=0, len=materials.size(); i<len; ++i) { - pScene->mMaterials[i] = materials[i]; + // Convert to Assimp + mesh->ConvertToAssimpScene(pScene); } - - // Meshes - pScene->mMeshes = new aiMesh*[subMeshes.size()]; - pScene->mNumMeshes = subMeshes.size(); - - for(size_t i=0, len=subMeshes.size(); i<len; ++i) - { - boost::shared_ptr<SubMesh> 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(); i<len; ++i) { - pScene->mRootNode->mMeshes[i] = static_cast<unsigned int>(i); - } - - // Skeleton and animations - CreateAssimpSkeleton(pScene, Bones, Animations); } } // Ogre diff --git a/src/3rdparty/assimp/code/OgreImporter.h b/src/3rdparty/assimp/code/OgreImporter.h index f43398751..2d9cf971e 100644 --- a/src/3rdparty/assimp/code/OgreImporter.h +++ b/src/3rdparty/assimp/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<Face> Faces; - std::vector<aiVector3D> Positions; - std::vector<aiVector3D> Normals; - std::vector<aiVector3D> 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<std::vector<aiVector3D> > Uvs; - - /// A list(inner) of bones for each vertex(outer). - std::vector<std::vector<BoneWeight> > 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<Bone> &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<Bone> &Bones, std::vector<Animation> &Animations) const; - - /// Converts the animations in aiAnimations and puts them into the scene. - void PutAnimationsInScene(aiScene *pScene, const std::vector<Bone> &Bones, const std::vector<Animation> &Animations); - - /// Creates the aiSkeleton in current scene. - void CreateAssimpSkeleton(aiScene *pScene, const std::vector<Bone> &bones, const std::vector<Animation> &animations); - - /// Recursively creates a filled aiNode from a given root bone. - static aiNode* CreateNodeFromBone(int boneId, const std::vector<Bone> &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<aiMaterial*> &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<aiTextureType, unsigned int> 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<int> 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<Bone>. - bool operator<(const Bone &other) const { return (Id < other.Id); } - - /// This operator is needed to find a bone by its name in a vector<Bone> - 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<Bone>& 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<KeyFrame> Keyframes; -}; - -/// Ogre animation -struct Animation -{ - /// Name - std::string Name; - /// Length - float Length; - /// Tracks - std::vector<Track> Tracks; -}; - } // Ogre } // Assimp diff --git a/src/3rdparty/assimp/code/OgreImporter.hpp b/src/3rdparty/assimp/code/OgreImporter.hpp deleted file mode 100644 index a24d1fc3f..000000000 --- a/src/3rdparty/assimp/code/OgreImporter.hpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "BaseImporter.h" - -#include <vector> - -#include "OgreXmlHelper.hpp" -#include "irrXMLWrapper.h" - -/// Ogre Importer TODO -/* - Read Vertex Colors - - Read multiple TexCoords -*/ - - - -namespace Assimp -{ -namespace Ogre -{ - - -//Forward declarations: -struct Face; -struct Weight; -struct Bone; -struct Animation; -struct Track; -struct Keyframe; - -///A submesh from Ogre -struct SubMesh -{ - bool SharedData; - - std::string Name; - std::string MaterialName; - std::vector<Face> FaceList; - - std::vector<aiVector3D> Positions; bool HasPositions; - std::vector<aiVector3D> Normals; bool HasNormals; - std::vector<aiVector3D> Tangents; bool HasTangents; - std::vector<std::vector<aiVector3D> > Uvs;//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< std::vector<Weight> > Weights;//a list(inner) of bones for each vertex(outer) - int MaterialIndex;///< The Index in the Assimp Materialarray from the material witch is attached to this submesh - unsigned int BonesUsed;//the highest index of a bone from a bone weight, this is needed to create the assimp bone structur (converting from Vertex-Bones to Bone-Vertices) - - SubMesh(): SharedData(false), HasPositions(false), HasNormals(false), HasTangents(false), - MaterialIndex(-1), BonesUsed(0) {}//initialize everything -}; - - -///The Main Ogre Importer Class -class OgreImporter : public BaseImporter -{ -public: - virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; - virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); - virtual const aiImporterDesc* GetInfo () const; - virtual void SetupProperties(const Importer* pImp); -private: - - - //-------------------------------- OgreMesh.cpp ------------------------------- - /// Helper Functions to read parts of the XML File - void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value - - /// Reads a single Vertexbuffer and writes its data in the Submesh - static void ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsigned int NumVertices); - - /// Reads bone weights are stores them into the given submesh - static void ReadBoneWeights(SubMesh &theSubMesh, XmlReader *Reader); - - /// After Loading a SubMehs some work needs to be done (make all Vertexes unique, normalize weights) - static void ProcessSubMesh(SubMesh &theSubMesh, SubMesh &theSharedGeometry); - - /// Uses the bone data to convert a SubMesh into a aiMesh which will be created and returned - aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& 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 LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const; - - /// Converts the animations in aiAnimations and puts them into the scene - void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations); - - /// Creates the aiskeleton in current scene - void CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations); - - /// Recursivly creates a filled aiNode from a given root bone - static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode); - - - //-------------------------------- OgreMaterial.cpp ------------------------------- - aiMaterial* LoadMaterial(const std::string MaterialName) const; - void ReadTechnique(std::stringstream &ss, aiMaterial* NewMaterial) const; - - - - - //Now we don't have to give theses parameters to all functions - std::string m_CurrentFilename; - std::string m_MaterialLibFilename; - bool m_TextureTypeFromFilename; - IOSystem* m_CurrentIOHandler; - aiScene *m_CurrentScene; - SubMesh m_SharedGeometry;///< we will just use the vertexbuffers of the submesh -}; - -///For the moment just triangles, no other polygon types! -struct Face -{ - unsigned int VertexIndices[3]; -}; - -struct BoneAssignment -{ - unsigned int BoneId;//this is, what we get from ogre - std::string BoneName;//this is, what we need for assimp -}; - -///for a vertex->bone structur -struct Weight -{ - unsigned int BoneId; - float Value; -}; - - -/// Helper Class to describe an ogre-bone for the skeleton: -/** All Id's are signed ints, because than we have -1 as a simple INVALID_ID Value (we start from 0 so 0 is a valid bone ID!*/ -struct Bone -{ - int Id; - int ParentId; - std::string Name; - aiVector3D Position; - float RotationAngle; - aiVector3D RotationAxis; - std::vector<int> Children; - aiMatrix4x4 BoneToWorldSpace; - - ///ctor - Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {} - ///this operator is needed to sort the bones after Id's - bool operator<(const Bone& rval) const - {return Id<rval.Id; } - ///this operator is needed to find a bone by its name in a vector<Bone> - bool operator==(const std::string& rval) const - {return Name==rval; } - bool operator==(const aiString& rval) const - {return Name==std::string(rval.data); } - - // implemented in OgreSkeleton.cpp - void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones); -}; - - - -///Describes an Ogre Animation -struct Animation -{ - std::string Name; - float Length; - std::vector<Track> Tracks; -}; - -///a track (keyframes for one bone) from an animation -struct Track -{ - std::string BoneName; - std::vector<Keyframe> Keyframes; -}; - -/// keyframe (bone transformation) from a track from a animation -struct Keyframe -{ - float Time; - aiVector3D Position; - aiQuaternion Rotation; - aiVector3D Scaling; -}; - -}//namespace Ogre -}//namespace Assimp diff --git a/src/3rdparty/assimp/code/OgreMaterial.cpp b/src/3rdparty/assimp/code/OgreMaterial.cpp index 157af24aa..a85741f18 100644 --- a/src/3rdparty/assimp/code/OgreMaterial.cpp +++ b/src/3rdparty/assimp/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 <vector> -#include <sstream> - #include "OgreImporter.h" #include "TinyFormatter.h" +#include "fast_atof.h" + +#include <vector> +#include <sstream> + 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<aiMaterial*> materials; + + // Create materials that can be found and parsed via the IOSystem. + for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i) + { + SubMesh *submesh = mesh->GetSubMesh(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<aiMaterial*> materials; + + // Create materials that can be found and parsed via the IOSystem. + for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i) + { + SubMeshXml *submesh = mesh->GetSubMesh(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<aiMaterial*> &materials) +{ + pScene->mNumMaterials = materials.size(); + if (pScene->mNumMaterials > 0) + { + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for(size_t i=0;i<pScene->mNumMaterials; ++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<IOStream> 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/src/3rdparty/assimp/code/OgreMesh.cpp b/src/3rdparty/assimp/code/OgreMesh.cpp deleted file mode 100644 index c25f73b95..000000000 --- a/src/3rdparty/assimp/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<string>(reader, "material"); - } - if (reader->getAttributeValue("use32bitindexes")) { - submesh.Use32bitIndexes = GetAttribute<bool>(reader, "use32bitindexes"); - } - if (reader->getAttributeValue("usesharedvertices")) { - submesh.UseSharedGeometry = GetAttribute<bool>(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<unsigned int>(reader, "count"); - - NextNode(reader); - currentNodeName = reader->getNodeName(); - - while(currentNodeName == nnFace) - { - Face NewFace; - NewFace.VertexIndices[0] = GetAttribute<int>(reader, "v1"); - NewFace.VertexIndices[1] = GetAttribute<int>(reader, "v2"); - NewFace.VertexIndices[2] = GetAttribute<int>(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<int>(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<bool>(reader, "positions")) - { - submesh.HasPositions = true; - submesh.Positions.reserve(numVertices); - DefaultLogger::get()->debug(" - Has positions"); - } - if (reader->getAttributeValue("normals") && GetAttribute<bool>(reader, "normals")) - { - submesh.HasNormals = true; - submesh.Normals.reserve(numVertices); - DefaultLogger::get()->debug(" - Has normals"); - } - if (reader->getAttributeValue("tangents") && GetAttribute<bool>(reader, "tangents")) - { - submesh.HasTangents = true; - submesh.Tangents.reserve(numVertices); - DefaultLogger::get()->debug(" - Has tangents"); - } - if (reader->getAttributeValue("texture_coords")) - { - submesh.Uvs.resize(GetAttribute<unsigned int>(reader, "texture_coords")); - for(size_t i=0, len=submesh.Uvs.size(); i<len; ++i) { - submesh.Uvs[i].reserve(numVertices); - } - DefaultLogger::get()->debug(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<float>(reader, "x"); - NewPos.y = GetAttribute<float>(reader, "y"); - NewPos.z = GetAttribute<float>(reader, "z"); - submesh.Positions.push_back(NewPos); - } - else if (submesh.HasNormals && currentNodeName == nnNormal) - { - aiVector3D NewNormal; - NewNormal.x = GetAttribute<float>(reader, "x"); - NewNormal.y = GetAttribute<float>(reader, "y"); - NewNormal.z = GetAttribute<float>(reader, "z"); - submesh.Normals.push_back(NewNormal); - } - else if (submesh.HasTangents && currentNodeName == nnTangent) - { - aiVector3D NewTangent; - NewTangent.x = GetAttribute<float>(reader, "x"); - NewTangent.y = GetAttribute<float>(reader, "y"); - NewTangent.z = GetAttribute<float>(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<len; ++i) - { - if (currentNodeName != nnTexCoord) { - throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex"); - } - - aiVector3D NewUv; - NewUv.x = GetAttribute<float>(reader, "u"); - NewUv.y = GetAttribute<float>(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<submesh.Uvs.size(); ++i) - { - if (submesh.Uvs[i].size() != numVertices) { - throw DeadlyImportError(Formatter::format() << "Read only " << submesh.Uvs[i].size() - << " uvs for uv index " << i << " when should have read " << numVertices); - } - } -} - -void OgreImporter::ReadBoneWeights(SubMesh &submesh, XmlReader *reader) -{ - submesh.Weights.resize(submesh.Positions.size()); - - unsigned int numRead = 0; - const string nnVertexBoneAssignment = "vertexboneassignment"; - - NextNode(reader); - while(CurrentNodeNameEquals(reader, nnVertexBoneAssignment)) - { - numRead++; - - BoneWeight weight; - weight.Id = GetAttribute<int>(reader, "boneindex"); - weight.Value = GetAttribute<float>(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<int>(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<Face> uniqueFaceList(submesh.Faces.size()); - unsigned int uniqueVertexCount = submesh.Faces.size() * 3; - - vector<aiVector3D> uniquePositions(uniqueVertexCount); - vector<aiVector3D> uniqueNormals(uniqueVertexCount); - vector<aiVector3D> uniqueTangents(uniqueVertexCount); - - vector<vector<BoneWeight> > uniqueWeights(uniqueVertexCount); - vector<vector<aiVector3D> > uniqueUvs(submesh.UseSharedGeometry ? sharedGeometry.Uvs.size() : submesh.Uvs.size()); - - for(size_t uvi=0; uvi<uniqueUvs.size(); ++uvi) { - uniqueUvs[uvi].resize(uniqueVertexCount); - } - - /* Support for shared geometry. - We can use this loop to copy vertex informations from the shared data pool. In order to do so - we just use a reference to a submodel instead of our submodel itself */ - SubMesh &vertexSource = (submesh.UseSharedGeometry ? sharedGeometry : submesh); - if (submesh.UseSharedGeometry) - { - submesh.HasPositions = sharedGeometry.HasPositions; - submesh.HasNormals = sharedGeometry.HasNormals; - submesh.HasTangents = sharedGeometry.HasTangents; - submesh.BonesUsed = sharedGeometry.BonesUsed; - } - - for (size_t i=0, flen=submesh.Faces.size(); i<flen; ++i) - { - const Face &face = submesh.Faces[i]; - - // We pre calculate the index values here, - // because we need them in all vertex attributes. - unsigned int v1 = face.VertexIndices[0]; - unsigned int v2 = face.VertexIndices[1]; - unsigned int v3 = face.VertexIndices[2]; - - size_t pos = i*3; - - uniqueFaceList[i].VertexIndices[0] = pos; - uniqueFaceList[i].VertexIndices[1] = pos + 1; - uniqueFaceList[i].VertexIndices[2] = pos + 2; - - uniquePositions[pos] = vertexSource.Positions[v1]; - uniquePositions[pos+1] = vertexSource.Positions[v2]; - uniquePositions[pos+2] = vertexSource.Positions[v3]; - - if (vertexSource.HasNormals) - { - uniqueNormals[pos ] = vertexSource.Normals[v1]; - uniqueNormals[pos+1] = vertexSource.Normals[v2]; - uniqueNormals[pos+2] = vertexSource.Normals[v3]; - } - - if (vertexSource.HasTangents) - { - uniqueTangents[pos] = vertexSource.Tangents[v1]; - uniqueTangents[pos+1] = vertexSource.Tangents[v2]; - uniqueTangents[pos+2] = vertexSource.Tangents[v3]; - } - - for(size_t uvi=0; uvi<uniqueUvs.size(); ++uvi) - { - const std::vector<aiVector3D> &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<wlen; ++vertexId) - { - std::vector<BoneWeight> &weights = submesh.Weights[vertexId]; - - float sum = 0.0f; - for(size_t boneId=0, blen=weights.size(); boneId<blen; ++boneId) { - sum += weights[boneId].Value; - } - - //check if the sum is too far away from 1 - if ((sum < (1.0f - 0.05f)) || (sum > (1.0f + 0.05f))) - { - for(size_t boneId=0, blen=weights.size(); boneId<blen; ++boneId) { - weights[boneId].Value /= sum; - } - } - } -} - -aiMesh *OgreImporter::CreateAssimpSubMesh(aiScene */*pScene*/, const SubMesh& submesh, const vector<Bone>& 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(); i<len; ++i) - { - dest->mNumUVComponents[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<vector<aiVertexWeight> > assimpWeights(submesh.BonesUsed); - for(size_t vertexId=0, len=submesh.Weights.size(); vertexId<len; ++vertexId) - { - const vector<BoneWeight> &vertexWeights = submesh.Weights[vertexId]; - for (size_t boneId=0, len=vertexWeights.size(); boneId<len; ++boneId) - { - const BoneWeight &ogreWeight = vertexWeights[boneId]; - assimpWeights[ogreWeight.Id].push_back(aiVertexWeight(vertexId, ogreWeight.Value)); - } - } - - // Bones. - vector<aiBone*> assimpBones; - assimpBones.reserve(submesh.BonesUsed); - - for(size_t boneId=0, len=submesh.BonesUsed; boneId<len; ++boneId) - { - const vector<aiVertexWeight> &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(); i<len; ++i) { - dest->mBones[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(); i<len; ++i) - { - dest->mFaces[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/src/3rdparty/assimp/code/OgreParsingUtils.h b/src/3rdparty/assimp/code/OgreParsingUtils.h index ac1e58173..d3a7aa8bf 100644 --- a/src/3rdparty/assimp/code/OgreParsingUtils.h +++ b/src/3rdparty/assimp/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 <functional> + 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<typename T> -inline T GetAttribute(const XmlReader* reader, const std::string &name); - -template<> -inline int GetAttribute<int>(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<unsigned int>(const XmlReader* reader, const std::string &name) -{ - const char* value = reader->getAttributeValue(name.c_str()); - if (value) - { - return static_cast<unsigned int>(atoi(value)); ///< @todo Find a better way... - } - else - { - ThrowAttibuteError(reader, name); - return 0; - } -} - -template<> -inline float GetAttribute<float>(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<std::string>(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<bool>(const XmlReader* reader, const std::string &name) -{ - std::string value = GetAttribute<std::string>(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/src/3rdparty/assimp/code/OgreSkeleton.cpp b/src/3rdparty/assimp/code/OgreSkeleton.cpp deleted file mode 100644 index cc006dc09..000000000 --- a/src/3rdparty/assimp/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<Bone> &Bones, vector<Animation> &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<IOStream> file(pIOHandler->Open(filename)); - if (!file.get()) { - throw DeadlyImportError("Failed to open skeleton file " + filename); - } - - boost::scoped_ptr<CIrrXML_IOStreamReader> 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 <skeleton> but <" + string(reader->getNodeName()) + "> in " + filename); - } - - // Bones - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "bones")) { - throw DeadlyImportError("No <bones> 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<int>(reader, "id"); - bone.Name = GetAttribute<string>(reader, "name"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "position")) { - throw DeadlyImportError("Position is not first node in Bone!"); - } - - bone.Position.x = GetAttribute<float>(reader, "x"); - bone.Position.y = GetAttribute<float>(reader, "y"); - bone.Position.z = GetAttribute<float>(reader, "z"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "rotation")) { - throw DeadlyImportError("Rotation is not the second node in Bone!"); - } - - bone.RotationAngle = GetAttribute<float>(reader, "angle"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "axis")) { - throw DeadlyImportError("No axis specified for bone rotation!"); - } - - bone.RotationAxis.x = GetAttribute<float>(reader, "x"); - bone.RotationAxis.y = GetAttribute<float>(reader, "y"); - bone.RotationAxis.z = GetAttribute<float>(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<len; ++i) - { - if (static_cast<int>(Bones[i].Id) != static_cast<int>(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 <bonehierarchy> node found after <bones> in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "boneparent")) - { - string childName = GetAttribute<string>(reader, "bone"); - string parentName = GetAttribute<string>(reader, "parent"); - - vector<Bone>::iterator iterChild = find(Bones.begin(), Bones.end(), childName); - vector<Bone>::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<string>(reader, "name"); - animation.Length = GetAttribute<float>(reader, "length"); - - // Tracks - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "tracks")) { - throw DeadlyImportError("No <tracks> node found in animation '" + animation.Name + "' in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "track")) - { - Track track; - track.BoneName = GetAttribute<string>(reader, "bone"); - - // Keyframes - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "keyframes")) { - throw DeadlyImportError("No <keyframes> node found in a track in animation '" + animation.Name + "' in " + skeletonFile); - } - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "keyframe")) - { - KeyFrame keyFrame; - keyFrame.Time = GetAttribute<float>(reader, "time"); - - NextNode(reader); - while(CurrentNodeNameEquals(reader, "translate") || CurrentNodeNameEquals(reader, "rotate") || CurrentNodeNameEquals(reader, "scale")) - { - if (CurrentNodeNameEquals(reader, "translate")) - { - keyFrame.Position.x = GetAttribute<float>(reader, "x"); - keyFrame.Position.y = GetAttribute<float>(reader, "y"); - keyFrame.Position.z = GetAttribute<float>(reader, "z"); - } - else if (CurrentNodeNameEquals(reader, "rotate")) - { - float angle = GetAttribute<float>(reader, "angle"); - - NextNode(reader); - if (!CurrentNodeNameEquals(reader, "axis")) { - throw DeadlyImportError("No axis for keyframe rotation in animation '" + animation.Name + "'"); - } - - aiVector3D axis; - axis.x = GetAttribute<float>(reader, "x"); - axis.y = GetAttribute<float>(reader, "y"); - axis.z = GetAttribute<float>(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<float>(reader, "x"); - keyFrame.Scaling.y = GetAttribute<float>(reader, "y"); - keyFrame.Scaling.z = GetAttribute<float>(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<Bone> &bones, const std::vector<Animation> &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<aiNode*> 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(); i<len; ++i) { - pScene->mRootNode->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(); ai<alen; ++ai) - { - const Animation &aSource = animations[ai]; - - aiAnimation *animation = new aiAnimation(); - animation->mName = 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(); ti<tlen; ++ti) - { - const Track &tSource = aSource.Tracks[ti]; - - aiNodeAnim *animationNode = new aiNodeAnim(); - animationNode->mNodeName = tSource.BoneName; - - // We need this, to access the bones default pose. - // Which we need to make keys absolute to the default bone pose. - vector<Bone>::const_iterator boneIter = find(bones.begin(), bones.end(), tSource.BoneName); - if (boneIter == bones.end()) - { - for(size_t createdAnimationIndex=0; createdAnimationIndex<ai; createdAnimationIndex++) { - delete pScene->mAnimations[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; kfi<numKeyframes; ++kfi) - { - const KeyFrame &kfSource = tSource.Keyframes[kfi]; - - // Create a matrix to transform a vector from the bones - // default pose to the bone bones in this animation key - aiMatrix4x4 t2, t3; - aiMatrix4x4 keyBonePose = - aiMatrix4x4::Translation(kfSource.Position, t3) * - aiMatrix4x4(kfSource.Rotation.GetMatrix()) * - aiMatrix4x4::Scaling(kfSource.Scaling, t2); - - // Calculate the complete transformation from world space to bone space - aiMatrix4x4 CompleteTransform = defaultBonePose * keyBonePose; - - aiVector3D kfPos; aiQuaternion kfRot; aiVector3D kfScale; - CompleteTransform.Decompose(kfScale, kfRot, kfPos); - - animationNode->mPositionKeys[kfi].mTime = static_cast<double>(kfSource.Time); - animationNode->mRotationKeys[kfi].mTime = static_cast<double>(kfSource.Time); - animationNode->mScalingKeys[kfi].mTime = static_cast<double>(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<Bone> &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(); i<len; ++i) { - boneNode->mChildren[i] = CreateNodeFromBone(source.Children[i], bones, boneNode); - } - } - - return boneNode; -} - -void Bone::CalculateBoneToWorldSpaceMatrix(vector<Bone> &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/src/3rdparty/assimp/code/OgreStructs.cpp b/src/3rdparty/assimp/code/OgreStructs.cpp new file mode 100644 index 000000000..3eaf2df01 --- /dev/null +++ b/src/3rdparty/assimp/code/OgreStructs.cpp @@ -0,0 +1,1193 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER + +#include "OgreStructs.h" +#include "TinyFormatter.h" + +namespace Assimp +{ +namespace Ogre +{ + +// VertexElement + +VertexElement::VertexElement() : + index(0), + source(0), + offset(0), + type(VET_FLOAT1), + semantic(VES_POSITION) +{ +} + +size_t VertexElement::Size() const +{ + return TypeSize(type); +} + +size_t VertexElement::ComponentCount() const +{ + return ComponentCount(type); +} + +size_t VertexElement::ComponentCount(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + case VET_FLOAT1: + case VET_DOUBLE1: + case VET_SHORT1: + case VET_USHORT1: + case VET_INT1: + case VET_UINT1: + return 1; + case VET_FLOAT2: + case VET_DOUBLE2: + case VET_SHORT2: + case VET_USHORT2: + case VET_INT2: + case VET_UINT2: + return 2; + case VET_FLOAT3: + case VET_DOUBLE3: + case VET_SHORT3: + case VET_USHORT3: + case VET_INT3: + case VET_UINT3: + return 3; + case VET_FLOAT4: + case VET_DOUBLE4: + case VET_SHORT4: + case VET_USHORT4: + case VET_INT4: + case VET_UINT4: + case VET_UBYTE4: + return 4; + } + return 0; +} + +size_t VertexElement::TypeSize(Type type) +{ + switch(type) + { + case VET_COLOUR: + case VET_COLOUR_ABGR: + case VET_COLOUR_ARGB: + return sizeof(unsigned int); + case VET_FLOAT1: + return sizeof(float); + case VET_FLOAT2: + return sizeof(float)*2; + case VET_FLOAT3: + return sizeof(float)*3; + case VET_FLOAT4: + return sizeof(float)*4; + case VET_DOUBLE1: + return sizeof(double); + case VET_DOUBLE2: + return sizeof(double)*2; + case VET_DOUBLE3: + return sizeof(double)*3; + case VET_DOUBLE4: + return sizeof(double)*4; + case VET_SHORT1: + return sizeof(short); + case VET_SHORT2: + return sizeof(short)*2; + case VET_SHORT3: + return sizeof(short)*3; + case VET_SHORT4: + return sizeof(short)*4; + case VET_USHORT1: + return sizeof(unsigned short); + case VET_USHORT2: + return sizeof(unsigned short)*2; + case VET_USHORT3: + return sizeof(unsigned short)*3; + case VET_USHORT4: + return sizeof(unsigned short)*4; + case VET_INT1: + return sizeof(int); + case VET_INT2: + return sizeof(int)*2; + case VET_INT3: + return sizeof(int)*3; + case VET_INT4: + return sizeof(int)*4; + case VET_UINT1: + return sizeof(unsigned int); + case VET_UINT2: + return sizeof(unsigned int)*2; + case VET_UINT3: + return sizeof(unsigned int)*3; + case VET_UINT4: + return sizeof(unsigned int)*4; + case VET_UBYTE4: + return sizeof(unsigned char)*4; + } + return 0; +} + +std::string VertexElement::TypeToString() +{ + return TypeToString(type); +} + +std::string VertexElement::TypeToString(Type type) +{ + switch(type) + { + case VET_COLOUR: return "COLOUR"; + case VET_COLOUR_ABGR: return "COLOUR_ABGR"; + case VET_COLOUR_ARGB: return "COLOUR_ARGB"; + case VET_FLOAT1: return "FLOAT1"; + case VET_FLOAT2: return "FLOAT2"; + case VET_FLOAT3: return "FLOAT3"; + case VET_FLOAT4: return "FLOAT4"; + case VET_DOUBLE1: return "DOUBLE1"; + case VET_DOUBLE2: return "DOUBLE2"; + case VET_DOUBLE3: return "DOUBLE3"; + case VET_DOUBLE4: return "DOUBLE4"; + case VET_SHORT1: return "SHORT1"; + case VET_SHORT2: return "SHORT2"; + case VET_SHORT3: return "SHORT3"; + case VET_SHORT4: return "SHORT4"; + case VET_USHORT1: return "USHORT1"; + case VET_USHORT2: return "USHORT2"; + case VET_USHORT3: return "USHORT3"; + case VET_USHORT4: return "USHORT4"; + case VET_INT1: return "INT1"; + case VET_INT2: return "INT2"; + case VET_INT3: return "INT3"; + case VET_INT4: return "INT4"; + case VET_UINT1: return "UINT1"; + case VET_UINT2: return "UINT2"; + case VET_UINT3: return "UINT3"; + case VET_UINT4: return "UINT4"; + case VET_UBYTE4: return "UBYTE4"; + } + return "Uknown_VertexElement::Type"; +} + +std::string VertexElement::SemanticToString() +{ + return SemanticToString(semantic); +} + +std::string VertexElement::SemanticToString(Semantic semantic) +{ + switch(semantic) + { + case VES_POSITION: return "POSITION"; + case VES_BLEND_WEIGHTS: return "BLEND_WEIGHTS"; + case VES_BLEND_INDICES: return "BLEND_INDICES"; + case VES_NORMAL: return "NORMAL"; + case VES_DIFFUSE: return "DIFFUSE"; + case VES_SPECULAR: return "SPECULAR"; + case VES_TEXTURE_COORDINATES: return "TEXTURE_COORDINATES"; + case VES_BINORMAL: return "BINORMAL"; + case VES_TANGENT: return "TANGENT"; + } + return "Uknown_VertexElement::Semantic"; +} + +// IVertexData + +IVertexData::IVertexData() : + count(0) +{ +} + +bool IVertexData::HasBoneAssignments() const +{ + return !boneAssignments.empty(); +} + +void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex) +{ + BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]); + vertexIndexMapping[oldIndex].push_back(newIndex); +} + +void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const +{ + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + if (iter->vertexIndex == currentIndex) + { + VertexBoneAssignment a = (*iter); + a.vertexIndex = newIndex; + dest.push_back(a); + } + } +} + +AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices) +{ + AssimpVertexBoneWeightList weights; + for(size_t vi=0; vi<vertices; ++vi) + { + VertexBoneAssignmentList &vertexWeights = boneAssignmentsMap[vi]; + for (VertexBoneAssignmentList::const_iterator iter=vertexWeights.begin(), end=vertexWeights.end(); + iter!=end; ++iter) + { + std::vector<aiVertexWeight> &boneWeights = weights[iter->boneIndex]; + boneWeights.push_back(aiVertexWeight(vi, iter->weight)); + } + } + return weights; +} + +std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const +{ + std::set<uint16_t> referenced; + for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end(); + iter!=end; ++iter) + { + referenced.insert(iter->boneIndex); + } + return referenced; +} + +// VertexData + +VertexData::VertexData() +{ +} + +VertexData::~VertexData() +{ + Reset(); +} + +void VertexData::Reset() +{ + // Releases shared ptr memory streams. + vertexBindings.clear(); + vertexElements.clear(); +} + +uint32_t VertexData::VertexSize(uint16_t source) const +{ + uint32_t size = 0; + for(VertexElementList::const_iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + if (iter->source == source) + size += iter->Size(); + } + return size; +} + +MemoryStream *VertexData::VertexBuffer(uint16_t source) +{ + if (vertexBindings.find(source) != vertexBindings.end()) + return vertexBindings[source].get(); + return 0; +} + +VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index) +{ + for(VertexElementList::iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter) + { + VertexElement &element = (*iter); + if (element.semantic == semantic && element.index == index) + return &element; + } + return 0; +} + +// VertexDataXml + +VertexDataXml::VertexDataXml() +{ +} + +bool VertexDataXml::HasPositions() const +{ + return !positions.empty(); +} + +bool VertexDataXml::HasNormals() const +{ + return !normals.empty(); +} + +bool VertexDataXml::HasTangents() const +{ + return !tangents.empty(); +} + +bool VertexDataXml::HasUvs() const +{ + return !uvs.empty(); +} + +size_t VertexDataXml::NumUvs() const +{ + return uvs.size(); +} + +// IndexData + +IndexData::IndexData() : + count(0), + faceCount(0), + is32bit(false) +{ +} + +IndexData::~IndexData() +{ + Reset(); +} + +void IndexData::Reset() +{ + // Release shared ptr memory stream. + buffer.reset(); +} + +size_t IndexData::IndexSize() const +{ + return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t)); +} + +size_t IndexData::FaceSize() const +{ + return IndexSize() * 3; +} + +// Mesh + +Mesh::Mesh() : + sharedVertexData(0), + skeleton(0), + hasSkeletalAnimations(false) +{ +} + +Mesh::~Mesh() +{ + Reset(); +} + +void Mesh::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); i<len; ++i) { + OGRE_SAFE_DELETE(subMeshes[i]) + } + subMeshes.clear(); + for(size_t i=0, len=animations.size(); i<len; ++i) { + OGRE_SAFE_DELETE(animations[i]) + } + animations.clear(); + for(size_t i=0, len=poses.size(); i<len; ++i) { + OGRE_SAFE_DELETE(poses[i]) + } + poses.clear(); +} + +size_t Mesh::NumSubMeshes() const +{ + return subMeshes.size(); +} + +SubMesh *Mesh::GetSubMesh(uint16_t index) const +{ + for(size_t i=0; i<subMeshes.size(); ++i) + if (subMeshes[i]->index == index) + return subMeshes[i]; + return 0; +} + +void Mesh::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; i<dest->mNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); i<len; ++i) + { + dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode); + } + } + + // Animations + if (!skeleton->animations.empty()) + { + dest->mNumAnimations = skeleton->animations.size(); + dest->mAnimations = new aiAnimation*[dest->mNumAnimations]; + + for(size_t i=0, len=skeleton->animations.size(); i<len; ++i) + { + dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// ISubMesh + +ISubMesh::ISubMesh() : + index(0), + materialIndex(-1), + usesSharedVertexData(false), + operationType(OT_POINT_LIST) +{ +} + +// SubMesh + +SubMesh::SubMesh() : + vertexData(0), + indexData(new IndexData()) +{ +} + +SubMesh::~SubMesh() +{ + Reset(); +} + +void SubMesh::Reset() +{ + OGRE_SAFE_DELETE(vertexData) + OGRE_SAFE_DELETE(indexData) +} + +aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) +{ + if (operationType != OT_TRIANGLE_LIST) { + throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType); + } + + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Pick source vertex data from shader geometry or from internal geometry. + VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + + VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION); + VertexElement *normalsElement = src->GetVertexElement(VertexElement::VES_NORMAL); + VertexElement *uv1Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0); + VertexElement *uv2Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1); + + // Sanity checks + if (!positionsElement) { + throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!"); + } else if (positionsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) { + throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported."); + } + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + // Source streams + MemoryStream *positions = src->VertexBuffer(positionsElement->source); + MemoryStream *normals = (normalsElement ? src->VertexBuffer(normalsElement->source) : 0); + MemoryStream *uv1 = (uv1Element ? src->VertexBuffer(uv1Element->source) : 0); + MemoryStream *uv2 = (uv2Element ? src->VertexBuffer(uv2Element->source) : 0); + + // Element size + const size_t sizePosition = positionsElement->Size(); + const size_t sizeNormal = (normalsElement ? normalsElement->Size() : 0); + const size_t sizeUv1 = (uv1Element ? uv1Element->Size() : 0); + const size_t sizeUv2 = (uv2Element ? uv2Element->Size() : 0); + + // Vertex width + const size_t vWidthPosition = src->VertexSize(positionsElement->source); + const size_t vWidthNormal = (normalsElement ? src->VertexSize(normalsElement->source) : 0); + const size_t vWidthUv1 = (uv1Element ? src->VertexSize(uv1Element->source) : 0); + const size_t vWidthUv2 = (uv2Element ? src->VertexSize(uv2Element->source) : 0); + + bool boneAssignments = src->HasBoneAssignments(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs, ignoring incompatible UVs. + if (uv1) + { + if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[0] = uv1Element->ComponentCount(); + dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv1Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv1 = 0; + } + } + if (uv2) + { + if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3) + { + dest->mNumUVComponents[1] = uv2Element->ComponentCount(); + dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices]; + } + else + { + DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv2Element->TypeToString() << " is not compatible with Assimp. Ignoring UV."); + uv2 = 0; + } + } + + aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : 0); + aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : 0); + + MemoryStream *faces = indexData->buffer.get(); + for (size_t fi=0, isize=indexData->IndexSize(), fsize=indexData->FaceSize(); + fi<dest->mNumFaces; ++fi) + { + // Source Ogre face + aiFace ogreFace; + ogreFace.mNumIndices = 3; + ogreFace.mIndices = new unsigned int[3]; + + faces->Seek(fi * fsize, aiOrigin_SET); + if (indexData->is32bit) + { + faces->Read(&ogreFace.mIndices[0], isize, 3); + } + else + { + uint16_t iout = 0; + for (size_t ii=0; ii<3; ++ii) + { + faces->Read(&iout, isize, 1); + ogreFace.mIndices[ii] = static_cast<unsigned int>(iout); + } + } + + // Destination Assimp face + aiFace &face = dest->mFaces[fi]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + + const size_t pos = fi * 3; + for (size_t v=0; v<3; ++v) + { + const size_t newIndex = pos + v; + + // Write face index + face.mIndices[v] = newIndex; + + // Ogres vertex index to ref into the source buffers. + const size_t ogreVertexIndex = ogreFace.mIndices[v]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET); + positions->Read(&dest->mVertices[newIndex], sizePosition, 1); + + // Normal + if (normals) + { + normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET); + normals->Read(&dest->mNormals[newIndex], sizeNormal, 1); + } + // UV0 + if (uv1 && uv1Dest) + { + uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET); + uv1->Read(&uv1Dest[newIndex], sizeUv1, 1); + uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + // UV1 + if (uv2 && uv2Dest) + { + uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET); + uv2->Read(&uv2Dest[newIndex], sizeUv2, 1); + uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// MeshXml + +MeshXml::MeshXml() : + sharedVertexData(0), + skeleton(0) +{ +} + +MeshXml::~MeshXml() +{ + Reset(); +} + +void MeshXml::Reset() +{ + OGRE_SAFE_DELETE(skeleton) + OGRE_SAFE_DELETE(sharedVertexData) + + for(size_t i=0, len=subMeshes.size(); i<len; ++i) { + OGRE_SAFE_DELETE(subMeshes[i]) + } + subMeshes.clear(); +} + +size_t MeshXml::NumSubMeshes() const +{ + return subMeshes.size(); +} + +SubMeshXml *MeshXml::GetSubMesh(uint16_t index) const +{ + for(size_t i=0; i<subMeshes.size(); ++i) + if (subMeshes[i]->index == index) + return subMeshes[i]; + return 0; +} + +void MeshXml::ConvertToAssimpScene(aiScene* dest) +{ + // Setup + dest->mNumMeshes = NumSubMeshes(); + dest->mMeshes = new aiMesh*[dest->mNumMeshes]; + + // Create root node + dest->mRootNode = new aiNode(); + dest->mRootNode->mNumMeshes = dest->mNumMeshes; + dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes]; + + // Export meshes + for(size_t i=0; i<dest->mNumMeshes; ++i) + { + dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this); + dest->mRootNode->mMeshes[i] = i; + } + + // Export skeleton + if (skeleton) + { + // Bones + if (!skeleton->bones.empty()) + { + BoneList rootBones = skeleton->RootBones(); + dest->mRootNode->mNumChildren = rootBones.size(); + dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren]; + + for(size_t i=0, len=rootBones.size(); i<len; ++i) + { + dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode); + } + } + + // Animations + if (!skeleton->animations.empty()) + { + dest->mNumAnimations = skeleton->animations.size(); + dest->mAnimations = new aiAnimation*[dest->mNumAnimations]; + + for(size_t i=0, len=skeleton->animations.size(); i<len; ++i) + { + dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation(); + } + } + } +} + +// SubMeshXml + +SubMeshXml::SubMeshXml() : + vertexData(0), + indexData(new IndexDataXml()) +{ +} + +SubMeshXml::~SubMeshXml() +{ + Reset(); +} + +void SubMeshXml::Reset() +{ + OGRE_SAFE_DELETE(indexData) + OGRE_SAFE_DELETE(vertexData) +} + +aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent) +{ + aiMesh *dest = new aiMesh(); + dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + if (!name.empty()) + dest->mName = name; + + // Material index + if (materialIndex != -1) + dest->mMaterialIndex = materialIndex; + + // Faces + dest->mNumFaces = indexData->faceCount; + dest->mFaces = new aiFace[dest->mNumFaces]; + + // Assimp required unique vertices, we need to convert from Ogres shared indexing. + size_t uniqueVertexCount = dest->mNumFaces * 3; + dest->mNumVertices = uniqueVertexCount; + dest->mVertices = new aiVector3D[dest->mNumVertices]; + + VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData); + bool boneAssignments = src->HasBoneAssignments(); + bool normals = src->HasNormals(); + size_t uvs = src->NumUvs(); + + // Prepare normals + if (normals) + dest->mNormals = new aiVector3D[dest->mNumVertices]; + + // Prepare UVs + for(size_t uvi=0; uvi<uvs; ++uvi) + { + dest->mNumUVComponents[uvi] = 2; + dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices]; + } + + for (size_t fi=0; fi<dest->mNumFaces; ++fi) + { + // Source Ogre face + aiFace &ogreFace = indexData->faces[fi]; + + // Destination Assimp face + aiFace &face = dest->mFaces[fi]; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + + const size_t pos = fi * 3; + for (size_t v=0; v<3; ++v) + { + const size_t newIndex = pos + v; + + // Write face index + face.mIndices[v] = newIndex; + + // Ogres vertex index to ref into the source buffers. + const size_t ogreVertexIndex = ogreFace.mIndices[v]; + src->AddVertexMapping(ogreVertexIndex, newIndex); + + // Position + dest->mVertices[newIndex] = src->positions[ogreVertexIndex]; + + // Normal + if (normals) + dest->mNormals[newIndex] = src->normals[ogreVertexIndex]; + + // UVs + for(size_t uvi=0; uvi<uvs; ++uvi) + { + aiVector3D *uvDest = dest->mTextureCoords[uvi]; + std::vector<aiVector3D> &uvSrc = src->uvs[uvi]; + uvDest[newIndex] = uvSrc[ogreVertexIndex]; + } + } + } + + // Bones and bone weights + if (parent->skeleton && boneAssignments) + { + AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices); + std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights(); + + dest->mNumBones = referencedBones.size(); + dest->mBones = new aiBone*[dest->mNumBones]; + + size_t assimpBoneIndex = 0; + for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) + { + Bone *bone = parent->skeleton->BoneById((*rbIter)); + dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]); + } + } + + return dest; +} + +// Animation + +Animation::Animation(Skeleton *parent) : + parentSkeleton(parent), + parentMesh(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +Animation::Animation(Mesh *parent) : + parentMesh(parent), + parentSkeleton(0), + length(0.0f), + baseTime(-1.0f) +{ +} + +VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const +{ + if (!parentMesh) + return 0; + + bool sharedGeom = (track->target == 0); + if (sharedGeom) + return parentMesh->sharedVertexData; + else + return parentMesh->GetSubMesh(track->target-1)->vertexData; +} + +aiAnimation *Animation::ConvertToAssimpAnimation() +{ + aiAnimation *anim = new aiAnimation(); + anim->mName = name; + anim->mDuration = static_cast<double>(length); + anim->mTicksPerSecond = 1.0; + + // Tracks + if (!tracks.empty()) + { + anim->mNumChannels = tracks.size(); + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + + for(size_t i=0, len=tracks.size(); i<len; ++i) + { + anim->mChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton); + } + } + return anim; +} + +// Skeleton + +Skeleton::Skeleton() : + blendMode(ANIMBLEND_AVERAGE) +{ +} + +Skeleton::~Skeleton() +{ + Reset(); +} + +void Skeleton::Reset() +{ + for(size_t i=0, len=bones.size(); i<len; ++i) { + OGRE_SAFE_DELETE(bones[i]) + } + bones.clear(); + for(size_t i=0, len=animations.size(); i<len; ++i) { + OGRE_SAFE_DELETE(animations[i]) + } + animations.clear(); +} + +BoneList Skeleton::RootBones() const +{ + BoneList rootBones; + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if (!(*iter)->IsParented()) + rootBones.push_back((*iter)); + } + return rootBones; +} + +size_t Skeleton::NumRootBones() const +{ + size_t num = 0; + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if (!(*iter)->IsParented()) + num++; + } + return num; +} + +Bone *Skeleton::BoneByName(const std::string &name) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->name == name) + return (*iter); + } + return 0; +} + +Bone *Skeleton::BoneById(uint16_t id) const +{ + for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) + { + if ((*iter)->id == id) + return (*iter); + } + return 0; +} + +// Bone + +Bone::Bone() : + id(0), + parent(0), + parentId(-1), + scale(1.0f, 1.0f, 1.0f) +{ +} + +bool Bone::IsParented() const +{ + return (parentId != -1 && parent != 0); +} + +uint16_t Bone::ParentId() const +{ + return static_cast<uint16_t>(parentId); +} + +void Bone::AddChild(Bone *bone) +{ + if (!bone) + return; + if (bone->IsParented()) + throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name); + + bone->parent = this; + bone->parentId = id; + children.push_back(bone->id); +} + +void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) +{ + if (!IsParented()) + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse(); + else + worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix; + + defaultPose = aiMatrix4x4(scale, rotation, position); + + // Recursively for all children now that the parent matrix has been calculated. + for (size_t i=0, len=children.size(); i<len; ++i) + { + Bone *child = skeleton->BoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + child->CalculateWorldMatrixAndDefaultPose(skeleton); + } +} + +aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) +{ + // Bone node + aiNode* node = new aiNode(name); + node->mParent = parentNode; + node->mTransformation = defaultPose; + + // Children + if (!children.empty()) + { + node->mNumChildren = children.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + + for(size_t i=0, len=children.size(); i<len; ++i) + { + Bone *child = skeleton->BoneById(children[i]); + if (!child) { + throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + } + node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node); + } + } + return node; +} + +aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights) +{ + aiBone *bone = new aiBone(); + bone->mName = name; + bone->mOffsetMatrix = worldMatrix; + + if (!boneWeights.empty()) + { + bone->mNumWeights = boneWeights.size(); + bone->mWeights = new aiVertexWeight[boneWeights.size()]; + memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight)); + } + + return bone; +} + +// VertexAnimationTrack + +VertexAnimationTrack::VertexAnimationTrack() : + target(0), + type(VAT_NONE) +{ +} + +aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton) +{ + if (boneName.empty() || type != VAT_TRANSFORM) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM"); + } + + aiNodeAnim *nodeAnim = new aiNodeAnim(); + nodeAnim->mNodeName = boneName; + + Bone *bone = skeleton->BoneByName(boneName); + if (!bone) { + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton"); + } + + // Keyframes + size_t numKeyframes = transformKeyFrames.size(); + + nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes]; + nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes]; + nodeAnim->mNumPositionKeys = numKeyframes; + nodeAnim->mNumRotationKeys = numKeyframes; + nodeAnim->mNumScalingKeys = numKeyframes; + + for(size_t kfi=0; kfi<numKeyframes; ++kfi) + { + TransformKeyFrame &kfSource = transformKeyFrames[kfi]; + + // Calculate the complete transformation from world space to bone space + aiVector3D pos; aiQuaternion rot; aiVector3D scale; + + aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform(); + finalTransform.Decompose(scale, rot, pos); + + double t = static_cast<double>(kfSource.timePos); + nodeAnim->mPositionKeys[kfi].mTime = t; + nodeAnim->mRotationKeys[kfi].mTime = t; + nodeAnim->mScalingKeys[kfi].mTime = t; + + nodeAnim->mPositionKeys[kfi].mValue = pos; + nodeAnim->mRotationKeys[kfi].mValue = rot; + nodeAnim->mScalingKeys[kfi].mValue = scale; + } + + return nodeAnim; +} + +// TransformKeyFrame + +TransformKeyFrame::TransformKeyFrame() : + timePos(0.0f), + scale(1.0f, 1.0f, 1.0f) +{ +} + +aiMatrix4x4 TransformKeyFrame::Transform() +{ + return aiMatrix4x4(scale, rotation, position); +} + +} // Ogre +} // Assimp + +#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER diff --git a/src/3rdparty/assimp/code/OgreStructs.h b/src/3rdparty/assimp/code/OgreStructs.h new file mode 100644 index 000000000..75cadf4b7 --- /dev/null +++ b/src/3rdparty/assimp/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<MemoryStream> MemoryStreamPtr; +typedef std::map<uint16_t, MemoryStreamPtr> 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<VertexElement> VertexElementList; + +/// Ogre Vertex Bone Assignment +struct VertexBoneAssignment +{ + uint32_t vertexIndex; + uint16_t boneIndex; + float weight; +}; +typedef std::vector<VertexBoneAssignment> VertexBoneAssignmentList; +typedef std::map<uint32_t, VertexBoneAssignmentList > VertexBoneAssignmentsMap; +typedef std::map<uint16_t, std::vector<aiVertexWeight> > 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<uint16_t> 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<uint32_t, std::vector<uint32_t> > 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<uint32_t, Vertex> 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<Pose*> PoseList; + +/// Ogre Pose Key Frame Ref +struct PoseRef +{ + uint16_t index; + float influence; +}; +typedef std::vector<PoseRef> PoseRefList; + +/// Ogre Pose Key Frame +struct PoseKeyFrame +{ + /// Time position in the animation. + float timePos; + + PoseRefList references; +}; +typedef std::vector<PoseKeyFrame> PoseKeyFrameList; + +/// Ogre Morph Key Frame +struct MorphKeyFrame +{ + /// Time position in the animation. + float timePos; + + MemoryStreamPtr buffer; +}; +typedef std::vector<MorphKeyFrame> MorphKeyFrameList; + +/// Ogre animation key frame +struct TransformKeyFrame +{ + TransformKeyFrame(); + + aiMatrix4x4 Transform(); + + float timePos; + + aiQuaternion rotation; + aiVector3D position; + aiVector3D scale; +}; +typedef std::vector<TransformKeyFrame> 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<VertexAnimationTrack> 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<Animation*> 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<aiVertexWeight> &boneWeights); + + uint16_t id; + std::string name; + + Bone *parent; + int32_t parentId; + std::vector<uint16_t> children; + + aiVector3D position; + aiQuaternion rotation; + aiVector3D scale; + + aiMatrix4x4 worldMatrix; + aiMatrix4x4 defaultPose; +}; +typedef std::vector<Bone*> 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<SubMesh*> 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<aiVector3D> positions; + std::vector<aiVector3D> normals; + std::vector<aiVector3D> tangents; + std::vector<std::vector<aiVector3D> > uvs; +}; + +/// Ogre XML Index Data +class IndexDataXml +{ +public: + IndexDataXml() : faceCount(0) {} + + /// Face count. + uint32_t faceCount; + + std::vector<aiFace> 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<SubMeshXml*> 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/src/3rdparty/assimp/code/OgreXmlHelper.hpp b/src/3rdparty/assimp/code/OgreXmlHelper.hpp deleted file mode 100644 index 8a71a4be5..000000000 --- a/src/3rdparty/assimp/code/OgreXmlHelper.hpp +++ /dev/null @@ -1,88 +0,0 @@ - -#include "irrXMLWrapper.h" -#include "fast_atof.h" - -namespace Assimp -{ -namespace Ogre -{ - -typedef irr::io::IrrXMLReader XmlReader; - - -//------------Helper Funktion to Get a Attribute Save--------------- -template<typename t> inline t GetAttribute(XmlReader* Reader, std::string Name); - -/* -{ - BOOST_STATIC_ASSERT(false); - return t(); -} -*/ - -template<> inline int GetAttribute<int>(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return atoi(Value); - else - throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline unsigned int GetAttribute<unsigned int>(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return static_cast<unsigned int>(atoi(Value));//yes, ugly, but pfff - else - throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline float GetAttribute<float>(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return fast_atof(Value); - else - throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline std::string GetAttribute<std::string>(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return std::string(Value); - else - throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline bool GetAttribute<bool>(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - { - if(Value==std::string("true")) - return true; - else if(Value==std::string("false")) - return false; - else - throw DeadlyImportError(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName())); - } - else - throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} -//__________________________________________________________________ - -inline bool XmlRead(XmlReader* Reader) -{ - do - { - if(!Reader->read()) - return false; - } - while(Reader->getNodeType()!=irr::io::EXN_ELEMENT); - return true; -} - -}//namespace Ogre -}//namespace Assimp diff --git a/src/3rdparty/assimp/code/OgreXmlSerializer.cpp b/src/3rdparty/assimp/code/OgreXmlSerializer.cpp new file mode 100644 index 000000000..733e36c03 --- /dev/null +++ b/src/3rdparty/assimp/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<int32_t>(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name.c_str())); + } + else + { + ThrowAttibuteError(m_reader, name); + return 0; + } +} + +template<> +uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(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<int32_t>(name); + if (temp >= 0) + { + return static_cast<uint32_t>(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<uint16_t>(const std::string &name) const +{ + if (HasAttribute(name.c_str())) + { + return static_cast<uint16_t>(ReadAttribute<uint32_t>(name)); + } + else + { + ThrowAttibuteError(m_reader, name); + } + return 0; +} + +template<> +float OgreXmlSerializer::ReadAttribute<float>(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<std::string>(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<bool>(const std::string &name) const +{ + std::string value = Ogre::ToLower(ReadAttribute<std::string>(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 + +// <mesh> +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"; + +// <submesh> +const std::string nnFaces = "faces"; +const std::string nnFace = "face"; +const std::string nnGeometry = "geometry"; +const std::string nnTextures = "textures"; + +// <mesh/submesh> +const std::string nnBoneAssignments = "boneassignments"; + +// <sharedgeometry/geometry> +const std::string nnVertexBuffer = "vertexbuffer"; + +// <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"; + +// <boneassignments> +const std::string nnVertexBoneAssignment = "vertexboneassignment"; + +// Skeleton XML constants + +// <skeleton> +const std::string nnSkeleton = "skeleton"; +const std::string nnBones = "bones"; +const std::string nnBoneHierarchy = "bonehierarchy"; +const std::string nnAnimationLinks = "animationlinks"; + +// <bones> +const std::string nnBone = "bone"; +const std::string nnRotation = "rotation"; +const std::string nnAxis = "axis"; +const std::string nnScale = "scale"; + +// <bonehierarchy> +const std::string nnBoneParent = "boneparent"; + +// <animations> +const std::string nnAnimation = "animation"; +const std::string nnTracks = "tracks"; + +// <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 <mesh>"); + } + + 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<std::string>("name"); + DefaultLogger::get()->debug("Read skeleton link " + mesh->skeletonRef); + NextNode(); + } + // Assimp incompatible/ignored nodes + else + SkipCurrentNode(); + } +} + +void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) +{ + dest->count = ReadAttribute<uint32_t>("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<bool>("positions")); + bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals")); + bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents")); + uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("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(); i<len; ++i) { + dest->uvs[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<float>(anX); + pos.y = ReadAttribute<float>(anY); + pos.z = ReadAttribute<float>(anZ); + dest->positions.push_back(pos); + } + else if (normals && m_currentNodeName == nnNormal) + { + aiVector3D normal; + normal.x = ReadAttribute<float>(anX); + normal.y = ReadAttribute<float>(anY); + normal.z = ReadAttribute<float>(anZ); + dest->normals.push_back(normal); + } + else if (tangents && m_currentNodeName == nnTangent) + { + aiVector3D tangent; + tangent.x = ReadAttribute<float>(anX); + tangent.y = ReadAttribute<float>(anY); + tangent.z = ReadAttribute<float>(anZ); + dest->tangents.push_back(tangent); + } + else if (uvs > 0 && m_currentNodeName == nnTexCoord) + { + for(size_t i=0, len=dest->uvs.size(); i<len; ++i) + { + if (m_currentNodeName != nnTexCoord) { + throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex"); + } + + aiVector3D uv; + uv.x = ReadAttribute<float>("u"); + uv.y = (ReadAttribute<float>("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; i<dest->uvs.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<std::string>(anMaterial); + } + if (HasAttribute(anUseSharedVertices)) { + submesh->usesSharedVertexData = ReadAttribute<bool>(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<uint32_t>(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<uint32_t>(anV1); + face.mIndices[1] = ReadAttribute<uint32_t>(anV2); + face.mIndices[2] = ReadAttribute<uint32_t>(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 <face> has quads with <v4>, 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 <geometry> in <submesh> 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<uint32_t> influencedVertices; + + NextNode(); + while(m_currentNodeName == nnVertexBoneAssignment) + { + VertexBoneAssignment ba; + ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex); + ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex); + ba.weight = ReadAttribute<float>(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<uint32_t>::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<IOStream> file(pIOHandler->Open(filename)); + if (!file.get()) { + throw DeadlyImportError("Failed to open skeleton file " + filename); + } + + boost::scoped_ptr<CIrrXML_IOStreamReader> 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 <skeleton>"); + } + + DefaultLogger::get()->debug("Reading Skeleton"); + + // Optional blend mode from root node + if (HasAttribute("blendmode")) { + skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" + ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); + } + + NextNode(); + + // 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 <animations> for a Skeleton without bones"); + } + + DefaultLogger::get()->debug(" - Animations"); + + NextNode(); + while(m_currentNodeName == nnAnimation) + { + Animation *anim = new Animation(skeleton); + anim->name = ReadAttribute<std::string>("name"); + anim->length = ReadAttribute<float>("length"); + + if (NextNode() != nnTracks) { + throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << 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<std::string>("bone"); + + if (NextNode() != nnKeyFrames) { + throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << 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<float>("time"); + + NextNode(); + while(m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale) + { + if (m_currentNodeName == nnTranslate) + { + keyframe.position.x = ReadAttribute<float>(anX); + keyframe.position.y = ReadAttribute<float>(anY); + keyframe.position.z = ReadAttribute<float>(anZ); + } + else if (m_currentNodeName == nnRotate) + { + float angle = ReadAttribute<float>("angle"); + + if (NextNode() != nnAxis) { + throw DeadlyImportError("No axis specified for keyframe rotation in animation " + anim->name); + } + + aiVector3D axis; + axis.x = ReadAttribute<float>(anX); + axis.y = ReadAttribute<float>(anY); + axis.z = ReadAttribute<float>(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<float>(anX); + keyframe.scale.y = ReadAttribute<float>(anY); + keyframe.scale.z = ReadAttribute<float>(anZ); + } + + NextNode(); + } + + dest->transformKeyFrames.push_back(keyframe); + } +} + +void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) +{ + if (skeleton->bones.empty()) { + throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones"); + } + + while(NextNode() == nnBoneParent) + { + const std::string name = ReadAttribute<std::string>("bone"); + const std::string parentName = ReadAttribute<std::string>("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(); i<len; ++i) + { + Bone *bone = skeleton->bones[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<uint16_t>("id"); + bone->name = ReadAttribute<std::string>("name"); + + NextNode(); + while(m_currentNodeName == nnPosition || + m_currentNodeName == nnRotation || + m_currentNodeName == nnScale) + { + if (m_currentNodeName == nnPosition) + { + bone->position.x = ReadAttribute<float>(anX); + bone->position.y = ReadAttribute<float>(anY); + bone->position.z = ReadAttribute<float>(anZ); + } + else if (m_currentNodeName == nnRotation) + { + float angle = ReadAttribute<float>("angle"); + + if (NextNode() != nnAxis) { + throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id); + } + + aiVector3D axis; + axis.x = ReadAttribute<float>(anX); + axis.y = ReadAttribute<float>(anY); + axis.z = ReadAttribute<float>(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<float>("factor"); + bone->scale.Set(factor, factor, factor); + } + else + { + if (HasAttribute(anX)) + bone->scale.x = ReadAttribute<float>(anX); + if (HasAttribute(anY)) + bone->scale.y = ReadAttribute<float>(anY); + if (HasAttribute(anZ)) + bone->scale.z = ReadAttribute<float>(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(); i<len; ++i) + { + Bone *b = skeleton->bones[i]; + DefaultLogger::get()->debug(Formatter::format() << " " << b->id << " " << b->name); + + if (b->id != static_cast<uint16_t>(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/src/3rdparty/assimp/code/OgreXmlSerializer.h b/src/3rdparty/assimp/code/OgreXmlSerializer.h new file mode 100644 index 000000000..62257f81c --- /dev/null +++ b/src/3rdparty/assimp/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<XmlReader> 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<typename T> + 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/src/3rdparty/assimp/code/Q3BSPFileImporter.cpp b/src/3rdparty/assimp/code/Q3BSPFileImporter.cpp index ac36e9f53..81a770261 100644 --- a/src/3rdparty/assimp/code/Q3BSPFileImporter.cpp +++ b/src/3rdparty/assimp/code/Q3BSPFileImporter.cpp @@ -73,11 +73,11 @@ static const aiImporterDesc desc = { namespace Assimp { -//static void getSupportedExtensions(std::vector<std::string> &supportedExtensions) { -// supportedExtensions.push_back( ".jpg" ); -// supportedExtensions.push_back( ".png" ); -// supportedExtensions.push_back( ".tga" ); -//} +static void getSupportedExtensions(std::vector<std::string> &supportedExtensions) { + supportedExtensions.push_back( ".jpg" ); + supportedExtensions.push_back( ".png" ); + supportedExtensions.push_back( ".tga" ); +} using namespace Q3BSP; diff --git a/src/3rdparty/assimp/code/Q3BSPZipArchive.cpp b/src/3rdparty/assimp/code/Q3BSPZipArchive.cpp index d53e474db..ec98a2877 100644 --- a/src/3rdparty/assimp/code/Q3BSPZipArchive.cpp +++ b/src/3rdparty/assimp/code/Q3BSPZipArchive.cpp @@ -68,25 +68,25 @@ voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) { return (voidpf) io_system->Open(filename, mode_fopen); } -uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) { +uLong IOSystem2Unzip::read(voidpf opaque, voidpf stream, void* buf, uLong size) { IOStream* io_stream = (IOStream*) stream; return io_stream->Read(buf, 1, size); } -uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) { +uLong IOSystem2Unzip::write(voidpf opaque, voidpf stream, const void* buf, uLong size) { IOStream* io_stream = (IOStream*) stream; return io_stream->Write(buf, 1, size); } -long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { +long IOSystem2Unzip::tell(voidpf opaque, voidpf stream) { IOStream* io_stream = (IOStream*) stream; return io_stream->Tell(); } -long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) { +long IOSystem2Unzip::seek(voidpf opaque, voidpf stream, uLong offset, int origin) { IOStream* io_stream = (IOStream*) stream; aiOrigin assimp_origin; @@ -115,7 +115,7 @@ int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { return 0; } -int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { +int IOSystem2Unzip::testerror(voidpf opaque, voidpf stream) { return 0; } diff --git a/src/3rdparty/assimp/contrib/clipper/clipper.cpp b/src/3rdparty/assimp/contrib/clipper/clipper.cpp index f3c323f9b..2b209da69 100644 --- a/src/3rdparty/assimp/contrib/clipper/clipper.cpp +++ b/src/3rdparty/assimp/contrib/clipper/clipper.cpp @@ -2124,16 +2124,12 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt) { //check for 'rounding' artefacts ... if (outRec->sides == esNeither && pt.Y == op->pt.Y) - { if (ToFront) { if (pt.X == op->pt.X +1) return; //ie wrong side of bottomPt } - else - { - if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt - } - } + else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt + outRec->sides = (EdgeSide)(outRec->sides | e->side); if (outRec->sides == esBoth) { diff --git a/src/3rdparty/assimp/contrib/unzip/crypt.h b/src/3rdparty/assimp/contrib/unzip/crypt.h index 9d7957765..622f4bc2e 100644 --- a/src/3rdparty/assimp/contrib/unzip/crypt.h +++ b/src/3rdparty/assimp/contrib/unzip/crypt.h @@ -34,10 +34,10 @@ */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) { - (void)pcrc_32_tab; // Unused unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } @@ -47,7 +47,6 @@ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) */ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) { - (void)pcrc_32_tab; // Unused (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; diff --git a/src/3rdparty/assimp/contrib/unzip/ioapi.c b/src/3rdparty/assimp/contrib/unzip/ioapi.c index af4739443..b7200df75 100644 --- a/src/3rdparty/assimp/contrib/unzip/ioapi.c +++ b/src/3rdparty/assimp/contrib/unzip/ioapi.c @@ -69,9 +69,11 @@ int ZCALLBACK ferror_file_func ( voidpf stream); -voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; { - (void)opaque; // Unused FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) @@ -89,34 +91,44 @@ voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) } -uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; { - (void)opaque; // Unused uLong ret; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } -uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; { - (void)opaque; // Unused uLong ret; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } -long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; { - (void)opaque; // Unused long ret; ret = ftell((FILE *)stream); return ret; } -long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; { - (void)opaque; // Unused int fseek_origin=0; long ret; switch (origin) @@ -137,23 +149,26 @@ long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int o return ret; } -int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; { - (void)opaque; // Unused int ret; ret = fclose((FILE *)stream); return ret; } -int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; { - (void)opaque; // Unused int ret; ret = ferror((FILE *)stream); return ret; } -void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; diff --git a/src/3rdparty/assimp/contrib/unzip/unzip.h b/src/3rdparty/assimp/contrib/unzip/unzip.h index 600dfaa41..e3b7f24ee 100644 --- a/src/3rdparty/assimp/contrib/unzip/unzip.h +++ b/src/3rdparty/assimp/contrib/unzip/unzip.h @@ -45,6 +45,9 @@ #ifndef _unz_H #define _unz_H +#ifdef __cplusplus +extern "C" { +#endif #ifndef _ZLIB_H # ifdef ASSIMP_BUILD_NO_OWN_ZLIB @@ -54,17 +57,6 @@ # endif #endif -// This needs to be moved down a bit otherwise -// when using the Zlib headers bundled with Qt -// an extern C block is redefined within another -// extern C block resulting in an extern C dangling -// around causing hundred of template with C linkage e -// errors - -#ifdef __cplusplus -extern "C" { -#endif - #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif diff --git a/src/3rdparty/assimp/code/pstdint.h b/src/3rdparty/assimp/include/assimp/Compiler/pstdint.h index 5bc322fab..5bc322fab 100644 --- a/src/3rdparty/assimp/code/pstdint.h +++ b/src/3rdparty/assimp/include/assimp/Compiler/pstdint.h diff --git a/src/3rdparty/assimp/include/assimp/matrix4x4.h b/src/3rdparty/assimp/include/assimp/matrix4x4.h index 3d0857fe6..6ed550b7b 100644 --- a/src/3rdparty/assimp/include/assimp/matrix4x4.h +++ b/src/3rdparty/assimp/include/assimp/matrix4x4.h @@ -84,8 +84,8 @@ public: * @param rotation The rotation as a hamilton quaternion * @param position The position for the x,y,z axes */ - aiMatrix4x4t(aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation, - aiVector3t<TReal>& position); + aiMatrix4x4t(const aiVector3t<TReal>& scaling, const aiQuaterniont<TReal>& rotation, + const aiVector3t<TReal>& position); public: diff --git a/src/3rdparty/assimp/include/assimp/matrix4x4.inl b/src/3rdparty/assimp/include/assimp/matrix4x4.inl index 4697d77b6..4fb86b11b 100644 --- a/src/3rdparty/assimp/include/assimp/matrix4x4.inl +++ b/src/3rdparty/assimp/include/assimp/matrix4x4.inl @@ -109,7 +109,7 @@ inline aiMatrix4x4t<TReal>::aiMatrix4x4t (const aiMatrix3x3t<TReal>& m) // ---------------------------------------------------------------------------------------- template <typename TReal> -inline aiMatrix4x4t<TReal>::aiMatrix4x4t (aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation, aiVector3t<TReal>& position) +inline aiMatrix4x4t<TReal>::aiMatrix4x4t (const aiVector3t<TReal>& scaling, const aiQuaterniont<TReal>& rotation, const aiVector3t<TReal>& position) { // build a 3x3 rotation matrix aiMatrix3x3t<TReal> m = rotation.GetMatrix(); diff --git a/src/3rdparty/assimp/include/assimp/metadata.h b/src/3rdparty/assimp/include/assimp/metadata.h index 8c8880e81..16809a511 100644 --- a/src/3rdparty/assimp/include/assimp/metadata.h +++ b/src/3rdparty/assimp/include/assimp/metadata.h @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <assert.h> #if defined(_MSC_VER) && (_MSC_VER <= 1500) -#include "pstdint.h" +#include "Compiler/pstdint.h" #else #include <stdint.h> #endif diff --git a/src/3rdparty/assimp/include/assimp/quaternion.h b/src/3rdparty/assimp/include/assimp/quaternion.h index a1fcbea9f..ad64dd9d3 100644 --- a/src/3rdparty/assimp/include/assimp/quaternion.h +++ b/src/3rdparty/assimp/include/assimp/quaternion.h @@ -55,7 +55,7 @@ template <typename TReal> class aiQuaterniont { public: - aiQuaterniont() : w(), x(), y(), z() {} + aiQuaterniont() : w(1.0), x(), y(), z() {} aiQuaterniont(TReal pw, TReal px, TReal py, TReal pz) : w(pw), x(px), y(py), z(pz) {} diff --git a/src/3rdparty/assimp/include/assimp/vector3.h b/src/3rdparty/assimp/include/assimp/vector3.h index c21e6cfde..8176f98a7 100644 --- a/src/3rdparty/assimp/include/assimp/vector3.h +++ b/src/3rdparty/assimp/include/assimp/vector3.h @@ -88,6 +88,7 @@ public: // comparison bool operator== (const aiVector3t& other) const; bool operator!= (const aiVector3t& other) const; + bool operator < (const aiVector3t& other) const; bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const; diff --git a/src/3rdparty/assimp/include/assimp/vector3.inl b/src/3rdparty/assimp/include/assimp/vector3.inl index b8cbe8b49..01e0b6f9d 100644 --- a/src/3rdparty/assimp/include/assimp/vector3.inl +++ b/src/3rdparty/assimp/include/assimp/vector3.inl @@ -159,6 +159,11 @@ AI_FORCE_INLINE bool aiVector3t<TReal>::Equal(const aiVector3t<TReal>& other, TR } // ------------------------------------------------------------------------------------------------ template <typename TReal> +AI_FORCE_INLINE bool aiVector3t<TReal>::operator < (const aiVector3t<TReal>& other) const { + return x != other.x ? x < other.x : y != other.y ? y < other.y : z < other.z; +} +// ------------------------------------------------------------------------------------------------ +template <typename TReal> AI_FORCE_INLINE const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) { return aiVector3t<TReal>(x*o.x,y*o.y,z*o.z); } diff --git a/src/3rdparty/assimp/revision.h b/src/3rdparty/assimp/revision.h index cebfa4b16..b265fb08f 100644 --- a/src/3rdparty/assimp/revision.h +++ b/src/3rdparty/assimp/revision.h @@ -1,6 +1,7 @@ #ifndef ASSIMP_REVISION_H_INC #define ASSIMP_REVISION_H_INC -#define GitVersion 0xA0bA3A8; +#define GitVersion 0x1c4a8e9 +#define GitBranch "master" #endif // ASSIMP_REVISION_H_INC |