diff --git a/.travis.yml b/.travis.yml index aa07c4f75..e0c0788ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ before_install: - - sudo apt-get install cmake + - sudo apt-get install cmake libcppunit-dev env: - TRAVIS_NO_EXPORT=YES @@ -13,7 +13,9 @@ compiler: - gcc - clang -script: cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD && make - - +script: + - cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD + - make + - cd test/unit + - ../../bin/unit diff --git a/CMakeLists.txt b/CMakeLists.txt index 31561864f..e32afb166 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,8 +76,7 @@ SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH "Path the header files are installed to." ) SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH "Path the tool executables are installed to." ) -SET ( ASSIMP_BUILD_STATIC_LIB OFF CACHE BOOL - "Build a static (.a) version of the library" ) +option (ASSIMP_BUILD_STATIC_LIB "Build a static (.a) version of the library" OFF) SET(ASSIMP_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfitx for lib, samples and tools") @@ -102,8 +101,9 @@ ENDIF() # Globally enable Boost resp. the Boost workaround – it is also needed by the # tools which include the Assimp headers. -SET ( ASSIMP_ENABLE_BOOST_WORKAROUND ON CACHE BOOL +option ( ASSIMP_ENABLE_BOOST_WORKAROUND "If a simple implementation of the used Boost functions is used. Slightly reduces functionality, but enables builds without Boost available." + ON ) IF ( ASSIMP_ENABLE_BOOST_WORKAROUND ) INCLUDE_DIRECTORIES( code/BoostWorkaround ) @@ -129,8 +129,9 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${C configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) -SET ( ASSIMP_NO_EXPORT OFF CACHE BOOL - "Disable Assimp's export functionality." +option ( ASSIMP_NO_EXPORT + "Disable Assimp's export functionality." + OFF ) # Search for external dependencies, and build them from source if not found @@ -186,8 +187,9 @@ ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "") MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) ADD_SUBDIRECTORY( code/ ) -SET ( ASSIMP_BUILD_ASSIMP_TOOLS ON CACHE BOOL +option ( ASSIMP_BUILD_ASSIMP_TOOLS "If the supplementary tools for Assimp are built in addition to the library." + ON ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( WIN32 ) @@ -196,8 +198,9 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) ADD_SUBDIRECTORY( tools/assimp_cmd/ ) ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) -SET ( ASSIMP_BUILD_SAMPLES OFF CACHE BOOL +option ( ASSIMP_BUILD_SAMPLES "If the official samples are built as well (needs Glut)." + OFF ) IF ( ASSIMP_BUILD_SAMPLES) @@ -207,19 +210,19 @@ IF ( ASSIMP_BUILD_SAMPLES) ADD_SUBDIRECTORY( samples/SimpleOpenGL/ ) ENDIF ( ASSIMP_BUILD_SAMPLES ) -IF ( WIN32 ) - SET ( ASSIMP_BUILD_TESTS ON CACHE BOOL - "If the test suite for Assimp is built in addition to the library." - ) +option ( ASSIMP_BUILD_TESTS + "If the test suite for Assimp is built in addition to the library." + ON +) - IF ( ASSIMP_BUILD_TESTS ) - ADD_SUBDIRECTORY( test/ ) - ENDIF ( ASSIMP_BUILD_TESTS ) -ENDIF ( WIN32 ) +IF ( ASSIMP_BUILD_TESTS ) + ADD_SUBDIRECTORY( test/ ) +ENDIF ( ASSIMP_BUILD_TESTS ) IF(MSVC) - SET ( ASSIMP_INSTALL_PDB ON CACHE BOOL + option ( ASSIMP_INSTALL_PDB "Install MSVC debug files." + ON ) ENDIF(MSVC) diff --git a/Readme.md b/Readme.md index 77306459c..1945b9dbb 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +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 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. +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 __40 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) @@ -46,6 +46,7 @@ The library provides importers for a lot of file formats, including: - Ogre Binary - Ogre XML - Q3D +- ASSBIN (Assimp scene serialization) Additionally, the following formats are also supported, but not part of the core library as they depend on proprietary libraries. @@ -57,7 +58,10 @@ Exporters include: - STL - OBJ - PLY +- X +- 3DS - JSON (for WebGl, via https://github.com/acgessler/assimp2json) +- ASSBIN See [the full list here](http://assimp.sourceforge.net/main_features_formats.html). diff --git a/code/3DSExporter.cpp b/code/3DSExporter.cpp new file mode 100644 index 000000000..8ad367058 --- /dev/null +++ b/code/3DSExporter.cpp @@ -0,0 +1,560 @@ +/* +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_EXPORT +#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER + +#include "3DSExporter.h" +#include "3DSLoader.h" +#include "SceneCombiner.h" +#include "SplitLargeMeshes.h" + +using namespace Assimp; +namespace Assimp { + +namespace { + + ////////////////////////////////////////////////////////////////////////////////////// + // Scope utility to write a 3DS file chunk. + // + // Upon construction, the chunk header is written with the chunk type (flags) + // filled out, but the chunk size left empty. Upon destruction, the correct chunk + // size based on the then-position of the output stream cursor is filled in. + class ChunkWriter { + enum { + CHUNK_SIZE_NOT_SET = 0xdeadbeef + , SIZE_OFFSET = 2 + }; + public: + + ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type) + : writer(writer) + { + chunk_start_pos = writer.GetCurrentPos(); + writer.PutU2(chunk_type); + writer.PutU4(CHUNK_SIZE_NOT_SET); + } + + ~ChunkWriter() { + std::size_t head_pos = writer.GetCurrentPos(); + + ai_assert(head_pos > chunk_start_pos); + const std::size_t chunk_size = head_pos - chunk_start_pos; + + writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET); + writer.PutU4(chunk_size); + writer.SetCurrentPos(head_pos); + } + + private: + StreamWriterLE& writer; + std::size_t chunk_start_pos; + }; + + + // Return an unique name for a given |mesh| attached to |node| that + // preserves the mesh's given name if it has one. |index| is the index + // of the mesh in |aiScene::mMeshes|. + std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) { + static const std::string underscore = "_"; + char postfix[10] = {0}; + ASSIMP_itoa10(postfix, index); + + std::string result = node.mName.C_Str(); + if (mesh.mName.length > 0) { + result += underscore + mesh.mName.C_Str(); + } + return result + underscore + postfix; + } + + // Return an unique name for a given |mat| with original position |index| + // in |aiScene::mMaterials|. The name preserves the original material + // name if possible. + std::string GetMaterialName(const aiMaterial& mat, unsigned int index) { + static const std::string underscore = "_"; + char postfix[10] = {0}; + ASSIMP_itoa10(postfix, index); + + aiString mat_name; + if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) { + return mat_name.C_Str() + underscore + postfix; + } + + return "Material" + underscore + postfix; + } + + // Collect world transformations for each node + void CollectTrafos(const aiNode* node, std::map& trafos) { + const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4(); + trafos[node] = parent * node->mTransformation; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectTrafos(node->mChildren[i], trafos); + } + } + + // Generate a flat list of the meshes (by index) assigned to each node + void CollectMeshes(const aiNode* node, std::multimap& meshes) { + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + meshes.insert(std::make_pair(node, node->mMeshes[i])); + } + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectMeshes(node->mChildren[i], meshes); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp +void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) +{ + boost::shared_ptr outfile (pIOSystem->Open(pFile, "wb")); + if(!outfile) { + throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile)); + } + + // TODO: This extra copy should be avoided and all of this made a preprocess + // requirement of the 3DS exporter. + // + // 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively. + // SplitLargeMeshes can do this, but it requires the correct limit to be set + // which is not possible with the current way of specifying preprocess steps + // in |Exporter::ExportFormatEntry|. + aiScene* scenecopy_tmp; + SceneCombiner::CopyScene(&scenecopy_tmp,pScene); + std::auto_ptr scenecopy(scenecopy_tmp); + + SplitLargeMeshesProcess_Triangle tri_splitter; + tri_splitter.SetLimit(0xffff); + tri_splitter.Execute(scenecopy.get()); + + SplitLargeMeshesProcess_Vertex vert_splitter; + vert_splitter.SetLimit(0xffff); + vert_splitter.Execute(scenecopy.get()); + + // Invoke the actual exporter + Discreet3DSExporter exporter(outfile, scenecopy.get()); +} + +} // end of namespace Assimp + +// ------------------------------------------------------------------------------------------------ +Discreet3DSExporter:: Discreet3DSExporter(boost::shared_ptr outfile, const aiScene* scene) +: scene(scene) +, writer(outfile) +{ + CollectTrafos(scene->mRootNode, trafos); + CollectMeshes(scene->mRootNode, meshes); + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH); + WriteMeshes(); + WriteMaterials(); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE); + writer.PutF4(1.0f); + } + } + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER); + WriteHierarchy(*scene->mRootNode, -1, -1); + } +} + +// ------------------------------------------------------------------------------------------------ +int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level) +{ + // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + + // Assimp node names are unique and distinct from all mesh-node + // names we generate; thus we can use them as-is + WriteString(node.mName); + + // Two unknown int16 values - it is even unclear if 0 is a safe value + // but luckily importers do not know better either. + writer.PutI4(0); + + int16_t hierarchy_pos = static_cast(seq); + if (sibling_level != -1) { + hierarchy_pos = sibling_level; + } + + // Write the hierarchy position + writer.PutI2(hierarchy_pos); + } + } + + // TODO: write transformation chunks + + ++seq; + sibling_level = seq; + + // Write all children + for (unsigned int i = 0; i < node.mNumChildren; ++i) { + seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level); + } + + // Write all meshes as separate nodes to be able to reference the meshes by name + for (unsigned int i = 0; i < node.mNumMeshes; ++i) { + const bool first_child = node.mNumChildren == 0 && i == 0; + + const unsigned int mesh_idx = node.mMeshes[i]; + const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + WriteString(GetMeshName(mesh, mesh_idx, node)); + + writer.PutI4(0); + writer.PutI2(static_cast(first_child ? seq : sibling_level)); + ++seq; + } + } + return seq; +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteMaterials() +{ + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); + const aiMaterial& mat = *scene->mMaterials[i]; + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME); + const std::string& name = GetMaterialName(mat, i); + WriteString(name); + } + + aiColor3D color; + if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); + WriteColor(color); + } + + if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); + WriteColor(color); + } + + aiShadingMode shading_mode; + if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING); + + Discreet3DS::shadetype3ds shading_mode_out; + switch(shading_mode) { + case aiShadingMode_Flat: + case aiShadingMode_NoShading: + shading_mode_out = Discreet3DS::Flat; + break; + + case aiShadingMode_Gouraud: + case aiShadingMode_Toon: + case aiShadingMode_OrenNayar: + case aiShadingMode_Minnaert: + shading_mode_out = Discreet3DS::Gouraud; + break; + + case aiShadingMode_Phong: + case aiShadingMode_Blinn: + case aiShadingMode_CookTorrance: + case aiShadingMode_Fresnel: + shading_mode_out = Discreet3DS::Phong; + break; + + default: + ai_assert(false); + }; + writer.PutU2(static_cast(shading_mode_out)); + } + + + float f; + if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS); + WritePercentChunk(f); + } + + if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT); + WritePercentChunk(f); + } + + int twosided; + if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE); + writer.PutI2(1); + } + + WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE); + WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP); + WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP); + WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP); + WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP); + WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP); + WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP); + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags) +{ + aiString path; + aiTextureMapMode map_mode[2] = { + aiTextureMapMode_Wrap, aiTextureMapMode_Wrap + }; + float blend = 1.0f; + if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) { + return; + } + + // TODO: handle embedded textures properly + if (path.data[0] == '*') { + DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str())); + return; + } + + ChunkWriter chunk(writer, chunk_flags); + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE); + WriteString(path); + } + + WritePercentChunk(blend); + + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); + uint16_t val = 0; // WRAP + if (map_mode[0] == aiTextureMapMode_Mirror) { + val = 0x2; + } + else if (map_mode[0] == aiTextureMapMode_Decal) { + val = 0x10; + } + writer.PutU2(val); + } + // TODO: export texture transformation (i.e. UV offset, scale, rotation) +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteMeshes() +{ + // NOTE: 3DS allows for instances. However: + // i) not all importers support reading them + // ii) instances are not as flexible as they are in assimp, in particular, + // nodes can carry (and instance) only one mesh. + // + // This exporter currently deep clones all instanced meshes, i.e. for each mesh + // attached to a node a full TRIMESH chunk is written to the file. + // + // Furthermore, the TRIMESH is transformed into world space so that it will + // appear correctly if importers don't read the scene hierarchy at all. + for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) { + const aiNode& node = *(*it).first; + const unsigned int mesh_idx = (*it).second; + + const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + + // This should not happen if the SLM step is correctly executed + // before the scene is handed to the exporter + ai_assert(mesh.mNumVertices <= 0xffff); + ai_assert(mesh.mNumFaces <= 0xffff); + + const aiMatrix4x4& trafo = trafos[&node]; + + ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK); + + // Mesh name is tied to the node it is attached to so it can later be referenced + const std::string& name = GetMeshName(mesh, mesh_idx, node); + WriteString(name); + + + // TRIMESH chunk + ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH); + + // Vertices in world space + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST); + + const uint16_t count = static_cast(mesh.mNumVertices); + writer.PutU2(count); + for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { + const aiVector3D& v = trafo * mesh.mVertices[i]; + writer.PutF4(v.x); + writer.PutF4(v.y); + writer.PutF4(v.z); + } + } + + // UV coordinates + if (mesh.HasTextureCoords(0)) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST); + const uint16_t count = static_cast(mesh.mNumVertices); + writer.PutU2(count); + + for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { + const aiVector3D& v = mesh.mTextureCoords[0][i]; + writer.PutF4(v.x); + writer.PutF4(v.y); + } + } + + // Faces (indices) + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST); + + ai_assert(mesh.mNumFaces <= 0xffff); + + // Count triangles, discard lines and points + uint16_t count = 0; + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + const aiFace& f = mesh.mFaces[i]; + if (f.mNumIndices < 3) { + continue; + } + // TRIANGULATE step is a pre-requisite so we should not see polys here + ai_assert(f.mNumIndices == 3); + ++count; + } + + writer.PutU2(count); + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + const aiFace& f = mesh.mFaces[i]; + if (f.mNumIndices < 3) { + continue; + } + + for (unsigned int j = 0; j < 3; ++j) { + ai_assert(f.mIndices[j] <= 0xffff); + writer.PutI2(static_cast(f.mIndices[j])); + } + + // Edge visibility flag + writer.PutI2(0x0); + } + + // TODO: write smoothing groups (CHUNK_SMOOLIST) + + WriteFaceMaterialChunk(mesh); + } + + // Transformation matrix by which the mesh vertices have been pre-transformed with. + { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX); + for (unsigned int r = 0; r < 4; ++r) { + for (unsigned int c = 0; c < 3; ++c) { + writer.PutF4(trafo[r][c]); + } + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) +{ + ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT); + const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); + WriteString(name); + + // Because assimp splits meshes by material, only a single + // FACEMAT chunk needs to be written + ai_assert(mesh.mNumFaces <= 0xffff); + const uint16_t count = static_cast(mesh.mNumFaces); + writer.PutU2(count); + + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { + writer.PutU2(static_cast(i)); + } +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteString(const std::string& s) { + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { + writer.PutI1(*it); + } + writer.PutI1('\0'); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteString(const aiString& s) { + for (std::size_t i = 0; i < s.length; ++i) { + writer.PutI1(s.data[i]); + } + writer.PutI1('\0'); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WriteColor(const aiColor3D& color) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF); + writer.PutF4(color.r); + writer.PutF4(color.g); + writer.PutF4(color.b); +} + +// ------------------------------------------------------------------------------------------------ +void Discreet3DSExporter::WritePercentChunk(float f) { + ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF); + writer.PutF4(f); +} + + +#endif // ASSIMP_BUILD_NO_3DS_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/3DSExporter.h b/code/3DSExporter.h new file mode 100644 index 000000000..9742abb0c --- /dev/null +++ b/code/3DSExporter.h @@ -0,0 +1,94 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @file 3DSExporter.h + * 3DS Exporter Main Header + */ +#ifndef AI_3DSEXPORTER_H_INC +#define AI_3DSEXPORTER_H_INC + +#include + +#include "StreamWriter.h" + +struct aiScene; +struct aiNode; + +namespace Assimp +{ + +// ------------------------------------------------------------------------------------------------ +/** Helper class to export a given scene to a 3DS file. */ +// ------------------------------------------------------------------------------------------------ +class Discreet3DSExporter +{ +public: + Discreet3DSExporter(boost::shared_ptr outfile, const aiScene* pScene); + +private: + + void WriteMeshes(); + void WriteMaterials(); + void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags); + + void WriteFaceMaterialChunk(const aiMesh& mesh); + + int WriteHierarchy(const aiNode& node, int level, int sibling_level); + + void WriteString(const std::string& s); + void WriteString(const aiString& s); + void WriteColor(const aiColor3D& color); + void WritePercentChunk(float f); + +private: + + const aiScene* const scene; + StreamWriterLE writer; + + std::map trafos; + + typedef std::multimap MeshesByNodeMap; + MeshesByNodeMap meshes; + +}; + +} + +#endif diff --git a/code/3DSLoader.h b/code/3DSLoader.h index 5e80195f5..2b1dd26f8 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -273,8 +273,8 @@ protected: bool bIsPrj; }; -#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER - } // end of namespace Assimp +#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER + #endif // AI_3DSIMPORTER_H_INC diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp new file mode 100644 index 000000000..a330dfd45 --- /dev/null +++ b/code/AssbinExporter.cpp @@ -0,0 +1,762 @@ +/* +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. + +---------------------------------------------------------------------- +*/ +/** @file AssbinExporter.cpp + * ASSBIN exporter main code + */ +#include "AssimpPCH.h" +#include "assbin_chunks.h" +#include "./../include/assimp/version.h" +#include "ProcessHelper.h" + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include "../contrib/zlib/zlib.h" +#endif + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER + +using namespace Assimp; + +namespace Assimp { + +template +size_t Write(IOStream * stream, const T& v) +{ + return stream->Write( &v, sizeof(T), 1 ); +} + + +// ----------------------------------------------------------------------------------- +// Serialize an aiString +template <> +inline size_t Write(IOStream * stream, const aiString& s) +{ + const size_t s2 = (uint32_t)s.length; + stream->Write(&s,4,1); + stream->Write(s.data,s2,1); + return s2+4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint32_t +template <> +inline size_t Write(IOStream * stream, const unsigned int& w) +{ + const uint32_t t = (uint32_t)w; + if (w > t) { + // this shouldn't happen, integers in Assimp data structures never exceed 2^32 + throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); + } + + stream->Write(&t,4,1); + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint16_t +template <> +inline size_t Write(IOStream * stream, const uint16_t& w) +{ + BOOST_STATIC_ASSERT(sizeof(uint16_t)==2); + stream->Write(&w,2,1); + return 2; +} + +// ----------------------------------------------------------------------------------- +// Serialize a float +template <> +inline size_t Write(IOStream * stream, const float& f) +{ + BOOST_STATIC_ASSERT(sizeof(float)==4); + stream->Write(&f,4,1); + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize a double +template <> +inline size_t Write(IOStream * stream, const double& f) +{ + BOOST_STATIC_ASSERT(sizeof(double)==8); + stream->Write(&f,8,1); + return 8; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vec3 +template <> +inline size_t Write(IOStream * stream, const aiVector3D& v) +{ + size_t t = Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline size_t Write(IOStream * stream, const aiColor4D& v) +{ + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + t += Write(stream,v.a); + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a quaternion +template <> +inline size_t Write(IOStream * stream, const aiQuaternion& v) +{ + size_t t = Write(stream,v.w); + t += Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + return 16; +} + + +// ----------------------------------------------------------------------------------- +// Serialize a vertex weight +template <> +inline size_t Write(IOStream * stream, const aiVertexWeight& v) +{ + size_t t = Write(stream,v.mVertexId); + return t+Write(stream,v.mWeight); +} + +// ----------------------------------------------------------------------------------- +// Serialize a mat4x4 +template <> +inline size_t Write(IOStream * stream, const aiMatrix4x4& m) +{ + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + Write(stream,m[i][i2]); + } + } + return 64; +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiVectorKey +template <> +inline size_t Write(IOStream * stream, const aiVectorKey& v) +{ + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiQuatKey +template <> +inline size_t Write(IOStream * stream, const aiQuatKey& v) +{ + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +template +inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) +{ + T minc,maxc; + ArrayBounds(in,size,minc,maxc); + + const size_t t = Write(stream,minc); + return t + Write(stream,maxc); +} + +// We use this to write out non-byte arrays so that we write using the specializations. +// This way we avoid writing out extra bytes that potentially come from struct alignment. +template +inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) +{ + size_t n = 0; + for (unsigned int i=0; i(stream,in[i]); + return n; +} + + // ---------------------------------------------------------------------------------- + /** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ + class AssbinChunkWriter : public IOStream + { + private: + + uint8_t* buffer; + uint32_t magic; + IOStream * container; + size_t cur_size, cursor, initial; + + private: + // ------------------------------------------------------------------- + void Grow(size_t need = 0) + { + size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + + const uint8_t* const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer,old,cur_size); + delete[] old; + } + + cur_size = new_size; + } + + public: + + AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) + : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) + { + } + + virtual ~AssbinChunkWriter() + { + if (container) { + container->Write( &magic, sizeof(uint32_t), 1 ); + container->Write( &cursor, sizeof(uint32_t), 1 ); + container->Write( buffer, 1, cursor ); + } + if (buffer) delete[] buffer; + } + + void * GetBufferPointer() { return buffer; }; + + // ------------------------------------------------------------------- + virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }; + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }; + virtual size_t Tell() const { return cursor; }; + virtual void Flush() { }; + + virtual size_t FileSize() const + { + return cursor; + } + + // ------------------------------------------------------------------- + virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) + { + pSize *= pCount; + if (cursor + pSize > cur_size) { + Grow(cursor + pSize); + } + + memcpy(buffer+cursor, pvBuffer, pSize); + cursor += pSize; + + return pCount; + } + + }; + + // ---------------------------------------------------------------------------------- + /** @class AssbinExport + * @brief Assbin exporter class + * + * This class performs the .assbin exporting, and is responsible for the file layout. + */ + class AssbinExport + { + private: + bool shortened; + bool compressed; + + protected: + + // ----------------------------------------------------------------------------------- + void WriteBinaryNode( IOStream * container, const aiNode* node) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + + Write(&chunk,node->mName); + Write(&chunk,node->mTransformation); + Write(&chunk,node->mNumChildren); + Write(&chunk,node->mNumMeshes); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + Write(&chunk,node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteBinaryNode( &chunk, node->mChildren[i] ); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + Write(&chunk,tex->mWidth); + Write(&chunk,tex->mHeight); + chunk.Write( tex->achFormatHint, sizeof(char), 4 ); + + if(!shortened) { + if (!tex->mHeight) { + chunk.Write(tex->pcData,1,tex->mWidth); + } + else { + chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryBone(IOStream * container, const aiBone* b) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + + Write(&chunk,b->mName); + Write(&chunk,b->mNumWeights); + Write(&chunk,b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(&chunk,b->mWeights,b->mNumWeights); + } // else write as usual + else WriteArray(&chunk,b->mWeights,b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + + Write(&chunk,mesh->mPrimitiveTypes); + Write(&chunk,mesh->mNumVertices); + Write(&chunk,mesh->mNumFaces); + Write(&chunk,mesh->mNumBones); + Write(&chunk,mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk,c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + Write(&chunk,mesh->mNumUVComponents[n]); + + if (shortened) { + WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { + + uint32_t hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + uint32_t tmp = f.mNumIndices; + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + for (unsigned int i = 0; i < f.mNumIndices; ++i) { + BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff); + tmp = static_cast( f.mIndices[i] ); + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + } + } + Write(&chunk,hash); + } + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff); + Write(&chunk,f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + Write(&chunk,f.mIndices[a]); + } + else Write(&chunk,f.mIndices[a]); + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + WriteBinaryBone(&chunk,b); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + + Write(&chunk,prop->mKey); + Write(&chunk,prop->mSemantic); + Write(&chunk,prop->mIndex); + + Write(&chunk,prop->mDataLength); + Write(&chunk,(unsigned int)prop->mType); + chunk.Write(prop->mData,1,prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + + Write(&chunk,mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + + Write(&chunk,nd->mNodeName); + Write(&chunk,nd->mNumPositionKeys); + Write(&chunk,nd->mNumRotationKeys); + Write(&chunk,nd->mNumScalingKeys); + Write(&chunk,nd->mPreState); + Write(&chunk,nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + } + } + + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); + + Write(&chunk,anim->mName); + Write(&chunk,anim->mDuration); + Write(&chunk,anim->mTicksPerSecond); + Write(&chunk,anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk,nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight( IOStream * container, const aiLight* l ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + + Write(&chunk,l->mName); + Write(&chunk,l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + Write(&chunk,l->mAttenuationConstant); + Write(&chunk,l->mAttenuationLinear); + Write(&chunk,l->mAttenuationQuadratic); + } + + Write(&chunk,(const aiVector3D&)l->mColorDiffuse); + Write(&chunk,(const aiVector3D&)l->mColorSpecular); + Write(&chunk,(const aiVector3D&)l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk,l->mAngleInnerCone); + Write(&chunk,l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + + Write(&chunk,cam->mName); + Write(&chunk,cam->mPosition); + Write(&chunk,cam->mLookAt); + Write(&chunk,cam->mUp); + Write(&chunk,cam->mHorizontalFOV); + Write(&chunk,cam->mClipPlaneNear); + Write(&chunk,cam->mClipPlaneFar); + Write(&chunk,cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene( IOStream * container, const aiScene* scene) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + + // basic scene information + Write(&chunk,scene->mFlags); + Write(&chunk,scene->mNumMeshes); + Write(&chunk,scene->mNumMaterials); + Write(&chunk,scene->mNumAnimations); + Write(&chunk,scene->mNumTextures); + Write(&chunk,scene->mNumLights); + Write(&chunk,scene->mNumCameras); + + // write node graph + WriteBinaryNode( &chunk, scene->mRootNode ); + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + WriteBinaryMesh( &chunk,mesh); + } + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk,mat); + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + const aiAnimation* anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk,anim); + } + + + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + const aiTexture* mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk,mesh); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + WriteBinaryLight(&chunk,l); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk,cam); + } + + } + + public: + AssbinExport() + : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters + { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) + { + IOStream * out = pIOSystem->Open( pFile, "wb" ); + if (!out) return; + + time_t tt = time(NULL); + tm* p = gmtime(&tt); + + // header + char s[64]; + memset( s, 0, 64 ); +#if _MSC_VER >= 1400 + sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); +#else + snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); +#endif + out->Write( s, 44, 1 ); + // == 44 bytes + + Write( out, ASSBIN_VERSION_MAJOR ); + Write( out, ASSBIN_VERSION_MINOR ); + Write( out, aiGetVersionRevision() ); + Write( out, aiGetCompileFlags() ); + Write( out, shortened ); + Write( out, compressed ); + // == 20 bytes + + char buff[256]; + strncpy(buff,pFile,256); + out->Write(buff,sizeof(char),256); + + char cmd[] = "\0"; + strncpy(buff,cmd,128); + out->Write(buff,sizeof(char),128); + + // leave 64 bytes free for future extensions + memset(buff,0xcd,64); + out->Write(buff,sizeof(char),64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + if (compressed) + { + AssbinChunkWriter uncompressedStream( NULL, 0 ); + WriteBinaryScene( &uncompressedStream, pScene ); + + uLongf uncompressedSize = uncompressedStream.Tell(); + uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.); + uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; + + compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); + + out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); + out->Write( compressedBuffer, sizeof(char), compressedSize ); + + delete[] compressedBuffer; + } + else + { + WriteBinaryScene( out, pScene ); + } + + pIOSystem->Close( out ); + } + }; + +void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) +{ + AssbinExport exporter; + exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); +} +} // end of namespace Assimp + +#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/AssbinExporter.h b/code/AssbinExporter.h new file mode 100644 index 000000000..34ccda3e1 --- /dev/null +++ b/code/AssbinExporter.h @@ -0,0 +1,49 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @file AssbinExporter.h + * ASSBIN Exporter Main Header + */ +#ifndef AI_ASSBINEXPORTER_H_INC +#define AI_ASSBINEXPORTER_H_INC + +// nothing really needed here - reserved for future use like properties + +#endif diff --git a/code/AssbinLoader.cpp b/code/AssbinLoader.cpp new file mode 100644 index 000000000..65299f577 --- /dev/null +++ b/code/AssbinLoader.cpp @@ -0,0 +1,671 @@ +/* +--------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- +*/ + +/** @file AssbinLoader.cpp + * @brief Implementation of the .assbin importer class + * + * see assbin_chunks.h + */ + +#include "AssimpPCH.h" +#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +// internal headers +#include "AssbinLoader.h" +#include "assbin_chunks.h" +#include "MemoryIOWrapper.h" +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include "../contrib/zlib/zlib.h" +#endif + +using namespace Assimp; + +static const aiImporterDesc desc = { + ".assbin Importer", + "Gargaj / Conspiracy", + "", + "", + aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour, + 0, + 0, + 0, + 0, + "assbin" +}; + +const aiImporterDesc* AssbinImporter::GetInfo() const +{ + return &desc; +} + +bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const +{ + IOStream * in = pIOHandler->Open(pFile); + if (!in) + return false; + + char s[32]; + in->Read( s, sizeof(char), 32 ); + + pIOHandler->Close(in); + + return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0; +} + +template +T Read(IOStream * stream) +{ + T t; + stream->Read( &t, sizeof(T), 1 ); + return t; +} + +template <> +aiVector3D Read(IOStream * stream) +{ + aiVector3D v; + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); + return v; +} + +template <> +aiColor4D Read(IOStream * stream) +{ + aiColor4D c; + c.r = Read(stream); + c.g = Read(stream); + c.b = Read(stream); + c.a = Read(stream); + return c; +} + +template <> +aiQuaternion Read(IOStream * stream) +{ + aiQuaternion v; + v.w = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); + return v; +} + +template <> +aiString Read(IOStream * stream) +{ + aiString s; + stream->Read(&s.length,4,1); + stream->Read(s.data,s.length,1); + return s; +} + +template <> +aiVertexWeight Read(IOStream * stream) +{ + aiVertexWeight w; + w.mVertexId = Read(stream); + w.mWeight = Read(stream); + return w; +} + +template <> +aiMatrix4x4 Read(IOStream * stream) +{ + aiMatrix4x4 m; + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + m[i][i2] = Read(stream); + } + } + return m; +} + +template <> +aiVectorKey Read(IOStream * stream) +{ + aiVectorKey v; + v.mTime = Read(stream); + v.mValue = Read(stream); + return v; +} + +template <> +aiQuatKey Read(IOStream * stream) +{ + aiQuatKey v; + v.mTime = Read(stream); + v.mValue = Read(stream); + return v; +} + +template +void ReadArray(IOStream * stream, T * out, unsigned int size) +{ + for (unsigned int i=0; i(stream); +} + +template void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) +{ + // not sure what to do here, the data isn't really useful. + stream->Seek( sizeof(T) * n, aiOrigin_CUR ); +} + +void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AINODE); + /*uint32_t size =*/ Read(stream); + + *node = new aiNode(); + + (*node)->mName = Read(stream); + (*node)->mTransformation = Read(stream); + (*node)->mNumChildren = Read(stream); + (*node)->mNumMeshes = Read(stream); + + if ((*node)->mNumMeshes) + { + (*node)->mMeshes = new unsigned int[(*node)->mNumMeshes]; + for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) { + (*node)->mMeshes[i] = Read(stream); + } + } + + if ((*node)->mNumChildren) + { + (*node)->mChildren = new aiNode*[(*node)->mNumChildren]; + for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) { + ReadBinaryNode( stream, &(*node)->mChildren[i] ); + } + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AIBONE ); + /*uint32_t size =*/ Read(stream); + + b->mName = Read(stream); + b->mNumWeights = Read(stream); + b->mOffsetMatrix = Read(stream); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) + { + ReadBounds(stream,b->mWeights,b->mNumWeights); + } // else write as usual + else + { + b->mWeights = new aiVertexWeight[b->mNumWeights]; + ReadArray(stream,b->mWeights,b->mNumWeights); + } +} + + +void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AIMESH); + /*uint32_t size =*/ Read(stream); + + mesh->mPrimitiveTypes = Read(stream); + mesh->mNumVertices = Read(stream); + mesh->mNumFaces = Read(stream); + mesh->mNumBones = Read(stream); + mesh->mMaterialIndex = Read(stream); + + // first of all, write bits for all existent vertex components + unsigned int c = Read(stream); + + if (c & ASSBIN_MESH_HAS_POSITIONS) + { + if (shortened) { + ReadBounds(stream,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mVertices,mesh->mNumVertices); + } + } + if (c & ASSBIN_MESH_HAS_NORMALS) + { + if (shortened) { + ReadBounds(stream,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mNormals,mesh->mNumVertices); + } + } + if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) + { + if (shortened) { + ReadBounds(stream,mesh->mTangents,mesh->mNumVertices); + ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else + { + mesh->mTangents = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mTangents,mesh->mNumVertices); + mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) + { + if (!(c & ASSBIN_MESH_HAS_COLOR(n))) + break; + + if (shortened) + { + ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else + { + mesh->mColors[n] = new aiColor4D[mesh->mNumVertices]; + ReadArray(stream,mesh->mColors[n],mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) + { + if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) + break; + + // write number of UV components + mesh->mNumUVComponents[n] = Read(stream); + + if (shortened) { + ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else + { + mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; + ReadArray(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + } + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + Read(stream); + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + mesh->mFaces = new aiFace[mesh->mNumFaces]; + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + aiFace& f = mesh->mFaces[i]; + + BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff); + f.mNumIndices = Read(stream); + f.mIndices = new unsigned int[f.mNumIndices]; + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) + { + f.mIndices[a] = Read(stream); + } + else + { + f.mIndices[a] = Read(stream); + } + } + } + } + + // write bones + if (mesh->mNumBones) { + mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones]; + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + mesh->mBones[a] = new aiBone(); + ReadBinaryBone(stream,mesh->mBones[a]); + } + } +} + +void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AIMATERIALPROPERTY); + /*uint32_t size =*/ Read(stream); + + prop->mKey = Read(stream); + prop->mSemantic = Read(stream); + prop->mIndex = Read(stream); + + prop->mDataLength = Read(stream); + prop->mType = (aiPropertyTypeInfo)Read(stream); + prop->mData = new char [ prop->mDataLength ]; + stream->Read(prop->mData,1,prop->mDataLength); +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AIMATERIAL); + /*uint32_t size =*/ Read(stream); + + mat->mNumAllocated = mat->mNumProperties = Read(stream); + if (mat->mNumProperties) + { + if (mat->mProperties) + { + delete[] mat->mProperties; + } + mat->mProperties = new aiMaterialProperty*[mat->mNumProperties]; + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + mat->mProperties[i] = new aiMaterialProperty(); + ReadBinaryMaterialProperty( stream, mat->mProperties[i]); + } + } +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AINODEANIM); + /*uint32_t size =*/ Read(stream); + + nd->mNodeName = Read(stream); + nd->mNumPositionKeys = Read(stream); + nd->mNumRotationKeys = Read(stream); + nd->mNumScalingKeys = Read(stream); + nd->mPreState = (aiAnimBehaviour)Read(stream); + nd->mPostState = (aiAnimBehaviour)Read(stream); + + if (nd->mNumPositionKeys) { + if (shortened) { + ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else { + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; + ReadArray(stream,nd->mPositionKeys,nd->mNumPositionKeys); + } + } + if (nd->mNumRotationKeys) { + if (shortened) { + ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else + { + nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; + ReadArray(stream,nd->mRotationKeys,nd->mNumRotationKeys); + } + } + if (nd->mNumScalingKeys) { + if (shortened) { + ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else + { + nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; + ReadArray(stream,nd->mScalingKeys,nd->mNumScalingKeys); + } + } +} + + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AIANIMATION); + /*uint32_t size =*/ Read(stream); + + anim->mName = Read (stream); + anim->mDuration = Read (stream); + anim->mTicksPerSecond = Read (stream); + anim->mNumChannels = Read(stream); + + if (anim->mNumChannels) + { + anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ]; + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + anim->mChannels[a] = new aiNodeAnim(); + ReadBinaryNodeAnim(stream,anim->mChannels[a]); + } + } +} + +void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AITEXTURE); + /*uint32_t size =*/ Read(stream); + + tex->mWidth = Read(stream); + tex->mHeight = Read(stream); + stream->Read( tex->achFormatHint, sizeof(char), 4 ); + + if(!shortened) { + if (!tex->mHeight) { + tex->pcData = new aiTexel[ tex->mWidth ]; + stream->Read(tex->pcData,1,tex->mWidth); + } + else { + tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ]; + stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AILIGHT); + /*uint32_t size =*/ Read(stream); + + l->mName = Read(stream); + l->mType = (aiLightSourceType)Read(stream); + + if (l->mType != aiLightSource_DIRECTIONAL) { + l->mAttenuationConstant = Read(stream); + l->mAttenuationLinear = Read(stream); + l->mAttenuationQuadratic = Read(stream); + } + + l->mColorDiffuse = Read(stream); + l->mColorSpecular = Read(stream); + l->mColorAmbient = Read(stream); + + if (l->mType == aiLightSource_SPOT) { + l->mAngleInnerCone = Read(stream); + l->mAngleOuterCone = Read(stream); + } + +} + +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AICAMERA); + /*uint32_t size =*/ Read(stream); + + cam->mName = Read(stream); + cam->mPosition = Read(stream); + cam->mLookAt = Read(stream); + cam->mUp = Read(stream); + cam->mHorizontalFOV = Read(stream); + cam->mClipPlaneNear = Read(stream); + cam->mClipPlaneFar = Read(stream); + cam->mAspect = Read(stream); +} + +void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) +{ + ai_assert( Read(stream) == ASSBIN_CHUNK_AISCENE); + /*uint32_t size =*/ Read(stream); + + scene->mFlags = Read(stream); + scene->mNumMeshes = Read(stream); + scene->mNumMaterials = Read(stream); + scene->mNumAnimations = Read(stream); + scene->mNumTextures = Read(stream); + scene->mNumLights = Read(stream); + scene->mNumCameras = Read(stream); + + // Read node graph + scene->mRootNode = new aiNode[1]; + ReadBinaryNode( stream, &scene->mRootNode ); + + // Read all meshes + if (scene->mNumMeshes) + { + scene->mMeshes = new aiMesh*[scene->mNumMeshes]; + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + scene->mMeshes[i] = new aiMesh(); + ReadBinaryMesh( stream,scene->mMeshes[i]); + } + } + + // Read materials + if (scene->mNumMaterials) + { + scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + scene->mMaterials[i] = new aiMaterial(); + ReadBinaryMaterial(stream,scene->mMaterials[i]); + } + } + + // Read all animations + if (scene->mNumAnimations) + { + scene->mAnimations = new aiAnimation*[scene->mNumAnimations]; + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + scene->mAnimations[i] = new aiAnimation(); + ReadBinaryAnim(stream,scene->mAnimations[i]); + } + } + + // Read all textures + if (scene->mNumTextures) + { + scene->mTextures = new aiTexture*[scene->mNumTextures]; + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + scene->mTextures[i] = new aiTexture(); + ReadBinaryTexture(stream,scene->mTextures[i]); + } + } + + // Read lights + if (scene->mNumLights) + { + scene->mLights = new aiLight*[scene->mNumLights]; + for (unsigned int i = 0; i < scene->mNumLights;++i) { + scene->mLights[i] = new aiLight(); + ReadBinaryLight(stream,scene->mLights[i]); + } + } + + // Read cameras + if (scene->mNumCameras) + { + scene->mCameras = new aiCamera*[scene->mNumCameras]; + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + scene->mCameras[i] = new aiCamera(); + ReadBinaryCamera(stream,scene->mCameras[i]); + } + } + +} + +void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) +{ + IOStream * stream = pIOHandler->Open(pFile,"rb"); + if (!stream) + return; + + stream->Seek( 44, aiOrigin_CUR ); // signature + + /*unsigned int versionMajor =*/ Read(stream); + /*unsigned int versionMinor =*/ Read(stream); + /*unsigned int versionRevision =*/ Read(stream); + /*unsigned int compileFlags =*/ Read(stream); + + shortened = Read(stream) > 0; + compressed = Read(stream) > 0; + + if (shortened) + throw DeadlyImportError( "Shortened binaries are not supported!" ); + + stream->Seek( 256, aiOrigin_CUR ); // original filename + stream->Seek( 128, aiOrigin_CUR ); // options + stream->Seek( 64, aiOrigin_CUR ); // padding + + if (compressed) + { + uLongf uncompressedSize = Read(stream); + uLongf compressedSize = stream->FileSize() - stream->Tell(); + + unsigned char * compressedData = new unsigned char[ compressedSize ]; + stream->Read( compressedData, 1, compressedSize ); + + unsigned char * uncompressedData = new unsigned char[ uncompressedSize ]; + + uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize ); + + MemoryIOStream io( uncompressedData, uncompressedSize ); + + ReadBinaryScene(&io,pScene); + + delete[] uncompressedData; + delete[] compressedData; + } + else + { + ReadBinaryScene(stream,pScene); + } + + pIOHandler->Close(stream); +} + +#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER diff --git a/code/AssbinLoader.h b/code/AssbinLoader.h new file mode 100644 index 000000000..f4e6e059a --- /dev/null +++ b/code/AssbinLoader.h @@ -0,0 +1,94 @@ + +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @file AssbinLoader.h + * @brief .assbin File format loader + */ +#ifndef AI_ASSBINIMPORTER_H_INC +#define AI_ASSBINIMPORTER_H_INC + +#include "BaseImporter.h" +#include "../include/assimp/types.h" + +#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +namespace Assimp { + +// --------------------------------------------------------------------------------- +/** Importer class for 3D Studio r3 and r4 3DS files + */ +class AssbinImporter : public BaseImporter +{ +private: + bool shortened; + bool compressed; +protected: + +public: + virtual bool CanRead( + const std::string& pFile, + IOSystem* pIOHandler, + bool checkSig + ) const; + virtual const aiImporterDesc* GetInfo() const; + virtual void InternReadFile( + const std::string& pFile, + aiScene* pScene, + IOSystem* pIOHandler + ); + void ReadBinaryScene( IOStream * stream, aiScene* pScene ); + void ReadBinaryNode( IOStream * stream, aiNode** mRootNode ); + void ReadBinaryMesh( IOStream * stream, aiMesh* mesh ); + void ReadBinaryBone( IOStream * stream, aiBone* bone ); + void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat); + void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop); + void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd); + void ReadBinaryAnim( IOStream * stream, aiAnimation* anim ); + void ReadBinaryTexture(IOStream * stream, aiTexture* tex); + void ReadBinaryLight( IOStream * stream, aiLight* l ); + void ReadBinaryCamera( IOStream * stream, aiCamera* cam ); +}; + +} // end of namespace Assimp + +#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER + +#endif // AI_ASSBINIMPORTER_H_INC diff --git a/code/BlenderLoader.cpp b/code/BlenderLoader.cpp index 4bbf5f9f6..562d3729b 100644 --- a/code/BlenderLoader.cpp +++ b/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 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 out(new aiLight()); out->mName = obj->id.name+2; diff --git a/code/BoostWorkaround/boost/tuple/tuple.hpp b/code/BoostWorkaround/boost/tuple/tuple.hpp index a0b46b497..ed5d11861 100644 --- a/code/BoostWorkaround/boost/tuple/tuple.hpp +++ b/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; } @@ -142,7 +142,7 @@ namespace boost { return me.me; } }; - }; + } // A very minimal implementation for up to 5 elements template t; return t; } -}; +} #endif // !! BOOST_TUPLE_INCLUDED diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 0533a05fd..224ae7f57 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -111,6 +111,7 @@ SET( Common_SRCS MemoryIOWrapper.h ParsingUtils.h StreamReader.h + StreamWriter.h StringComparison.h SGSpatialSort.cpp SGSpatialSort.h @@ -143,6 +144,7 @@ SET( Common_SRCS LogAux.h Bitmap.cpp Bitmap.h + XMLTools.h ) SOURCE_GROUP(Common FILES ${Common_SRCS}) @@ -151,6 +153,8 @@ SET( 3DS_SRCS 3DSHelper.h 3DSLoader.cpp 3DSLoader.h + 3DSExporter.h + 3DSExporter.cpp ) SOURCE_GROUP(3DS FILES ${3DS_SRCS}) @@ -168,6 +172,14 @@ SET( ASE_SRCS ) SOURCE_GROUP( ASE FILES ${ASE_SRCS}) +SET( ASSBIN_SRCS + AssbinExporter.h + AssbinExporter.cpp + AssbinLoader.h + AssbinLoader.cpp +) +SOURCE_GROUP( Assbin FILES ${ASSBIN_SRCS}) + SET( B3D_SRCS B3DImporter.cpp B3DImporter.h @@ -612,7 +624,7 @@ SOURCE_GROUP( unzip FILES ${unzip_SRCS}) # VC2010 fixes if(MSVC10) - OPTION( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) + option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) if( VC10_STDINT_FIX ) ADD_DEFINITIONS( -D_STDINT ) endif( VC10_STDINT_FIX ) @@ -643,6 +655,7 @@ SET( assimp_src ${3DS_SRCS} ${AC_SRCS} ${ASE_SRCS} + ${ASSBIN_SRCS} ${B3D_SRCS} ${BVH_SRCS} ${Collada_SRCS} diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index 46ab8f868..338c16aaa 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -115,9 +115,9 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // we assume that the mesh is still in the verbose vertex format where each face has its own set // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to // assert() it here. - //assert( must be verbose, dammit); + // assert( must be verbose, dammit); - if (pMesh->mTangents) // thisimplies that mBitangents is also there + if (pMesh->mTangents) // this implies that mBitangents is also there return false; // If the mesh consists of lines and/or points but not of @@ -271,7 +271,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) const aiVector3D& origNorm = pMesh->mNormals[a]; const aiVector3D& origTang = pMesh->mTangents[a]; const aiVector3D& origBitang = pMesh->mBitangents[a]; - closeVertices.clear(); + closeVertices.resize( 0 ); // find all vertices close to that position vertexFinder->FindPositions( origPos, posEpsilon, verticesFound); diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 963827966..d2e85a015 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Bitmap.h" #include "fast_atof.h" #include "SceneCombiner.h" +#include "XMLTools.h" #include #include @@ -93,6 +94,7 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p } // end of namespace Assimp + // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file) @@ -140,7 +142,7 @@ void ColladaExporter::WriteFile() // useless Collada fu at the end, just in case we haven't had enough indirections, yet. mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mRootNode->mName.C_Str()) + "\" />" << endstr; + mOutput << startstr << "mRootNode->mName.C_Str()) + "\" />" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -236,12 +238,12 @@ void ColladaExporter::WriteHeader() if (!meta || !meta->Get("Author", value)) mOutput << startstr << "" << "Assimp" << "" << endstr; else - mOutput << startstr << "" << value.C_Str() << "" << endstr; + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; if (!meta || !meta->Get("AuthoringTool", value)) mOutput << startstr << "" << "Assimp Exporter" << "" << endstr; else - mOutput << startstr << "" << value.C_Str() << "" << endstr; + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; //mOutput << startstr << "" << mScene->author.C_Str() << "" << endstr; //mOutput << startstr << "" << mScene->authoringTool.C_Str() << "" << endstr; @@ -342,16 +344,20 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin { if( !pSurface.texture.empty() ) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << ""; + + // URL encode image file name first, then XML encode on top + std::stringstream imageUrlEncoded; for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) { if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) - mOutput << *it; + imageUrlEncoded << *it; else - mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; + imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; } + mOutput << XMLEscape(imageUrlEncoded.str()); mOutput << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; @@ -371,7 +377,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std } else { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } PopTag(); mOutput << startstr << "" << endstr; @@ -385,21 +391,21 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture if( !pSurface.texture.empty() ) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << pMatName << "-" << pTypeName << "-image" << endstr; + mOutput << startstr << "" << XMLEscape(pMatName) << "-" << pTypeName << "-image" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << pMatName << "-" << pTypeName << "-surface" << endstr; + mOutput << startstr << "" << XMLEscape(pMatName) << "-" << pTypeName << "-surface" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -439,7 +445,7 @@ void ColladaExporter::WriteMaterials() name = "mat"; materials[a].name = std::string( "m") + boost::lexical_cast (a) + name.C_Str(); for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) { - // isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion + // isalnum on MSVC asserts for code points outside [0,255]. Thus prevent unwanted promotion // of char to signed int and take the unsigned char value. if( !isalnum( static_cast(*it) ) ) { *it = '_'; @@ -510,7 +516,7 @@ void ColladaExporter::WriteMaterials() { const Material& mat = *it; // this is so ridiculous it must be right - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); @@ -561,9 +567,9 @@ void ColladaExporter::WriteMaterials() for( std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it ) { const Material& mat = *it; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; } @@ -591,13 +597,14 @@ void ColladaExporter::WriteGeometryLibrary() void ColladaExporter::WriteGeometry( size_t pIndex) { const aiMesh* mesh = mScene->mMeshes[pIndex]; - std::string idstr = GetMeshId( pIndex); + const std::string idstr = GetMeshId( pIndex); + const std::string idstrEscaped = XMLEscape(idstr); if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) return; // opening tag - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -627,20 +634,20 @@ void ColladaExporter::WriteGeometry( size_t pIndex) } // assemble vertex structure - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; if( mesh->HasNormals() ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { if( mesh->HasTextureCoords( a) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) { if( mesh->HasVertexColors( a) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } PopTag(); @@ -660,7 +667,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; mOutput << startstr << "

"; for( size_t a = 0; a < mesh->mNumFaces; ++a ) { @@ -681,7 +688,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; mOutput << startstr << ""; for( size_t a = 0; a < mesh->mNumFaces; ++a ) @@ -728,11 +735,11 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy std::string arrayId = pIdString + "-array"; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // source array - mOutput << startstr << " "; + mOutput << startstr << " "; PushTag(); if( pType == FloatType_TexCoord2 ) @@ -804,11 +811,11 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy // Writes the scene library void ColladaExporter::WriteSceneLibrary() { - std::string scene_name = mScene->mRootNode->mName.C_Str(); + const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str()); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // start recursive write at the root node @@ -833,7 +840,8 @@ void ColladaExporter::WriteNode(aiNode* pNode) pNode->mName.Set(ss.str()); } - mOutput << startstr << "mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr; + const std::string node_name_escaped = XMLEscape(pNode->mName.data); + mOutput << startstr << "" << endstr; PushTag(); // write transformation - we can directly put the matrix there @@ -854,13 +862,13 @@ void ColladaExporter::WriteNode(aiNode* pNode) if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) continue; - mOutput << startstr << "mMeshes[a]) << "\">" << endstr; + mOutput << startstr << "mMeshes[a])) << "\">" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mMaterialIndex].name << "\" />" << endstr; + mOutput << startstr << "mMaterialIndex].name) << "\" />" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index 3a51daf57..4f5b40840 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -57,12 +57,15 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer MakeLeftHandedProcess::MakeLeftHandedProcess() -{} +: BaseProcess() { + // empty +} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -MakeLeftHandedProcess::~MakeLeftHandedProcess() -{} +MakeLeftHandedProcess::~MakeLeftHandedProcess() { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. @@ -121,8 +124,9 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways... // continue for all children - for( size_t a = 0; a < pNode->mNumChildren; ++a) - ProcessNode( pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation); + for( size_t a = 0; a < pNode->mNumChildren; ++a ) { + ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation ); + } } // ------------------------------------------------------------------------------------------------ @@ -244,6 +248,10 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat) aiMaterial* mat = (aiMaterial*)_mat; for (unsigned int a = 0; a < mat->mNumProperties;++a) { aiMaterialProperty* prop = mat->mProperties[a]; + if( !prop ) { + DefaultLogger::get()->debug( "Property is null" ); + continue; + } // UV transformation key? if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) { @@ -263,11 +271,13 @@ void FlipUVsProcess::ProcessMesh( aiMesh* pMesh) { // mirror texture y coordinate for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { - if( !pMesh->HasTextureCoords( a)) - break; + if( !pMesh->HasTextureCoords( a ) ) { + break; + } - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) - pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y; + for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) { + pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y; + } } } diff --git a/code/DeboneProcess.cpp b/code/DeboneProcess.cpp index 7e72b836e..e22e2fb00 100644 --- a/code/DeboneProcess.cpp +++ b/code/DeboneProcess.cpp @@ -111,8 +111,8 @@ void DeboneProcess::Execute( aiScene* pScene) if(numSplits) { // we need to do something. Let's go. - mSubMeshIndices.clear(); - mSubMeshIndices.resize(pScene->mNumMeshes); + //mSubMeshIndices.clear(); // really needed? + mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway // build a new array of meshes for the scene std::vector meshes; diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 18bf77e4a..22c60ebee 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -78,7 +78,8 @@ void ExportSceneObj(const char*,IOSystem*, const aiScene*); void ExportSceneSTL(const char*,IOSystem*, const aiScene*); void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*); void ExportScenePly(const char*,IOSystem*, const aiScene*); -void ExportScene3DS(const char*, IOSystem*, const aiScene*) {} +void ExportScene3DS(const char*, IOSystem*, const aiScene*); +void ExportSceneAssbin(const char*, IOSystem*, const aiScene*); // ------------------------------------------------------------------------------------------------ // global array of all export formats which Assimp supports in its current build @@ -90,7 +91,7 @@ Exporter::ExportFormatEntry gExporters[] = #ifndef ASSIMP_BUILD_NO_FXILE_EXPORTER Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile, - aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs), + aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs), #endif #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER @@ -113,9 +114,14 @@ Exporter::ExportFormatEntry gExporters[] = ), #endif -//#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER -// ExportFormatEntry( "3ds", "Autodesk 3DS (legacy format)", "3ds" , &ExportScene3DS), -//#endif +#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER + Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS, + aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices), +#endif + +#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER + Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0), +#endif }; #define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) diff --git a/code/FBXAnimation.cpp b/code/FBXAnimation.cpp index ccf1d82f4..3bf60acd4 100644 --- a/code/FBXAnimation.cpp +++ b/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/code/FBXConverter.cpp b/code/FBXConverter.cpp index 075a4903c..03d359875 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -1319,7 +1319,7 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertCluster(std::vector& bones, const Model& model, const Cluster& cl, + void ConvertCluster(std::vector& bones, const Model& /*model*/, const Cluster& cl, std::vector& out_indices, std::vector& index_out_indices, std::vector& count_out_indices, @@ -2347,7 +2347,7 @@ private: // ------------------------------------------------------------------------------------------------ aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, - const Model& target, + const Model& /*target*/, const std::vector& curves, const LayerMap& layer_map, double& max_time, @@ -2378,7 +2378,7 @@ private: // ------------------------------------------------------------------------------------------------ aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, - const Model& target, + const Model& /*target*/, const std::vector& curves, const LayerMap& layer_map, double& max_time, @@ -2830,7 +2830,7 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertScaleKeys(aiNodeAnim* na, const std::vector& nodes, const LayerMap& layers, + void ConvertScaleKeys(aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, double& maxTime, double& minTime) { @@ -2851,7 +2851,7 @@ private: // ------------------------------------------------------------------------------------------------ void ConvertTranslationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& layers, + const LayerMap& /*layers*/, double& maxTime, double& minTime) { @@ -2869,7 +2869,7 @@ private: // ------------------------------------------------------------------------------------------------ void ConvertRotationKeys(aiNodeAnim* na, const std::vector& nodes, - const LayerMap& layers, + const LayerMap& /*layers*/, double& maxTime, double& minTime, Model::RotOrder order) diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index 404a8d6e2..fc27c8874 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -253,8 +253,8 @@ Document::Document(const Parser& parser, const ImportSettings& settings) : settings(settings) , parser(parser) { - // cannot use array default initialization syntax because vc8 fails on it - for (unsigned int i = 0; i < 7; ++i) { + // Cannot use array default initialization syntax because vc8 fails on it + for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) { creationTimeStamp[i] = 0; } @@ -263,7 +263,7 @@ Document::Document(const Parser& parser, const ImportSettings& settings) ReadGlobalSettings(); - // this order is important, connections need parsed objects to check + // This order is important, connections need parsed objects to check // whether connections are ok or not. Objects may not be evaluated yet, // though, since this may require valid connections. ReadObjects(); @@ -277,13 +277,18 @@ Document::~Document() BOOST_FOREACH(ObjectMap::value_type& v, objects) { delete v.second; } + + BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) { + delete v.second; + } + // |dest_connections| contain the same Connection objects as the |src_connections| } // ------------------------------------------------------------------------------------------------ void Document::ReadHeader() { - // read ID objects from "Objects" section + // Read ID objects from "Objects" section const Scope& sc = parser.GetRootScope(); const Element* const ehead = sc["FBXHeaderExtension"]; if(!ehead || !ehead->Compound()) { @@ -293,7 +298,7 @@ void Document::ReadHeader() const Scope& shead = *ehead->Compound(); fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0)); - // while we maye have some success with newer files, we don't support + // While we maye have some success with newer files, we don't support // the older 6.n fbx format if(fbxVersion < 7100) { DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013"); diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 9dd5c79dd..8cf8202a1 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -696,7 +696,7 @@ public: public: /** Get the Skin attached to this geometry or NULL */ - const Skin* const DeformerSkin() const { + const Skin* DeformerSkin() const { return skin; } @@ -1096,7 +1096,7 @@ public: return transformLink; } - const Model* const TargetNode() const { + const Model* TargetNode() const { return node; } diff --git a/code/FBXImporter.cpp b/code/FBXImporter.cpp index 56e99063b..dfbe5dbd0 100644 --- a/code/FBXImporter.cpp +++ b/code/FBXImporter.cpp @@ -179,6 +179,8 @@ void FBXImporter::InternReadFile( const std::string& pFile, // convert the FBX DOM to aiScene ConvertToAssimpScene(pScene,doc); + + std::for_each(tokens.begin(),tokens.end(),Util::delete_fun()); } catch(std::exception&) { std::for_each(tokens.begin(),tokens.end(),Util::delete_fun()); diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index a5e2a1169..fffa14fd3 100644 --- a/code/FBXMaterial.cpp +++ b/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/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index be3fbd621..ebc75f48e 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -466,8 +466,9 @@ void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const std::string& MappingInformationType, const std::string& ReferenceInformationType) { + const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, - "Tangent", + str, "TangentIndex", vertices.size(), mapping_counts, @@ -481,8 +482,9 @@ void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_ou const std::string& MappingInformationType, const std::string& ReferenceInformationType) { + const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal"; ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, - "Binormal", + str, "BinormalIndex", vertices.size(), mapping_counts, diff --git a/code/FBXParser.cpp b/code/FBXParser.cpp index f6dc2e7e2..24b12ccbf 100644 --- a/code/FBXParser.cpp +++ b/code/FBXParser.cpp @@ -93,7 +93,7 @@ namespace { } // ------------------------------------------------------------------------------------------------ - void ParseWarning(const std::string& message, const Element* element = NULL) +/* void ParseWarning(const std::string& message, const Element* element = NULL) { if(element) { ParseWarning(message,element->KeyToken()); @@ -103,7 +103,7 @@ namespace { DefaultLogger::get()->warn("FBX-Parser: " + message); } } - +*/ // ------------------------------------------------------------------------------------------------ void ParseError(const std::string& message, TokenPtr token) { @@ -113,6 +113,18 @@ namespace { ParseError(message); } + // 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 + template + T SafeParse(const char* data, const char* end) { + // Actual size validation happens during Tokenization so + // this is valid as an assertion. + ai_assert(static_cast(end - data) >= sizeof(T)); + T result = static_cast(0); + ::memcpy(&result, data, sizeof(T)); + return result; + } } namespace Assimp { @@ -275,9 +287,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) return 0L; } - ai_assert(t.end() - data == 9); - - BE_NCONST uint64_t id = *reinterpret_cast(data+1); + BE_NCONST uint64_t id = SafeParse(data+1, t.end()); AI_SWAP8(id); return id; } @@ -316,8 +326,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out) return 0; } - ai_assert(t.end() - data == 9); - BE_NCONST uint64_t id = *reinterpret_cast(data+1); + BE_NCONST uint64_t id = SafeParse(data+1, t.end()); AI_SWAP8(id); return static_cast(id); } @@ -364,24 +373,10 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out) } if (data[0] == 'F') { - // 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; + return SafeParse(data+1, t.end()); } else { - ai_assert(t.end() - data == sizeof(double) + 1); - - // Same - double out_double; - ::memcpy(&out_double, data+1, sizeof(double)); - return static_cast(out_double); + return SafeParse(data+1, t.end()); } } @@ -416,8 +411,7 @@ int ParseTokenAsInt(const Token& t, const char*& err_out) return 0; } - ai_assert(t.end() - data == 5); - BE_NCONST int32_t ival = *reinterpret_cast(data+1); + BE_NCONST int32_t ival = SafeParse(data+1, t.end()); AI_SWAP4(ival); return static_cast(ival); } @@ -453,10 +447,8 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out) return ""; } - ai_assert(t.end() - data >= 5); - // read string length - BE_NCONST int32_t len = *reinterpret_cast(data+1); + BE_NCONST int32_t len = SafeParse(data+1, t.end()); AI_SWAP4(len); ai_assert(t.end() - data == 5 + len); @@ -494,7 +486,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin type = *data; // read number of elements - BE_NCONST uint32_t len = *reinterpret_cast(data+1); + BE_NCONST uint32_t len = SafeParse(data+1, end); AI_SWAP4(len); count = len; @@ -506,16 +498,14 @@ 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& buff, - const Element& el) + const Element& /*el*/) { - ai_assert(static_cast(end-data) >= 4); // runtime check for this happens at tokenization stage - - BE_NCONST uint32_t encmode = *reinterpret_cast(data); + BE_NCONST uint32_t encmode = SafeParse(data, end); AI_SWAP4(encmode); data += 4; // next comes the compressed length - BE_NCONST uint32_t comp_len = *reinterpret_cast(data); + BE_NCONST uint32_t comp_len = SafeParse(data, end); AI_SWAP4(comp_len); data += 4; diff --git a/code/FBXProperties.cpp b/code/FBXProperties.cpp index 48bdb4f40..62cbba51d 100644 --- a/code/FBXProperties.cpp +++ b/code/FBXProperties.cpp @@ -105,7 +105,7 @@ Property* ReadTypedProperty(const Element& element) ParseTokenAsFloat(*tok[6])) ); } - else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"KTime") || !strcmp(cs,"Float")) { + else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"KTime") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) { return new TypedProperty(ParseTokenAsFloat(*tok[4])); } return NULL; diff --git a/code/FBXProperties.h b/code/FBXProperties.h index 9219c3eea..bcbdc8a30 100644 --- a/code/FBXProperties.h +++ b/code/FBXProperties.h @@ -143,8 +143,7 @@ private: // ------------------------------------------------------------------------------------------------ template inline T PropertyGet(const PropertyTable& in, const std::string& name, - const T& defaultValue, - bool ignoreTemplate = false) + const T& defaultValue) { const Property* const prop = in.Get(name); if(!prop) { @@ -164,8 +163,7 @@ inline T PropertyGet(const PropertyTable& in, const std::string& name, // ------------------------------------------------------------------------------------------------ template inline T PropertyGet(const PropertyTable& in, const std::string& name, - bool& result, - bool ignoreTemplate = false) + bool& result) { const Property* const prop = in.Get(name); if(!prop) { diff --git a/code/FindInstancesProcess.cpp b/code/FindInstancesProcess.cpp index faf0541af..278f01115 100644 --- a/code/FindInstancesProcess.cpp +++ b/code/FindInstancesProcess.cpp @@ -174,7 +174,6 @@ void FindInstancesProcess::Execute( aiScene* pScene) // use a constant epsilon for colors and UV coordinates static const float uvEpsilon = 10e-4f; - { unsigned int i, end = orig->GetNumUVChannels(); for(i = 0; i < end; ++i) { @@ -260,7 +259,7 @@ void FindInstancesProcess::Execute( aiScene* pScene) pScene->mMeshes[real++] = pScene->mMeshes[i]; } - // And update the nodegraph with our nice lookup table + // And update the node graph with our nice lookup table UpdateMeshIndices(pScene->mRootNode,remapping.get()); // write to log diff --git a/code/GenVertexNormalsProcess.cpp b/code/GenVertexNormalsProcess.cpp index b278afb87..77ef20ac5 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/GenVertexNormalsProcess.cpp @@ -93,7 +93,7 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene) bool bHas = false; for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if(GenMeshVertexNormals( pScene->mMeshes[a],a)) + if(GenMeshVertexNormals( pScene->mMeshes[a],a)) bHas = true; } diff --git a/code/GenVertexNormalsProcess.h b/code/GenVertexNormalsProcess.h index 9b103892c..e77e71e59 100644 --- a/code/GenVertexNormalsProcess.h +++ b/code/GenVertexNormalsProcess.h @@ -53,7 +53,7 @@ namespace Assimp { // --------------------------------------------------------------------------- /** The GenFaceNormalsProcess computes vertex normals for all vertizes */ -class ASSIMP_API_WINONLY GenVertexNormalsProcess : public BaseProcess +class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { public: diff --git a/code/IFCBoolean.cpp b/code/IFCBoolean.cpp index 8573e4d62..7d3840710 100644 --- a/code/IFCBoolean.cpp +++ b/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/code/IFCOpenings.cpp b/code/IFCOpenings.cpp index c26574cc3..0af90eb5b 100644 --- a/code/IFCOpenings.cpp +++ b/code/IFCOpenings.cpp @@ -259,7 +259,7 @@ BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly) // ------------------------------------------------------------------------------------------------ void InsertWindowContours(const ContourVector& contours, - const std::vector& openings, + const std::vector& /*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& openings,const std: #undef from_int64 #undef one_vec -#endif \ No newline at end of file +#endif diff --git a/code/IFCProfile.cpp b/code/IFCProfile.cpp index 5119338c1..84f5c3194 100644 --- a/code/IFCProfile.cpp +++ b/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()) { const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f; diff --git a/code/IFCReaderGen.cpp b/code/IFCReaderGen.cpp index 2e7d357ca..00ff4aa35 100644 --- a/code/IFCReaderGen.cpp +++ b/code/IFCReaderGen.cpp @@ -1045,7 +1045,7 @@ void IFC::GetSchema(EXPRESS::ConversionSchema& out) namespace STEP { // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill(const STEP::DB& db, const LIST& params, NotImplemented* in) +template <> size_t GenericFill(const STEP::DB& /*db*/, const LIST& /*params*/, NotImplemented* /*in*/) { return 0; } @@ -1253,7 +1253,7 @@ template <> size_t GenericFill(const DB& db, const LIST& return base; } // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill(const DB& db, const LIST& params, IfcRepresentationItem* in) +template <> size_t GenericFill(const DB& /*db*/, const LIST& /*params*/, IfcRepresentationItem* /*in*/) { size_t base = 0; return base; @@ -1715,7 +1715,7 @@ template <> size_t GenericFill(const DB& db, const LIST& params, I return base; } // ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill(const DB& db, const LIST& params, IfcObjectPlacement* in) +template <> size_t GenericFill(const DB& /*db*/, const LIST& /*params*/, IfcObjectPlacement* /*in*/) { size_t base = 0; return base; diff --git a/code/Importer.cpp b/code/Importer.cpp index c6b9daf67..a9173cddc 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -640,16 +640,25 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } + // Get file size for progress handler + IOStream * fileIO = pimpl->mIOHandler->Open( pFile ); + uint32_t fileSize = 0; + if (fileIO) + { + fileSize = fileIO->FileSize(); + pimpl->mIOHandler->Close( fileIO ); + } + // Dispatch the reading to the worker class for this format DefaultLogger::get()->info("Found a matching importer for this file format"); - pimpl->mProgressHandler->Update(); + pimpl->mProgressHandler->UpdateFileRead( 0, fileSize ); if (profiler) { profiler->BeginRegion("import"); } pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler); - pimpl->mProgressHandler->Update(); + pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize ); if (profiler) { profiler->EndRegion("import"); @@ -678,7 +687,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) ScenePreprocessor pre(pimpl->mScene); pre.ProcessScene(); - pimpl->mProgressHandler->Update(); if (profiler) { profiler->EndRegion("preprocess"); } @@ -768,6 +776,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* process = pimpl->mPostProcessingSteps[a]; + pimpl->mProgressHandler->UpdatePostProcess( a, pimpl->mPostProcessingSteps.size() ); if( process->IsActive( pFlags)) { if (profiler) { @@ -775,7 +784,6 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) } process->ExecuteOnScene ( this ); - pimpl->mProgressHandler->Update(); if (profiler) { profiler->EndRegion("postprocess"); @@ -803,6 +811,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) } #endif // ! DEBUG } + pimpl->mProgressHandler->UpdatePostProcess( pimpl->mPostProcessingSteps.size(), pimpl->mPostProcessingSteps.size() ); // update private scene flags if( pimpl->mScene ) diff --git a/code/ImporterRegistry.cpp b/code/ImporterRegistry.cpp index e301804e2..dff195854 100644 --- a/code/ImporterRegistry.cpp +++ b/code/ImporterRegistry.cpp @@ -166,6 +166,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER # include "FBXImporter.h" #endif +#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER +# include "AssbinLoader.h" +#endif namespace Assimp { @@ -291,6 +294,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER ) out.push_back( new FBXImporter() ); #endif +#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER ) + out.push_back( new AssbinImporter() ); +#endif } } diff --git a/code/JoinVerticesProcess.h b/code/JoinVerticesProcess.h index a004b2528..0195c0168 100644 --- a/code/JoinVerticesProcess.h +++ b/code/JoinVerticesProcess.h @@ -59,7 +59,7 @@ class JoinVerticesTest; * erases all but one of the copies. This usually reduces the number of vertices * in a mesh by a serious amount and is the standard form to render a mesh. */ -class ASSIMP_API_WINONLY JoinVerticesProcess : public BaseProcess +class ASSIMP_API JoinVerticesProcess : public BaseProcess { public: diff --git a/code/LimitBoneWeightsProcess.cpp b/code/LimitBoneWeightsProcess.cpp index 91ac122ac..f7a83a970 100644 --- a/code/LimitBoneWeightsProcess.cpp +++ b/code/LimitBoneWeightsProcess.cpp @@ -131,10 +131,15 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) // and renormalize the weights float sum = 0.0f; - for( std::vector::const_iterator it = vit->begin(); it != vit->end(); ++it) - sum += it->mWeight; - for( std::vector::iterator it = vit->begin(); it != vit->end(); ++it) - it->mWeight /= sum; + for( std::vector::const_iterator it = vit->begin(); it != vit->end(); ++it ) { + sum += it->mWeight; + } + if( 0.0f != sum ) { + const float invSum = 1.0f / sum; + for( std::vector::iterator it = vit->begin(); it != vit->end(); ++it ) { + it->mWeight *= invSum; + } + } } if (bChanged) { @@ -157,18 +162,6 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) const std::vector& bw = boneWeights[a]; aiBone* bone = pMesh->mBones[a]; - // ignore the bone if no vertex weights were removed there - - // FIX (Aramis, 07|22|08) - // NO! we can't ignore it in this case ... it is possible that - // the number of weights did not change, but the weight values did. - - // if( bw.size() == bone->mNumWeights) - // continue; - - // FIX (Aramis, 07|21|08) - // It is possible that all weights of a bone have been removed. - // This would naturally cause an exception in &bw[0]. if ( bw.empty() ) { abNoNeed[a] = bChanged = true; @@ -177,7 +170,7 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) // copy the weight list. should always be less weights than before, so we don't need a new allocation ai_assert( bw.size() <= bone->mNumWeights); - bone->mNumWeights = (unsigned int) bw.size(); + bone->mNumWeights = static_cast( bw.size() ); ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight)); } diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index 282983965..7ebb55b3e 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -75,6 +75,7 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene } // end of namespace Assimp +static const std::string MaterialExt = ".mtl"; // ------------------------------------------------------------------------------------------------ ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene) @@ -107,7 +108,7 @@ std::string ObjExporter :: GetMaterialLibName() // ------------------------------------------------------------------------------------------------ std::string ObjExporter :: GetMaterialLibFileName() { - return filename + ".mtl"; + return filename + MaterialExt; } // ------------------------------------------------------------------------------------------------ @@ -132,7 +133,7 @@ std::string ObjExporter :: GetMaterialName(unsigned int index) } // ------------------------------------------------------------------------------------------------ -void ObjExporter :: WriteMaterialFile() +void ObjExporter::WriteMaterialFile() { WriteHeader(mOutputMat); @@ -144,16 +145,16 @@ void ObjExporter :: WriteMaterialFile() aiColor4D c; if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) { - mOutputMat << "kd " << c.r << " " << c.g << " " << c.b << endl; + mOutputMat << "Kd " << c.r << " " << c.g << " " << c.b << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) { - mOutputMat << "ka " << c.r << " " << c.g << " " << c.b << endl; + mOutputMat << "Ka " << c.r << " " << c.g << " " << c.b << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) { - mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl; + mOutputMat << "Ks " << c.r << " " << c.g << " " << c.b << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) { - mOutputMat << "ke " << c.r << " " << c.g << " " << c.b << endl; + mOutputMat << "Ke " << c.r << " " << c.g << " " << c.b << endl; } float o; @@ -170,16 +171,19 @@ void ObjExporter :: WriteMaterialFile() aiString s; if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) { - mOutputMat << "map_kd " << s.data << endl; + mOutputMat << "map_Kd " << s.data << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) { - mOutputMat << "map_ka " << s.data << endl; + mOutputMat << "map_Ka " << s.data << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) { - mOutputMat << "map_ks " << s.data << endl; + mOutputMat << "map_Ks " << s.data << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) { - mOutputMat << "map_ns " << s.data << endl; + mOutputMat << "map_Ns " << s.data << endl; + } + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_OPACITY(0),s)) { + mOutputMat << "map_d " << s.data << endl; } if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) { // implementations seem to vary here, so write both variants @@ -281,7 +285,7 @@ void ObjExporter::vecIndexMap::getVectors( std::vector& vecs ) } // ------------------------------------------------------------------------------------------------ -void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) +void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { meshes.push_back(MeshInstance()); MeshInstance& mesh = meshes.back(); @@ -332,7 +336,7 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri } // ------------------------------------------------------------------------------------------------ -void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent) +void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) { const aiMatrix4x4& mAbs = mParent * nd->mTransformation; @@ -345,5 +349,7 @@ void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent) } } -#endif -#endif +// ------------------------------------------------------------------------------------------------ + +#endif // ASSIMP_BUILD_NO_OBJ_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index 8424995c0..e494fa515 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -54,6 +54,7 @@ static const std::string DiffuseTexture = "map_kd"; static const std::string AmbientTexture = "map_ka"; static const std::string SpecularTexture = "map_ks"; static const std::string OpacityTexture = "map_d"; +static const std::string EmmissiveTexture = "map_emissive"; static const std::string BumpTexture1 = "map_bump"; static const std::string BumpTexture2 = "map_Bump"; static const std::string BumpTexture3 = "bump"; @@ -128,6 +129,7 @@ void ObjFileMtlImporter::load() { switch (*m_DataIt) { + case 'k': case 'K': { ++m_DataIt; @@ -221,15 +223,17 @@ void ObjFileMtlImporter::getColorRGBA( aiColor3D *pColor ) { ai_assert( NULL != pColor ); - float r, g, b; + float r( 0.0f ), g( 0.0f ), b( 0.0f ); m_DataIt = getFloat( m_DataIt, m_DataItEnd, r ); pColor->r = r; - m_DataIt = getFloat( m_DataIt, m_DataItEnd, g ); - pColor->g = g; - - m_DataIt = getFloat( m_DataIt, m_DataItEnd, b ); - pColor->b = b; + // we have to check if color is default 0 with only one token + if( !isNewLine( *m_DataIt ) ) { + m_DataIt = getFloat( m_DataIt, m_DataItEnd, g ); + m_DataIt = getFloat( m_DataIt, m_DataItEnd, b ); + } + pColor->g = g; + pColor->b = b; } // ------------------------------------------------------------------- @@ -303,11 +307,7 @@ void ObjFileMtlImporter::getTexture() { // Opacity texture out = & m_pModel->m_pCurrentMaterial->textureOpacity; clampIndex = ObjFile::Material::TextureOpacityType; - } else if (!ASSIMP_strincmp( pPtr,"map_ka",6)) { - // Ambient texture - out = & m_pModel->m_pCurrentMaterial->textureAmbient; - clampIndex = ObjFile::Material::TextureAmbientType; - } else if (!ASSIMP_strincmp(&(*m_DataIt),"map_emissive",6)) { + } else if (!ASSIMP_strincmp( pPtr, EmmissiveTexture.c_str(), EmmissiveTexture.size())) { // Emissive texture out = & m_pModel->m_pCurrentMaterial->textureEmissive; clampIndex = ObjFile::Material::TextureEmissiveType; diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 5b8305723..6e73f0bf4 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -113,8 +113,8 @@ void ObjFileParser::parseFile() getVector3(m_pModel->m_Vertices); } else if (*m_DataIt == 't') { // read in texture coordinate ( 2D or 3D ) - ++m_DataIt; - getVector( m_pModel->m_TextureCoord ); + ++m_DataIt; + getVector( m_pModel->m_TextureCoord ); } else if (*m_DataIt == 'n') { // Read in normal vector definition ++m_DataIt; @@ -233,12 +233,13 @@ void ObjFileParser::copyNextLine(char *pBuffer, size_t length) // ------------------------------------------------------------------- void ObjFileParser::getVector( std::vector &point3d_array ) { size_t numComponents( 0 ); - DataArrayIt tmp( m_DataIt ); + const char* tmp( &m_DataIt[0] ); while( !IsLineEnd( *tmp ) ) { - if( *tmp == ' ' ) { - ++numComponents; + if ( !SkipSpaces( &tmp ) ) { + break; } - tmp++; + SkipToken( tmp ); + ++numComponents; } float x, y, z; if( 2 == numComponents ) { @@ -550,13 +551,15 @@ void ObjFileParser::getNewMaterial() { m_DataIt = getNextToken(m_DataIt, m_DataItEnd); m_DataIt = getNextWord(m_DataIt, m_DataItEnd); - if ( m_DataIt == m_DataItEnd ) - return; + if( m_DataIt == m_DataItEnd ) { + return; + } char *pStart = &(*m_DataIt); std::string strMat( pStart, *m_DataIt ); - while ( m_DataIt != m_DataItEnd && isSeparator( *m_DataIt ) ) - m_DataIt++; + while( m_DataIt != m_DataItEnd && isSeparator( *m_DataIt ) ) { + ++m_DataIt; + } std::map::iterator it = m_pModel->m_MaterialMap.find( strMat ); if ( it == m_pModel->m_MaterialMap.end() ) { @@ -581,8 +584,9 @@ void ObjFileParser::getNewMaterial() int ObjFileParser::getMaterialIndex( const std::string &strMaterialName ) { int mat_index = -1; - if ( strMaterialName.empty() ) - return mat_index; + if( strMaterialName.empty() ) { + return mat_index; + } for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index) { if ( strMaterialName == m_pModel->m_MaterialLib[ index ]) @@ -601,8 +605,9 @@ void ObjFileParser::getGroupName() std::string strGroupName; m_DataIt = getName(m_DataIt, m_DataItEnd, strGroupName); - if ( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) - return; + if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) { + return; + } // Change active group, if necessary if ( m_pModel->m_strActiveGroup != strGroupName ) @@ -653,11 +658,13 @@ void ObjFileParser::getGroupNumberAndResolution() void ObjFileParser::getObjectName() { m_DataIt = getNextToken(m_DataIt, m_DataItEnd); - if (m_DataIt == m_DataItEnd) - return; + if( m_DataIt == m_DataItEnd ) { + return; + } char *pStart = &(*m_DataIt); - while ( m_DataIt != m_DataItEnd && !isSeparator( *m_DataIt ) ) - ++m_DataIt; + while( m_DataIt != m_DataItEnd && !isSeparator( *m_DataIt ) ) { + ++m_DataIt; + } std::string strObjectName(pStart, &(*m_DataIt)); if (!strObjectName.empty()) @@ -678,8 +685,9 @@ void ObjFileParser::getObjectName() } // Allocate a new object, if current one was not found before - if ( NULL == m_pModel->m_pCurrent ) - createObject(strObjectName); + if( NULL == m_pModel->m_pCurrent ) { + createObject( strObjectName ); + } } m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } @@ -694,7 +702,6 @@ void ObjFileParser::createObject(const std::string &strObjectName) m_pModel->m_pCurrent->m_strObjName = strObjectName; m_pModel->m_Objects.push_back( m_pModel->m_pCurrent ); - createMesh(); if( m_pModel->m_pCurrentMaterial ) diff --git a/code/ObjTools.h b/code/ObjTools.h index 530588368..047c9a4cd 100644 --- a/code/ObjTools.h +++ b/code/ObjTools.h @@ -259,4 +259,4 @@ unsigned int tokenize( const string_type& str, std::vector& tokens, } // Namespace Assimp -#endif +#endif // OBJ_TOOLS_H_INC diff --git a/code/OgreBinarySerializer.cpp b/code/OgreBinarySerializer.cpp index 6674f4cee..2908ca056 100644 --- a/code/OgreBinarySerializer.cpp +++ b/code/OgreBinarySerializer.cpp @@ -376,14 +376,14 @@ void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh) mesh->skeletonRef = ReadLine(); } -void OgreBinarySerializer::ReadMeshBounds(Mesh *mesh) +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) +void OgreBinarySerializer::ReadMeshExtremes(Mesh * /*mesh*/) { // Skip extremes, not compatible with Assimp. size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE; @@ -534,7 +534,6 @@ void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *submesh) void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) { uint16_t id = 0; - uint16_t submeshIndex = 0; if (!AtEnd()) { @@ -644,7 +643,7 @@ void OgreBinarySerializer::ReadGeometryVertexBuffer(VertexData *dest) DefaultLogger::get()->debug(Formatter::format() << " - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes"); } -void OgreBinarySerializer::ReadEdgeList(Mesh *mesh) +void OgreBinarySerializer::ReadEdgeList(Mesh * /*mesh*/) { // Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped. @@ -1055,7 +1054,7 @@ void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) DefaultLogger::get()->debug(Formatter::format() << " " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)"); } -void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest) +void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, Animation *dest) { uint16_t boneId = Read(); Bone *bone = dest->parentSkeleton->BoneById(boneId); @@ -1097,7 +1096,7 @@ void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *d dest->transformKeyFrames.push_back(keyframe); } -void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton *skeleton) +void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton * /*skeleton*/) { // Skip bounds, not compatible with Assimp. ReadLine(); // skeleton name diff --git a/code/OgreBinarySerializer.h b/code/OgreBinarySerializer.h index 69db4b722..1080b226a 100644 --- a/code/OgreBinarySerializer.h +++ b/code/OgreBinarySerializer.h @@ -75,8 +75,8 @@ private: }; OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) : - m_reader(reader), m_currentLen(0), + m_reader(reader), assetMode(mode) { } @@ -301,11 +301,12 @@ enum MeshChunkId // unsigned short poseIndex // float influence // Optional submesh extreme vertex list chink - M_TABLE_EXTREMES = 0xE000, + M_TABLE_EXTREMES = 0xE000 // unsigned short submesh_index; // float extremes [n_extremes][3]; }; +/* static std::string MeshHeaderToString(MeshChunkId id) { switch(id) @@ -347,6 +348,7 @@ static std::string MeshHeaderToString(MeshChunkId id) } return "Unknown_MeshChunkId"; } +*/ enum SkeletonChunkId { @@ -393,6 +395,7 @@ enum SkeletonChunkId // float scale : scale to apply to trans/scale keys }; +/* static std::string SkeletonHeaderToString(SkeletonChunkId id) { switch(id) @@ -409,6 +412,7 @@ static std::string SkeletonHeaderToString(SkeletonChunkId id) } return "Unknown_SkeletonChunkId"; } +*/ } // Ogre } // Assimp diff --git a/code/OgreStructs.cpp b/code/OgreStructs.cpp index 3eaf2df01..2009214cc 100644 --- a/code/OgreStructs.cpp +++ b/code/OgreStructs.cpp @@ -404,9 +404,9 @@ size_t IndexData::FaceSize() const // Mesh Mesh::Mesh() : - sharedVertexData(0), - skeleton(0), - hasSkeletalAnimations(false) + hasSkeletalAnimations(false), + skeleton(NULL), + sharedVertexData(NULL) { } @@ -712,8 +712,8 @@ aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) // MeshXml MeshXml::MeshXml() : - sharedVertexData(0), - skeleton(0) + skeleton(0), + sharedVertexData(0) { } @@ -797,8 +797,8 @@ void MeshXml::ConvertToAssimpScene(aiScene* dest) // SubMeshXml SubMeshXml::SubMeshXml() : - vertexData(0), - indexData(new IndexDataXml()) + indexData(new IndexDataXml()), + vertexData(0) { } @@ -912,8 +912,8 @@ aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent) // Animation Animation::Animation(Skeleton *parent) : + parentMesh(NULL), parentSkeleton(parent), - parentMesh(0), length(0.0f), baseTime(-1.0f) { @@ -963,6 +963,8 @@ aiAnimation *Animation::ConvertToAssimpAnimation() // Skeleton Skeleton::Skeleton() : + bones(), + animations(), blendMode(ANIMBLEND_AVERAGE) { } @@ -1103,7 +1105,7 @@ aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) return node; } -aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector &boneWeights) +aiBone *Bone::ConvertToAssimpBone(Skeleton * /*parent*/, const std::vector &boneWeights) { aiBone *bone = new aiBone(); bone->mName = name; @@ -1122,8 +1124,8 @@ aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector @@ -63,118 +66,145 @@ AI_FORCE_INLINE char_t ToLower( char_t in) { return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in; } + // --------------------------------------------------------------------------------- template -AI_FORCE_INLINE char_t ToUpper( char_t in) -{ - return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in; +AI_FORCE_INLINE char_t ToUpper( char_t in) { + return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in; } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsUpper( char_t in) { return (in >= (char_t)'A' && in <= (char_t)'Z'); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsLower( char_t in) { return (in >= (char_t)'a' && in <= (char_t)'z'); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsSpace( char_t in) { return (in == (char_t)' ' || in == (char_t)'\t'); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsLineEnd( char_t in) { return (in == (char_t)'\r' || in == (char_t)'\n' || in == (char_t)'\0'); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsSpaceOrNewLine( char_t in) { return IsSpace(in) || IsLineEnd(in); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipSpaces( const char_t* in, const char_t** out) { - while (*in == (char_t)' ' || *in == (char_t)'\t')in++; + while( *in == ( char_t )' ' || *in == ( char_t )'\t' ) { + ++in; + } *out = in; return !IsLineEnd(*in); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipSpaces( const char_t** inout) { return SkipSpaces(*inout,inout); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out) { - while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0')in++; + while( *in != ( char_t )'\r' && *in != ( char_t )'\n' && *in != ( char_t )'\0' ) { + ++in; + } // files are opened in binary mode. Ergo there are both NL and CR - while (*in == (char_t)'\r' || *in == (char_t)'\n')in++; + while( *in == ( char_t )'\r' || *in == ( char_t )'\n' ) { + ++in; + } *out = in; return *in != (char_t)'\0'; } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipLine( const char_t** inout) { return SkipLine(*inout,inout); } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out) { - while (*in == (char_t)' ' || *in == (char_t)'\t' || - *in == (char_t)'\r' || *in == (char_t)'\n')in++; + while( *in == ( char_t )' ' || *in == ( char_t )'\t' || *in == ( char_t )'\r' || *in == ( char_t )'\n' ) { + ++in; + } *out = in; return *in != '\0'; } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t** inout) { return SkipSpacesAndLineEnd(*inout,inout); } + // --------------------------------------------------------------------------------- template -AI_FORCE_INLINE bool GetNextLine(const char_t*& buffer, char_t out[4096]) +AI_FORCE_INLINE bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) { - if ((char_t)'\0' == *buffer)return false; + if( ( char_t )'\0' == *buffer ) { + return false; + } char* _out = out; - char* const end = _out+4096; - while (!IsLineEnd( *buffer ) && _out < end) - *_out++ = *buffer++; + char* const end = _out + BufferSize; + while( !IsLineEnd( *buffer ) && _out < end ) { + *_out++ = *buffer++; + } *_out = (char_t)'\0'; - while (IsLineEnd( *buffer ) && '\0' != *buffer)++buffer; - return true; + while( IsLineEnd( *buffer ) && '\0' != *buffer ) { + ++buffer; + } + + return true; } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool IsNumeric( char_t in) { return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in; } + // --------------------------------------------------------------------------------- template AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len) { - if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) - { + if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) { in += len+1; return true; } + return false; } // --------------------------------------------------------------------------------- @@ -185,8 +215,7 @@ AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len */ AI_FORCE_INLINE bool TokenMatchI(const char*& in, const char* token, unsigned int len) { - if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) - { + if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) { in += len+1; return true; } @@ -206,5 +235,9 @@ AI_FORCE_INLINE std::string GetNextToken(const char*& in) while (!IsSpaceOrNewLine(*in))++in; return std::string(cur,(size_t)(in-cur)); } + +// --------------------------------------------------------------------------------- + } // ! namespace Assimp + #endif // ! AI_PARSING_UTILS_H_INC diff --git a/code/Q3BSPFileImporter.cpp b/code/Q3BSPFileImporter.cpp index ecb28e06e..b662be299 100644 --- a/code/Q3BSPFileImporter.cpp +++ b/code/Q3BSPFileImporter.cpp @@ -73,11 +73,13 @@ static const aiImporterDesc desc = { namespace Assimp { +/* static void getSupportedExtensions(std::vector &supportedExtensions) { supportedExtensions.push_back( ".jpg" ); supportedExtensions.push_back( ".png" ); supportedExtensions.push_back( ".tga" ); } +*/ using namespace Q3BSP; diff --git a/code/Q3BSPZipArchive.cpp b/code/Q3BSPZipArchive.cpp index 947b7ca7b..e683e63f8 100644 --- a/code/Q3BSPZipArchive.cpp +++ b/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/code/STLLoader.cpp b/code/STLLoader.cpp index ebd320c1a..068008d9e 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -348,8 +348,8 @@ bool STLImporter::LoadBinaryFile() bool bIsMaterialise = false; // search for an occurence of "COLOR=" in the header - const char* sz2 = (const char*)mBuffer; - const char* const szEnd = sz2+80; + const unsigned char* sz2 = (const unsigned char*)mBuffer; + const unsigned char* const szEnd = sz2+80; while (sz2 < szEnd) { if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ && diff --git a/code/StreamWriter.h b/code/StreamWriter.h new file mode 100644 index 000000000..afa8d2489 --- /dev/null +++ b/code/StreamWriter.h @@ -0,0 +1,235 @@ +/* +--------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- +*/ + +/** @file Defines the StreamWriter class which writes data to + * a binary stream with a well-defined endianess. */ + +#ifndef AI_STREAMWRITER_H_INCLUDED +#define AI_STREAMWRITER_H_INCLUDED + +#include "ByteSwap.h" + +namespace Assimp { + +// -------------------------------------------------------------------------------------------- +/** Wrapper class around IOStream to allow for consistent writing of binary data in both + * little and big endian format. Don't attempt to instance the template directly. Use + * StreamWriterLE to read from a little-endian stream and StreamWriterBE to read from a + * BE stream. Alternatively, there is StreamWriterAny if the endianess of the output + * stream is to be determined at runtime. + */ +// -------------------------------------------------------------------------------------------- +template +class StreamWriter +{ + enum { + INITIAL_CAPACITY = 1024 + }; + +public: + + // --------------------------------------------------------------------- + /** Construction from a given stream with a well-defined endianess. + * + * The StreamReader holds a permanent strong reference to the + * stream, which is released upon destruction. + * @param stream Input stream. The stream is not re-seeked and writing + continues at the current position of the stream cursor. + * @param le If @c RuntimeSwitch is true: specifies whether the + * stream is in little endian byte order. Otherwise the + * endianess information is defined by the @c SwapEndianess + * template parameter and this parameter is meaningless. */ + StreamWriter(boost::shared_ptr stream, bool le = false) + : stream(stream) + , le(le) + , cursor() + { + ai_assert(stream); + buffer.reserve(INITIAL_CAPACITY); + } + + // --------------------------------------------------------------------- + StreamWriter(IOStream* stream, bool le = false) + : stream(boost::shared_ptr(stream)) + , le(le) + , cursor() + { + ai_assert(stream); + buffer.reserve(INITIAL_CAPACITY); + } + + // --------------------------------------------------------------------- + ~StreamWriter() { + stream->Write(&buffer[0], 1, buffer.size()); + stream->Flush(); + } + +public: + + // --------------------------------------------------------------------- + /** Write a float to the stream */ + void PutF4(float f) + { + Put(f); + } + + // --------------------------------------------------------------------- + /** Write a double to the stream */ + void PutF8(double d) { + Put(d); + } + + // --------------------------------------------------------------------- + /** Write a signed 16 bit integer to the stream */ + void PutI2(int16_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write a signed 8 bit integer to the stream */ + void PutI1(int8_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write an signed 32 bit integer to the stream */ + void PutI4(int32_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write a signed 64 bit integer to the stream */ + void PutI8(int64_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write a unsigned 16 bit integer to the stream */ + void PutU2(uint16_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write a unsigned 8 bit integer to the stream */ + void PutU1(uint8_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write an unsigned 32 bit integer to the stream */ + void PutU4(uint32_t n) { + Put(n); + } + + // --------------------------------------------------------------------- + /** Write a unsigned 64 bit integer to the stream */ + void PutU8(uint64_t n) { + Put(n); + } + +public: + + // --------------------------------------------------------------------- + /** overload operator<< and allow chaining of MM ops. */ + template + StreamWriter& operator << (T f) { + Put(f); + return *this; + } + + // --------------------------------------------------------------------- + std::size_t GetCurrentPos() const { + return cursor; + } + + // --------------------------------------------------------------------- + void SetCurrentPos(std::size_t new_cursor) { + cursor = new_cursor; + } + +private: + + // --------------------------------------------------------------------- + /** Generic write method. ByteSwap::Swap(T*) *must* be defined */ + template + void Put(T f) { + Intern :: Getter() (&f, le); + + if (cursor + sizeof(T) >= buffer.size()) { + buffer.resize(cursor + sizeof(T)); + } + + void* dest = &buffer[cursor]; + + // reinterpret_cast + assignment breaks strict aliasing rules + // and generally causes trouble on platforms such as ARM that + // do not silently ignore alignment faults. + ::memcpy(dest, &f, sizeof(T)); + cursor += sizeof(T); + } + +private: + + boost::shared_ptr stream; + bool le; + + std::vector buffer; + std::size_t cursor; +}; + + +// -------------------------------------------------------------------------------------------- +// `static` StreamWriter. Their byte order is fixed and they might be a little bit faster. +#ifdef AI_BUILD_BIG_ENDIAN + typedef StreamWriter StreamWriterLE; + typedef StreamWriter StreamWriterBE; +#else + typedef StreamWriter StreamWriterBE; + typedef StreamWriter StreamWriterLE; +#endif + +// `dynamic` StreamWriter. The byte order of the input data is specified in the +// c'tor. This involves runtime branching and might be a little bit slower. +typedef StreamWriter StreamWriterAny; + +} // end namespace Assimp + +#endif // !! AI_STREAMWriter_H_INCLUDED diff --git a/code/XMLTools.h b/code/XMLTools.h new file mode 100644 index 000000000..103f1d815 --- /dev/null +++ b/code/XMLTools.h @@ -0,0 +1,81 @@ +/* +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 INCLUDED_ASSIMP_XML_TOOLS_H +#define INCLUDED_ASSIMP_XML_TOOLS_H + +#include + +namespace Assimp { + // XML escape the 5 XML special characters (",',<,> and &) in |data| + // Based on http://stackoverflow.com/questions/5665231 + std::string XMLEscape(const std::string& data) { + std::string buffer; + + const size_t size = data.size(); + buffer.reserve(size + size / 8); + for(size_t i = 0; i < size; ++i) { + const char c = data[i]; + switch(c) { + case '&' : + buffer.append("&"); + break; + case '\"': + buffer.append("""); + break; + case '\'': + buffer.append("'"); + break; + case '<' : + buffer.append("<"); + break; + case '>' : + buffer.append(">"); + break; + default: + buffer.append(&c, 1); + break; + } + } + return buffer; + } +} + +#endif // INCLUDED_ASSIMP_XML_TOOLS_H diff --git a/code/fast_atof.h b/code/fast_atof.h index b7aca3837..c4a41fca3 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -16,7 +16,9 @@ #define __FAST_A_TO_F_H_INCLUDED__ #include -#include +#include + +#include "StringComparison.h" namespace Assimp { @@ -229,15 +231,45 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* template inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) { - Real f; + Real f = 0; - bool inv = (*c=='-'); - if (inv || *c=='+') { + bool inv = (*c == '-'); + if (inv || *c == '+') { ++c; } - f = static_cast( strtoul10_64 ( c, &c) ); - if (*c == '.' || (check_comma && c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too + if ((c[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0) + { + out = std::numeric_limits::quiet_NaN(); + c += 3; + return c; + } + + if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0) + { + out = std::numeric_limits::infinity(); + c += 3; + if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inity", 5) == 0) + { + c += 5; + } + return c; + } + + if (!(c[0] >= '0' && c[0] <= '9') && + !(c[0] == '.' && c[1] >= '0' && c[1] <= '9')) + { + throw std::invalid_argument("Cannot parse string " + "as real number: does not start with digit " + "or decimal point followed by digit."); + } + + if (*c != '.') + { + f = static_cast( strtoul10_64 ( c, &c) ); + } + + if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') { ++c; @@ -255,6 +287,10 @@ inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma pl *= fast_atof_table[diff]; f += static_cast( pl ); } + // For backwards compatibility: eat trailing dots, but not trailing commas. + else if (*c == '.') { + ++c; + } // A major 'E' must be allowed. Necessary for proper reading of some DXF files. // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..) diff --git a/contrib/clipper/clipper.cpp b/contrib/clipper/clipper.cpp index b9754e4eb..1efa01df8 100644 --- a/contrib/clipper/clipper.cpp +++ b/contrib/clipper/clipper.cpp @@ -2124,11 +2124,13 @@ 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 + } outRec->sides = (EdgeSide)(outRec->sides | e->side); if (outRec->sides == esBoth) diff --git a/contrib/unzip/unzip.c b/contrib/unzip/unzip.c index f62b45ec8..e83862a43 100644 --- a/contrib/unzip/unzip.c +++ b/contrib/unzip/unzip.c @@ -1246,7 +1246,7 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len) return UNZ_PARAMERROR; - if ((pfile_in_zip_read_info->read_buffer == NULL)) + if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index 31c746c59..3ab1e489b 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -81,13 +81,39 @@ public: * all needed cleanup tasks prior to returning control to the * caller). If the loading is aborted, #Importer::ReadFile() * returns always NULL. - * - * @note Currently, percentage is always -1.f because there is - * no reliable way to compute it. * */ virtual bool Update(float percentage = -1.f) = 0; + // ------------------------------------------------------------------- + /** @brief Progress callback for file loading steps + * @param numberOfSteps The number of total post-processing + * steps + * @param currentStep The index of the current post-processing + * step that will run, or equal to numberOfSteps if all of + * them has finished. This number is always strictly monotone + * increasing, although not necessarily linearly. + * + * @note This is currently only used at the start and the end + * of the file parsing. + * */ + virtual void UpdateFileRead(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { + float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; + Update( f * 0.5f ); + }; + // ------------------------------------------------------------------- + /** @brief Progress callback for post-processing steps + * @param numberOfSteps The number of total post-processing + * steps + * @param currentStep The index of the current post-processing + * step that will run, or equal to numberOfSteps if all of + * them has finished. This number is always strictly monotone + * increasing, although not necessarily linearly. + * */ + virtual void UpdatePostProcess(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { + float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; + Update( f * 0.5f + 0.5f ); + }; }; // !class ProgressHandler // ------------------------------------------------------------------------------------ diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index a1e29b23b..32b0013ae 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -72,7 +72,7 @@ enum aiImporterFlags * should be used with care. This only happens for trunk * (i.e. SVN) versions, experimental code is not included * in releases. */ - aiImporterFlags_Experimental = 0x10, + aiImporterFlags_Experimental = 0x10 }; diff --git a/samples/SimpleOpenGL/CMakeLists.txt b/samples/SimpleOpenGL/CMakeLists.txt index 49e5fc212..dea335ee1 100644 --- a/samples/SimpleOpenGL/CMakeLists.txt +++ b/samples/SimpleOpenGL/CMakeLists.txt @@ -1,5 +1,6 @@ FIND_PACKAGE(OpenGL) FIND_PACKAGE(GLUT) +find_library(M_LIB m) IF ( NOT GLUT_FOUND ) IF ( MSVC ) @@ -29,7 +30,7 @@ ADD_EXECUTABLE( assimp_simpleogl SET_PROPERTY(TARGET assimp_simpleogl PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX}) -TARGET_LINK_LIBRARIES( assimp_simpleogl assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ) +TARGET_LINK_LIBRARIES( assimp_simpleogl assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${M_LIB} ) SET_TARGET_PROPERTIES( assimp_simpleogl PROPERTIES OUTPUT_NAME assimp_simpleogl ) diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c index 921046a44..18cb43959 100644 --- a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -1,4 +1,4 @@ -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- // Simple sample to prove that Assimp is easy to use with OpenGL. // It takes a file name as command line parameter, loads it using standard // settings and displays it. @@ -9,29 +9,30 @@ // The vc8 solution links against assimp-release-dll_win32 - be sure to // have this configuration built. // ---------------------------------------------------------------------------- +*/ #include #include #include -// assimp include files. These three are usually needed. +/* assimp include files. These three are usually needed. */ #include #include #include -// the global Assimp scene object +/* the global Assimp scene object */ const struct aiScene* scene = NULL; GLuint scene_list = 0; struct aiVector3D scene_min, scene_max, scene_center; -// current rotation angle +/* current rotation angle */ static float angle = 0.f; #define aisgl_min(x,y) (xx?y:x) -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void reshape(int width, int height) { const double aspectRatio = (float) width / height, fieldOfView = 45.0; @@ -43,7 +44,7 @@ void reshape(int width, int height) glViewport(0, 0, width, height); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void get_bounding_box_for_node (const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, @@ -78,7 +79,7 @@ void get_bounding_box_for_node (const struct aiNode* nd, *trafo = prev; } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) { struct aiMatrix4x4 trafo; @@ -89,7 +90,7 @@ void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) get_bounding_box_for_node(scene->mRootNode,min,max,&trafo); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void color4_to_float4(const struct aiColor4D *c, float f[4]) { f[0] = c->r; @@ -98,7 +99,7 @@ void color4_to_float4(const struct aiColor4D *c, float f[4]) f[3] = c->a; } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void set_float4(float f[4], float a, float b, float c, float d) { f[0] = a; @@ -107,7 +108,7 @@ void set_float4(float f[4], float a, float b, float c, float d) f[3] = d; } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void apply_material(const struct aiMaterial *mtl) { float c[4]; @@ -173,19 +174,19 @@ void apply_material(const struct aiMaterial *mtl) glEnable(GL_CULL_FACE); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) { unsigned int i; unsigned int n = 0, t; struct aiMatrix4x4 m = nd->mTransformation; - // update transform + /* update transform */ aiTransposeMatrix4(&m); glPushMatrix(); glMultMatrixf((float*)&m); - // draw all meshes assigned to this node + /* draw all meshes assigned to this node */ for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; @@ -224,7 +225,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) } - // draw all children + /* draw all children */ for (n = 0; n < nd->mNumChildren; ++n) { recursive_render(sc, nd->mChildren[n]); } @@ -232,7 +233,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) glPopMatrix(); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void do_motion (void) { static GLint prev_time = 0; @@ -244,7 +245,7 @@ void do_motion (void) prev_time = time; frames += 1; - if ((time - prev_fps_time) > 1000) // update every seconds + if ((time - prev_fps_time) > 1000) /* update every seconds */ { int current_fps = frames * 1000 / (time - prev_fps_time); printf("%d fps\n", current_fps); @@ -256,7 +257,7 @@ void do_motion (void) glutPostRedisplay (); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ void display(void) { float tmp; @@ -267,27 +268,27 @@ void display(void) glLoadIdentity(); gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f); - // rotate it around the y axis + /* rotate it around the y axis */ glRotatef(angle,0.f,1.f,0.f); - // scale the whole asset to fit into our view frustum + /* scale the whole asset to fit into our view frustum */ tmp = scene_max.x-scene_min.x; tmp = aisgl_max(scene_max.y - scene_min.y,tmp); tmp = aisgl_max(scene_max.z - scene_min.z,tmp); tmp = 1.f / tmp; glScalef(tmp, tmp, tmp); - // center the model + /* center the model */ glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z ); - // if the display list has not been made yet, create a new one and - // fill it with scene contents + /* if the display list has not been made yet, create a new one and + fill it with scene contents */ if(scene_list == 0) { scene_list = glGenLists(1); glNewList(scene_list, GL_COMPILE); - // now begin at the root node of the imported data and traverse - // the scenegraph by multiplying subsequent local transforms - // together on GL's matrix stack. + /* now begin at the root node of the imported data and traverse + the scenegraph by multiplying subsequent local transforms + together on GL's matrix stack. */ recursive_render(scene, scene->mRootNode); glEndList(); } @@ -299,11 +300,11 @@ void display(void) do_motion(); } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ int loadasset (const char* path) { - // we are taking one of the postprocessing presets to avoid - // spelling out 20+ single postprocessing flags here. + /* we are taking one of the postprocessing presets to avoid + spelling out 20+ single postprocessing flags here. */ scene = aiImportFile(path,aiProcessPreset_TargetRealtime_MaxQuality); if (scene) { @@ -316,7 +317,7 @@ int loadasset (const char* path) return 1; } -// ---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ int main(int argc, char **argv) { struct aiLogStream stream; @@ -330,21 +331,21 @@ int main(int argc, char **argv) glutDisplayFunc(display); glutReshapeFunc(reshape); - // get a handle to the predefined STDOUT log stream and attach - // it to the logging system. It remains active for all further - // calls to aiImportFile(Ex) and aiApplyPostProcessing. + /* get a handle to the predefined STDOUT log stream and attach + it to the logging system. It remains active for all further + calls to aiImportFile(Ex) and aiApplyPostProcessing. */ stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); aiAttachLogStream(&stream); - // ... same procedure, but this stream now writes the - // log messages to assimp_log.txt + /* ... same procedure, but this stream now writes the + log messages to assimp_log.txt */ stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt"); aiAttachLogStream(&stream); - // the model name can be specified on the command line. If none - // is specified, we try to locate one of the more expressive test - // models from the repository (/models-nonbsd may be missing in - // some distributions so we need a fallback from /models!). + /* the model name can be specified on the command line. If none + is specified, we try to locate one of the more expressive test + models from the repository (/models-nonbsd may be missing in + some distributions so we need a fallback from /models!). */ if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models-nonbsd/X/dwarf.x")) { if( argc != 1 || (0 != loadasset( "../../../../test/models-nonbsd/X/dwarf.x") && 0 != loadasset( "../../test/models/X/Testwuson.X"))) { return -1; @@ -354,14 +355,14 @@ int main(int argc, char **argv) glClearColor(0.1f,0.1f,0.1f,1.f); glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); // Uses default lighting parameters + glEnable(GL_LIGHT0); /* Uses default lighting parameters */ glEnable(GL_DEPTH_TEST); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glEnable(GL_NORMALIZE); - // XXX docs say all polygons are emitted CCW, but tests show that some aren't. + /* XXX docs say all polygons are emitted CCW, but tests show that some aren't. */ if(getenv("MODEL_IS_BROKEN")) glFrontFace(GL_CW); @@ -370,14 +371,15 @@ int main(int argc, char **argv) glutGet(GLUT_ELAPSED_TIME); glutMainLoop(); - // cleanup - calling 'aiReleaseImport' is important, as the library - // keeps internal resources until the scene is freed again. Not - // doing so can cause severe resource leaking. + /* cleanup - calling 'aiReleaseImport' is important, as the library + keeps internal resources until the scene is freed again. Not + doing so can cause severe resource leaking. */ aiReleaseImport(scene); - // We added a log stream to the library, it's our job to disable it - // again. This will definitely release the last resources allocated - // by Assimp. + /* We added a log stream to the library, it's our job to disable it + again. This will definitely release the last resources allocated + by Assimp.*/ aiDetachAllLogStreams(); return 0; } + diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index 253387509..2787fad52 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -12,9 +12,6 @@ // Thanks to NeHe on whose OpenGL tutorials this one's based on! :) // http://nehe.gamedev.net/ // ---------------------------------------------------------------------------- - - - #include #include #include @@ -36,7 +33,7 @@ #include "assimp/LogStream.hpp" -// The default hardcoded path. Can be overridden by supplying a path through the commandline. +// The default hard-coded path. Can be overridden by supplying a path through the command line. static std::string modelpath = "../../test/models/OBJ/spider.obj"; @@ -47,7 +44,7 @@ HINSTANCE hInstance; // Holds The Instance Of The Application bool keys[256]; // Array used for Keyboard Routine; bool active=TRUE; // Window Active Flag Set To TRUE by Default -bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen By Default +bool fullscreen=TRUE; // full-screen Flag Set To full-screen By Default GLfloat xrot; GLfloat yrot; @@ -80,6 +77,7 @@ Assimp::Importer importer; void createAILogger() { + // Change this line to normal if you not want to analyse the import process //Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL; Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE; @@ -101,20 +99,20 @@ void destroyAILogger() void logInfo(std::string logString) { - //Will add message to File with "info" Tag + // Will add message to File with "info" Tag Assimp::DefaultLogger::get()->info(logString.c_str()); } void logDebug(const char* logString) { - //Will add message to File with "debug" Tag + // Will add message to File with "debug" Tag Assimp::DefaultLogger::get()->debug(logString); } bool Import3DFromFile( const std::string& pFile) { - //check if file exists + // Check if file exists std::ifstream fin(pFile.c_str()); if(!fin.fail()) { @@ -143,12 +141,14 @@ bool Import3DFromFile( const std::string& pFile) return true; } - -void ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window +// Resize And Initialize The GL Window +void ReSizeGLScene(GLsizei width, GLsizei height) { - if (height==0) // Prevent A Divide By Zero By + // Prevent A Divide By Zero By + if (height==0) { - height=1; // Making Height Equal One + // Making Height Equal One + height=1; } glViewport(0, 0, width, height); // Reset The Current Viewport @@ -217,9 +217,6 @@ int LoadGLTextures(const aiScene* scene) textureIds = new GLuint[numTextures]; glGenTextures(numTextures, textureIds); /* Texture name generation */ - /* define texture path */ - //std::string texturepath = "../../../test/models/Obj/"; - /* get iterator */ std::map::iterator itr = textureIdMap.begin(); @@ -239,48 +236,50 @@ int LoadGLTextures(const aiScene* scene) if (success) /* If no error occured: */ { - success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); /* Convert every colour component into - unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA */ + // Convert every colour component into unsigned byte.If your image contains + // alpha channel you can replace IL_RGB with IL_RGBA + success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); if (!success) { /* Error occured */ abortGLInit("Couldn't convert image"); return -1; } - //glGenTextures(numTextures, &textureIds[i]); /* Texture name generation */ - glBindTexture(GL_TEXTURE_2D, textureIds[i]); /* Binding of texture name */ - //redefine standard texture values - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* We will use linear - interpolation for magnification filter */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* We will use linear - interpolation for minifying filter */ - glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), + // Binding of texture name + glBindTexture(GL_TEXTURE_2D, textureIds[i]); + // redefine standard texture values + // We will use linear interpolation for magnification filter + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + // We will use linear interpolation for minifying filter + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + // Texture specification + glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, - ilGetData()); /* Texture specification */ + ilGetData()); + // we also want to be able to deal with odd texture dimensions + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); } else { /* Error occured */ MessageBox(NULL, ("Couldn't load Image: " + fileloc).c_str() , "ERROR", MB_OK | MB_ICONEXCLAMATION); } - - } + // Because we have already copied image data into texture data we can release memory used by image. + ilDeleteImages(numTextures, imageIds); - ilDeleteImages(numTextures, imageIds); /* Because we have already copied image data into texture data - we can release memory used by image. */ - - //Cleanup + // Cleanup delete [] imageIds; imageIds = NULL; - //return success; return TRUE; } - - -int InitGL() // All Setup For OpenGL goes here +// All Setup For OpenGL goes here +int InitGL() { if (!LoadGLTextures(scene)) { @@ -307,9 +306,6 @@ int InitGL() // All Setup For OpenGL goes here glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); glEnable(GL_LIGHT1); - //glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - - return TRUE; // Initialization Went OK } @@ -449,8 +445,6 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd, float glDisable(GL_COLOR_MATERIAL); } - - for (t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; GLenum face_mode; @@ -480,14 +474,10 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd, float glNormal3fv(&mesh->mNormals[vertexIndex].x); glVertex3fv(&mesh->mVertices[vertexIndex].x); } - glEnd(); - } - } - // draw all children for (n = 0; n < nd->mNumChildren; ++n) { @@ -521,12 +511,11 @@ int DrawGLScene() //Here's where we do all the drawing drawAiScene(scene); - //xrot+=0.3f; yrot+=0.2f; //zrot+=0.4f; - return TRUE; // Ewwrissing okay + return TRUE; // okay } @@ -667,11 +656,6 @@ BOOL CreateGLWindow(const char* title, int width, int height, int bits, bool ful { abortGLInit("Window Creation Error."); return FALSE; - /* - KillGLWindow(); // Reset The Display - MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return FALSE; // Return False - */ } static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be @@ -767,8 +751,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window { switch (wParam) { - case SC_SCREENSAVE: // Screensaver trying to start - case SC_MONITORPOWER: // Monitor tryig to enter powersafe + case SC_SCREENSAVE: // Screen-saver trying to start + case SC_MONITORPOWER: // Monitor trying to enter power-safe return 0; } break; @@ -799,12 +783,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window } } - // Pass All Unhandled Messaged To DefWindowProc + // Pass All unhandled Messaged To DefWindowProc return DefWindowProc(hWnd, uMsg, wParam, lParam); } -int WINAPI WinMain( HINSTANCE hInstance, // Instance - HINSTANCE hPrevInstance, // Previous Instance +int WINAPI WinMain( HINSTANCE hInstance, // The instance + HINSTANCE hPrevInstance, // Previous instance LPSTR lpCmdLine, // Command Line Parameters int nShowCmd ) // Window Show State { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 87c36a893..92b618558 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,7 +15,8 @@ SOURCE_GROUP( unit FILES unit/BoostWorkaround/tupletest.cpp ) -SOURCE_GROUP( cppunit FILES +if(WIN32) +SET( CPPUNIT_SRCS ../contrib/cppunit-1.12.1/src/cppunit/AdditionalMessage.cpp ../contrib/cppunit-1.12.1/src/cppunit/Asserter.cpp ../contrib/cppunit-1.12.1/src/cppunit/BeOsDynamicLibraryManager.cpp @@ -70,59 +71,12 @@ SOURCE_GROUP( cppunit FILES ../contrib/cppunit-1.12.1/src/cppunit/XmlOutputter.cpp ../contrib/cppunit-1.12.1/src/cppunit/XmlOutputterHook.cpp ) +SOURCE_GROUP(cppunit FILES ${CPPUNIT_SRCS}) +else() + find_library(CPPUNIT_LIBRARY cppunit) +endif() -SOURCE_GROUP( tests FILES - unit/Main.cpp - unit/UnitTestPCH.cpp - unit/UnitTestPCH.h - unit/utFindDegenerates.cpp - unit/utFindDegenerates.h - unit/utFindInvalidData.cpp - unit/utFindInvalidData.h - unit/utFixInfacingNormals.cpp - unit/utGenNormals.cpp - unit/utGenNormals.h - unit/utImporter.cpp - unit/utImporter.h - unit/utImproveCacheLocality.cpp - unit/utJoinVertices.cpp - unit/utJoinVertices.h - unit/utLimitBoneWeights.cpp - unit/utLimitBoneWeights.h - unit/utMaterialSystem.cpp - unit/utMaterialSystem.h - unit/utPretransformVertices.cpp - unit/utPretransformVertices.h - unit/utRemoveComments.cpp - unit/utRemoveComments.h - unit/utRemoveComponent.cpp - unit/utRemoveComponent.h - unit/utRemoveRedundantMaterials.cpp - unit/utRemoveRedundantMaterials.h - unit/utScenePreprocessor.cpp - unit/utScenePreprocessor.h - unit/utSharedPPData.cpp - unit/utSharedPPData.h - unit/utSortByPType.cpp - unit/utSortByPType.h - unit/utSplitLargeMeshes.cpp - unit/utSplitLargeMeshes.h - unit/utTargetAnimation.cpp - unit/utTargetAnimation.h - unit/utTextureTransform.cpp - unit/utTriangulate.cpp - unit/utTriangulate.h - unit/utVertexTriangleAdjacency.cpp - unit/utVertexTriangleAdjacency.h - unit/utNoBoostTest.cpp - unit/utNoBoostTest.h -) - -add_executable( unit - unit/CCompilerTest.c - unit/Main.cpp - unit/UnitTestPCH.cpp - unit/UnitTestPCH.h +SET( TEST_SRCS unit/utFindDegenerates.cpp unit/utFindDegenerates.h unit/utFindInvalidData.cpp @@ -165,65 +119,20 @@ add_executable( unit unit/utNoBoostTest.cpp unit/utNoBoostTest.h unit/BoostWorkaround/tupletest.cpp - ../contrib/cppunit-1.12.1/src/cppunit/AdditionalMessage.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Asserter.cpp - ../contrib/cppunit-1.12.1/src/cppunit/BeOsDynamicLibraryManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/BriefTestProgressListener.cpp - ../contrib/cppunit-1.12.1/src/cppunit/CompilerOutputter.cpp - ../contrib/cppunit-1.12.1/src/cppunit/DefaultProtector.cpp - ../contrib/cppunit-1.12.1/src/cppunit/DefaultProtector.h - ../contrib/cppunit-1.12.1/src/cppunit/DllMain.cpp - ../contrib/cppunit-1.12.1/src/cppunit/DynamicLibraryManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/DynamicLibraryManagerException.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Exception.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Message.cpp - ../contrib/cppunit-1.12.1/src/cppunit/PlugInManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/PlugInParameters.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Protector.cpp - ../contrib/cppunit-1.12.1/src/cppunit/ProtectorChain.cpp - ../contrib/cppunit-1.12.1/src/cppunit/ProtectorChain.h - ../contrib/cppunit-1.12.1/src/cppunit/ProtectorContext.h - ../contrib/cppunit-1.12.1/src/cppunit/RepeatedTest.cpp - ../contrib/cppunit-1.12.1/src/cppunit/ShlDynamicLibraryManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/SourceLine.cpp - ../contrib/cppunit-1.12.1/src/cppunit/StringTools.cpp - ../contrib/cppunit-1.12.1/src/cppunit/SynchronizedObject.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Test.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestAssert.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestCase.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestCaseDecorator.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestComposite.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestDecorator.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestFactoryRegistry.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestFailure.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestLeaf.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestNamer.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestPath.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestPlugInDefaultImpl.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestResult.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestResultCollector.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestRunner.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestSetUp.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestSuccessListener.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestSuite.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TestSuiteBuilderContext.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TextOutputter.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TextTestProgressListener.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TextTestResult.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TextTestRunner.cpp - ../contrib/cppunit-1.12.1/src/cppunit/TypeInfoHelper.cpp - ../contrib/cppunit-1.12.1/src/cppunit/UnixDynamicLibraryManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/Win32DynamicLibraryManager.cpp - ../contrib/cppunit-1.12.1/src/cppunit/XmlDocument.cpp - ../contrib/cppunit-1.12.1/src/cppunit/XmlElement.cpp - ../contrib/cppunit-1.12.1/src/cppunit/XmlOutputter.cpp - ../contrib/cppunit-1.12.1/src/cppunit/XmlOutputterHook.cpp ) -IF( WIN32 ) - FIND_PACKAGE(DirectX REQUIRED) -ENDIF( WIN32 ) +SOURCE_GROUP(tests FILES ${TEST_SRCS}) + + +add_executable( unit + unit/CCompilerTest.c + unit/Main.cpp + unit/UnitTestPCH.cpp + unit/UnitTestPCH.h + ${TEST_SRCS} + ${CPPUNIT_SRCS} +) + SET_PROPERTY(TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX}) -# TODO: Port to non-Windows platforms. -target_link_libraries ( unit assimp ${DirectX_LIBRARY} ${DirectX_D3DX9_LIBRARY} comctl32.lib Winmm.lib ) +target_link_libraries ( unit assimp ${CPPUNIT_LIBRARY} ) diff --git a/test/models/Collada/cube_xmlspecialchars.dae b/test/models/Collada/cube_xmlspecialchars.dae new file mode 100644 index 000000000..94e1bed2d --- /dev/null +++ b/test/models/Collada/cube_xmlspecialchars.dae @@ -0,0 +1,210 @@ + + + + + alorino + Maya 7.0 | ColladaMaya v2.01 Jun 9 2006 at 16:08:19 | FCollada v1.11 + Collada Maya Export Options: bakeTransforms=0;exportPolygonMeshes=1;bakeLighting=0;isSampling=0; +curveConstrainSampling=0;exportCameraAsLookat=0; +exportLights=1;exportCameras=1;exportJointsAndSkin=1; +exportAnimations=1;exportTriangles=0;exportInvisibleNodes=0; +exportNormals=1;exportTexCoords=1;exportVertexColors=1;exportTangents=0; +exportTexTangents=0;exportConstraints=0;exportPhysics=0;exportXRefs=1; +dereferenceXRefs=0;cameraXFov=0;cameraYFov=1 + +Copyright 2006 Sony Computer Entertainment Inc. +Licensed under the SCEA Shared Source License, Version 1.0 (the +"License"); you may not use this file except in compliance with the +License. You may obtain a copy of the License at: +http://research.scea.com/scea_shared_source_license.html +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + + 2006-06-21T21:23:22Z + 2006-06-21T21:23:22Z + + Y_UP + + + + + + + 37.8493 + 1 + 10 + 1000 + + + + + + + + + 37.8501 + 1 + 0.01 + 1000 + + + + + + + + + + 1 1 1 + 1 + 0 + 0 + + + + 1.000000 + + + + + + 1 1 1 + 1 + 0 + 0 + + + + + + + + + + + + + + + + 0 0 0 1 + + + 0 0 0 1 + + + 0.137255 0.403922 0.870588 1 + + + 0.5 0.5 0.5 1 + + + 16 + + + 0 0 0 1 + + + 0.5 + + + 0 0 0 1 + + + 1 + + + 0 + + + + + + + + + + + -50 50 50 50 50 50 -50 -50 50 50 -50 50 -50 50 -50 50 50 -50 -50 -50 -50 50 -50 -50 + + + + + + + + + + 0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1 + + + + + + + + + + + + + + + 4 4 4 4 4 4 +

0 0 2 1 3 2 1 3 0 4 1 5 5 6 4 7 6 8 7 9 3 10 2 11 0 12 4 13 6 14 2 15 3 16 7 17 5 18 1 19 5 20 7 21 6 22 4 23

+ +
+
+ + + + + -427.749 333.855 655.017 + 0 1 0 -33 + 1 0 0 -22.1954 + 0 0 1 0 + + + + -500 1000 400 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + + + + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + + + + + + + + + + -427.749 333.855 655.017 + 0 1 0 -33 + 1 0 0 -22.1954 + 0 0 1 0 + + + + 3 4 10 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + + + + + + + + diff --git a/test/models/OBJ/empty_mat.mtl b/test/models/OBJ/empty_mat.mtl index 84db99062..8f52a73b0 100644 --- a/test/models/OBJ/empty_mat.mtl +++ b/test/models/OBJ/empty_mat.mtl @@ -4,7 +4,7 @@ newmtl Ns 0 Ka 0.000000 0.000000 0.000000 Kd 0.8 0.8 0.8 -Ks 0.8 0.8 0.8 +Ks 0 d 1 illum 2 diff --git a/test/models/OBJ/multiple_spaces.obj b/test/models/OBJ/multiple_spaces.obj new file mode 100644 index 000000000..4f27a0342 --- /dev/null +++ b/test/models/OBJ/multiple_spaces.obj @@ -0,0 +1,11 @@ +v 1.0 2.0 3.0 +v 2.0 3.0 1.0 +v 3.0 1.0 2.0 +v 1.0 2.0 3.0 + +vt 1.0 2.0 3.0 +vt 2.0 3.0 1.0 +vt 3.0 1.0 2.0 +vt 1.0 2.0 3.0 + +f 1 2 3 diff --git a/test/models/OBJ/number_formats.obj b/test/models/OBJ/number_formats.obj new file mode 100644 index 000000000..12b21bf44 --- /dev/null +++ b/test/models/OBJ/number_formats.obj @@ -0,0 +1,23 @@ +v 0 0 0 + +v 1 2. 3.0 +v +1 +2. +3.0 +v -1 -2. -3.0 + +v 1e2 2.e1 3.1e2 +v +1e2 +2.e1 +3.1e2 +v -1e2 -2.e1 -3.1e2 + +v 1e+2 2.e+1 3.1+e2 +v +1e+2 +2.e+1 +3.1+e2 +v -1e+2 -2.e+1 -3.1+e2 + +v 1e-2 2.e-1 3.1-e2 +v +1e-2 +2.e-1 +3.1-e2 +v -1e-2 -2.e-1 -3.1-e2 + +v 1e10 2.e01 3.1e10 + +v 1E2 2.E1 3.1E2 + +f 1 2 4 diff --git a/test/unit/CCompilerTest.c b/test/unit/CCompilerTest.c index b27376350..6020e265b 100644 --- a/test/unit/CCompilerTest.c +++ b/test/unit/CCompilerTest.c @@ -1,5 +1,5 @@ -// This is just a small test to check whether Assimp's API compiles from C +/* This is just a small test to check whether Assimp's API compiles from C */ #include #include diff --git a/test/unit/Main.cpp b/test/unit/Main.cpp index 5c7bb60fb..33840a3c0 100644 --- a/test/unit/Main.cpp +++ b/test/unit/Main.cpp @@ -26,9 +26,8 @@ int main (int argc, char* argv[]) // .. and C. They should smoothly work together aiEnableVerboseLogging(AI_TRUE); - aiAttachLogStream(&aiGetPredefinedLogStream( - aiDefaultLogStream_FILE, - "AssimpLog_C.txt")); + aiLogStream logstream= aiGetPredefinedLogStream(aiDefaultLogStream_FILE, "AssimpLog_C.txt"); + aiAttachLogStream(&logstream); // ............................................................................ @@ -66,4 +65,4 @@ int main (int argc, char* argv[]) // Rueckmeldung, ob Tests erfolgreich waren return collectedresults.wasSuccessful () ? 0 : 1; -} \ No newline at end of file +} diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index 702bb7978..a3b9a6fe1 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -72,7 +72,7 @@ static const aiImporterDesc desc = { bool TestPlugin :: CanRead( const std::string& pFile, - IOSystem* pIOHandler, bool test) const + IOSystem* /*pIOHandler*/, bool /*test*/) const { std::string::size_type pos = pFile.find_last_of('.'); // no file extension - can't read @@ -90,8 +90,8 @@ const aiImporterDesc* TestPlugin :: GetInfo() const return & desc; } -void TestPlugin :: InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +void TestPlugin :: InternReadFile( const std::string& /*pFile*/, + aiScene* /*pScene*/, IOSystem* /*pIOHandler*/) { throw DeadlyImportError(AIUT_DEF_ERROR_TEXT); } @@ -208,11 +208,11 @@ void ImporterTest :: testMultipleReads (void) CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/test.x",flags)); //CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/dwarf.x",flags)); # is in nonbsd - CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/Testwuson.x",flags)); + CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/Testwuson.X",flags)); CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/anim_test.x",flags)); //CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/dwarf.x",flags)); # is in nonbsd CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/anim_test.x",flags)); - CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/bcn_epileptic.x",flags)); + CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/BCN_Epileptic.X",flags)); //CPPUNIT_ASSERT(pImp->ReadFile("../../test/models/X/dwarf.x",flags)); # is in nonbsd } diff --git a/test/unit/utNoBoostTest.h b/test/unit/utNoBoostTest.h index 5fe3ceabd..6fbff7dff 100644 --- a/test/unit/utNoBoostTest.h +++ b/test/unit/utNoBoostTest.h @@ -4,7 +4,7 @@ namespace noboost { #define ASSIMP_FORCE_NOBOOST -#include "..\..\code\BoostWorkaround\boost\format.hpp" +#include "../../code/BoostWorkaround/boost/format.hpp" using boost::format; using boost::str; @@ -34,4 +34,4 @@ class NoBoostTest : public CPPUNIT_NS :: TestFixture }; -#endif \ No newline at end of file +#endif diff --git a/test/unit/utRemoveComments.cpp b/test/unit/utRemoveComments.cpp index f1d11ec72..5779946eb 100644 --- a/test/unit/utRemoveComments.cpp +++ b/test/unit/utRemoveComments.cpp @@ -43,7 +43,7 @@ void RemoveCommentsTest :: testSingleLineComments (void) // ------------------------------------------------------------------------------------------------ void RemoveCommentsTest :: testMultiLineComments (void) { - char* szTest = + const char* szTest = "/* comment to be removed */\n" "valid text /* \n " " comment across multiple lines */" @@ -62,4 +62,4 @@ void RemoveCommentsTest :: testMultiLineComments (void) CPPUNIT_ASSERT(0 == ::strcmp(szTest2,szTestResult)); delete[] szTest2; -} \ No newline at end of file +} diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index 669e71b3a..185d4c4dc 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -656,7 +656,7 @@ uint32_t WriteBinaryScene(const aiScene* scene) // ----------------------------------------------------------------------------------- // Write a binary model dump void WriteBinaryDump(const aiScene* scene, FILE* _out, const char* src, const char* cmd, - bool _shortened, bool compressed, ImportData& imp) + bool _shortened, bool compressed, ImportData& /*imp*/) { out = _out; shortened = _shortened; diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index c32cbde61..0b95a8ec6 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -1030,18 +1030,17 @@ void PopulateExportMenu() //------------------------------------------------------------------------------- void DoExport(size_t formatId) { - if (!g_szFileName) { + if (!g_szFileName[0]) { + MessageBox(g_hDlg, "No model loaded", "Export", MB_ICONERROR); return; } - Exporter exp; const aiExportFormatDesc* const e = exp.GetExportFormatDescription(formatId); ai_assert(e); char szFileName[MAX_PATH*2]; - DWORD dwTemp; - if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"ModelExportDest",NULL,NULL,(BYTE*)szFileName,&dwTemp)) { - ai_assert(dwTemp == MAX_PATH + 1); + DWORD dwTemp = sizeof(szFileName); + if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"ModelExportDest",NULL,NULL,(BYTE*)szFileName, &dwTemp)) { ai_assert(strlen(szFileName) <= MAX_PATH); // invent a nice default file name