diff --git a/.gitignore b/.gitignore index 2a3b68a50..f8dda3e8b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ tools/assimp_cmd/Makefile # Tests test/results +test/readlinetest* # Python __pycache__ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6aebbbd01 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +#How to contribute + +If you want to contribute you can follow these setps: +- Fist create your own clone of assimp +- When you want to fix a bug or add a new feature create a branch on your own fork ( just follow https://help.github.com/articles/creating-a-pull-request-from-a-fork/ ) +- Push it to the repo and open a pull request +- A pull request will start our CI-service, which checks if the build works for linux and windows. + It will check for memory leaks, compiler warnings and memory alignment issues. If any of these tests fails: fix it and the tests will be reastarted automatically + - At the end we will perform a code review and merge your branch to the master branch. + + diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index d5d05db18..c8cc2fecd 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -208,8 +208,15 @@ OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_ # macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader # this way selective loaders can be compiled (reduces filesize + compile time) MACRO(ADD_ASSIMP_IMPORTER name) - OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" ${ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT}) - IF(ASSIMP_BUILD_${name}_IMPORTER) + IF (ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT) + set(ASSIMP_IMPORTER_ENABLED TRUE) + IF (DEFINED ASSIMP_BUILD_${name}_IMPORTER AND NOT ASSIMP_BUILD_${name}_IMPORTER) + set(ASSIMP_IMPORTER_ENABLED FALSE) + ENDIF () + ELSE () + set(ASSIMP_IMPORTER_ENABLED ${ASSIMP_BUILD_${name}_IMPORTER}) + ENDIF () + IF (ASSIMP_IMPORTER_ENABLED) LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN}) SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}") SET(${name}_SRCS ${ARGN}) diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 45dd52710..611e487b0 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -1819,9 +1819,12 @@ void ColladaLoader::ConvertPath (aiString& ss) // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... // I need to filter it without destroying linux paths starting with "/somewhere" - if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' ) - { - ss.length--; +#if defined( _MSC_VER ) + if( ss.data[0] == '/' && isalpha( (unsigned char) ss.data[1]) && ss.data[2] == ':' ) { +#else + if (ss.data[ 0 ] == '/' && isalpha( ss.data[ 1 ] ) && ss.data[ 2 ] == ':') { +#endif + --ss.length; ::memmove( ss.data, ss.data+1, ss.length); ss.data[ss.length] = 0; } diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 0a3a140f3..e02c5f41d 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -115,10 +115,10 @@ public: // import the metadata if ( !mMetaData.empty() ) { const size_t numMeta( mMetaData.size() ); - scene->mMetaData = aiMetadata::Alloc( numMeta ); + scene->mMetaData = aiMetadata::Alloc(static_cast( numMeta ) ); for ( size_t i = 0; i < numMeta; ++i ) { aiString val( mMetaData[ i ].value ); - scene->mMetaData->Set( i, mMetaData[ i ].name, val ); + scene->mMetaData->Set(static_cast( i ), mMetaData[ i ].name, val ); } } diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index 90270bbd7..d317382dc 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -127,7 +127,7 @@ bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool if ( extension.empty() || checkSig ) { static const char *pTokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" }; - return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 4 ); + return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 4, 32 ); } return false; diff --git a/code/DefaultIOSystem.cpp b/code/DefaultIOSystem.cpp index fee9c3e7f..58afe475c 100644 --- a/code/DefaultIOSystem.cpp +++ b/code/DefaultIOSystem.cpp @@ -76,11 +76,11 @@ bool DefaultIOSystem::Exists( const char* pFile) const #ifdef _WIN32 wchar_t fileName16[PATHLIMIT]; - bool isUnicode = IsTextUnicode(pFile, static_cast(strlen(pFile)), NULL); + bool isUnicode = IsTextUnicode(pFile, static_cast(strlen(pFile)), NULL) != 0; if (isUnicode) { MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT); - struct _stat64 filestat; + struct __stat64 filestat; if (0 != _wstat64(fileName16, &filestat)) { return false; } @@ -110,7 +110,7 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode) FILE* file; #ifdef _WIN32 wchar_t fileName16[PATHLIMIT]; - bool isUnicode = IsTextUnicode(strFile, static_cast(strlen(strFile)), NULL ); + bool isUnicode = IsTextUnicode(strFile, static_cast(strlen(strFile)), NULL) != 0; if (isUnicode) { MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT); std::string mode8(strMode); @@ -158,7 +158,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out) { ai_assert(in && _out); #if defined( _MSC_VER ) || defined( __MINGW32__ ) - bool isUnicode = IsTextUnicode(in, static_cast(strlen(in)), NULL); + bool isUnicode = IsTextUnicode(in, static_cast(strlen(in)), NULL) != 0; if (isUnicode) { wchar_t out16[PATHLIMIT]; wchar_t in16[PATHLIMIT]; diff --git a/code/Exporter.cpp b/code/Exporter.cpp index bd533f3b3..894c00740 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -154,9 +154,9 @@ Exporter::ExportFormatEntry gExporters[] = aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2, + Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb2", &ExportSceneGLB2, + Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2, aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), #endif diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index d6c34de6f..b81a9f945 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -448,8 +448,8 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le /*Result ignored*/ ReadByte(input, cursor, input + length); const uint32_t version = ReadWord(input, cursor, input + length); const bool is64bits = version >= 7500; - while (cursor < input + length) - { + const char *end = input + length; + while (cursor < end ) { if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { break; } diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index 1bbd18145..c21d71f47 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -108,6 +108,125 @@ void JoinVerticesProcess::Execute( aiScene* pScene) pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; } +namespace { + +bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) +{ + // A little helper to find locally close vertices faster. + // Try to reuse the lookup table from the last step. + const static float epsilon = 1e-5f; + // Squared because we check against squared length of the vector difference + static const float squareEpsilon = epsilon * epsilon; + + // Square compare is useful for animeshes vertexes compare + if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) { + return false; + } + + // We just test the other attributes even if they're not present in the mesh. + // In this case they're initialized to 0 so the comparison succeeds. + // By this method the non-present attributes are effectively ignored in the comparison. + if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.texcoords[0] - rhs.texcoords[0]).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) { + return false; + } + + // Usually we won't have vertex colors or multiple UVs, so we can skip from here + // Actually this increases runtime performance slightly, at least if branch + // prediction is on our side. + if (complex) { + for (int i = 0; i < 8; i++) { + if (i > 0 && (lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) { + return false; + } + if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) { + return false; + } + } + } + return true; +} + +template +void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { + // replace vertex data with the unique data sets + pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); + + // ---------------------------------------------------------------------------- + // NOTE - we're *not* calling Vertex::SortBack() because it would check for + // presence of every single vertex component once PER VERTEX. And our CPU + // dislikes branches, even if they're easily predictable. + // ---------------------------------------------------------------------------- + + // Position, if present (check made for aiAnimMesh) + if (pMesh->mVertices) + { + delete [] pMesh->mVertices; + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mVertices[a] = uniqueVertices[a].position; + } + } + + // Normals, if present + if (pMesh->mNormals) + { + delete [] pMesh->mNormals; + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mNormals[a] = uniqueVertices[a].normal; + } + } + // Tangents, if present + if (pMesh->mTangents) + { + delete [] pMesh->mTangents; + pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mTangents[a] = uniqueVertices[a].tangent; + } + } + // Bitangents as well + if (pMesh->mBitangents) + { + delete [] pMesh->mBitangents; + pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mBitangents[a] = uniqueVertices[a].bitangent; + } + } + // Vertex colors + for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) + { + delete [] pMesh->mColors[a]; + pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; + for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; + } + } + // Texture coords + for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) + { + delete [] pMesh->mTextureCoords[a]; + pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; + } + } +} +} // namespace + // ------------------------------------------------------------------------------------------------ // Unites identical vertices in the given mesh int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) @@ -132,9 +251,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); - // A little helper to find locally close vertices faster. - // Try to reuse the lookup table from the last step. - const static float epsilon = 1e-5f; // float posEpsilonSqr; SpatialSort* vertexFinder = NULL; SpatialSort _vertexFinder; @@ -156,9 +272,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // posEpsilonSqr = ComputePositionEpsilon(pMesh); } - // Squared because we check against squared length of the vector difference - static const float squareEpsilon = epsilon * epsilon; - // Again, better waste some bytes than a realloc ... std::vector verticesFound; verticesFound.reserve(10); @@ -166,6 +279,16 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // Run an optimized code path if we don't have multiple UVs or vertex colors. // This should yield false in more than 99% of all imports ... const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1); + const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0; + + // We'll never have more vertices afterwards. + std::vector> uniqueAnimatedVertices; + if (hasAnimMeshes) { + uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes); + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices); + } + } // Now check each vertex if it brings something new to the table for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { @@ -178,74 +301,32 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // check all unique vertices close to the position if this vertex is already present among them for( unsigned int b = 0; b < verticesFound.size(); b++) { - const unsigned int vidx = verticesFound[b]; const unsigned int uidx = replaceIndex[ vidx]; if( uidx & 0x80000000) continue; const Vertex& uv = uniqueVertices[ uidx]; - // Position mismatch is impossible - the vertex finder already discarded all non-matching positions - // We just test the other attributes even if they're not present in the mesh. - // In this case they're initialized to 0 so the comparison succeeds. - // By this method the non-present attributes are effectively ignored in the comparison. - if( (uv.normal - v.normal).SquareLength() > squareEpsilon) - continue; - if( (uv.texcoords[0] - v.texcoords[0]).SquareLength() > squareEpsilon) - continue; - if( (uv.tangent - v.tangent).SquareLength() > squareEpsilon) - continue; - if( (uv.bitangent - v.bitangent).SquareLength() > squareEpsilon) + if (!areVerticesEqual(v, uv, complex)) { continue; + } - // Usually we won't have vertex colors or multiple UVs, so we can skip from here - // Actually this increases runtime performance slightly, at least if branch - // prediction is on our side. - if (complex){ - // manually unrolled because continue wouldn't work as desired in an inner loop, - // also because some compilers seem to fail the task. Colors and UV coords - // are interleaved since the higher entries are most likely to be - // zero and thus useless. By interleaving the arrays, vertices are, - // on average, rejected earlier. - - if( (uv.texcoords[1] - v.texcoords[1]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[0], v.colors[0]) > squareEpsilon) - continue; - - if( (uv.texcoords[2] - v.texcoords[2]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[1], v.colors[1]) > squareEpsilon) - continue; - - if( (uv.texcoords[3] - v.texcoords[3]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[2], v.colors[2]) > squareEpsilon) - continue; - - if( (uv.texcoords[4] - v.texcoords[4]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[3], v.colors[3]) > squareEpsilon) - continue; - - if( (uv.texcoords[5] - v.texcoords[5]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[4], v.colors[4]) > squareEpsilon) - continue; - - if( (uv.texcoords[6] - v.texcoords[6]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[5], v.colors[5]) > squareEpsilon) - continue; - - if( (uv.texcoords[7] - v.texcoords[7]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[6], v.colors[6]) > squareEpsilon) - continue; - - if( GetColorDifference( uv.colors[7], v.colors[7]) > squareEpsilon) + if (hasAnimMeshes) { + // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology) + // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces) + bool breaksAnimMesh = false; + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx]; + Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); + if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) { + breaksAnimMesh = true; + break; + } + } + if (breaksAnimMesh) { continue; + } } // we're still here -> this vertex perfectly matches our given vertex @@ -264,6 +345,12 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // no unique vertex matches it up to now -> so add it replaceIndex[a] = (unsigned int)uniqueVertices.size(); uniqueVertices.push_back( v); + if (hasAnimMeshes) { + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); + uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex); + } + } } } @@ -281,64 +368,10 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) ); } - // replace vertex data with the unique data sets - pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); - - // ---------------------------------------------------------------------------- - // NOTE - we're *not* calling Vertex::SortBack() because it would check for - // presence of every single vertex component once PER VERTEX. And our CPU - // dislikes branches, even if they're easily predictable. - // ---------------------------------------------------------------------------- - - // Position - delete [] pMesh->mVertices; - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - pMesh->mVertices[a] = uniqueVertices[a].position; - - // Normals, if present - if( pMesh->mNormals) - { - delete [] pMesh->mNormals; - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mNormals[a] = uniqueVertices[a].normal; - } - } - // Tangents, if present - if( pMesh->mTangents) - { - delete [] pMesh->mTangents; - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mTangents[a] = uniqueVertices[a].tangent; - } - } - // Bitangents as well - if( pMesh->mBitangents) - { - delete [] pMesh->mBitangents; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mBitangents[a] = uniqueVertices[a].bitangent; - } - } - // Vertex colors - for( unsigned int a = 0; pMesh->HasVertexColors(a); a++) - { - delete [] pMesh->mColors[a]; - pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; - } - } - // Texture coords - for( unsigned int a = 0; pMesh->HasTextureCoords(a); a++) - { - delete [] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; + updateXMeshVertices(pMesh, uniqueVertices); + if (hasAnimMeshes) { + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]); } } diff --git a/code/glTF2Exporter.cpp b/code/glTF2Exporter.cpp index fcf8005ae..d4b3d67de 100644 --- a/code/glTF2Exporter.cpp +++ b/code/glTF2Exporter.cpp @@ -138,28 +138,29 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai } } +glTF2Exporter::~glTF2Exporter() { + // empty +} + /* * Copy a 4x4 matrix from struct aiMatrix to typedef mat4. * Also converts from row-major to column-major storage. */ -static void CopyValue(const aiMatrix4x4& v, mat4& o) -{ +static void CopyValue(const aiMatrix4x4& v, mat4& o) { o[ 0] = v.a1; o[ 1] = v.b1; o[ 2] = v.c1; o[ 3] = v.d1; o[ 4] = v.a2; o[ 5] = v.b2; o[ 6] = v.c2; o[ 7] = v.d2; o[ 8] = v.a3; o[ 9] = v.b3; o[10] = v.c3; o[11] = v.d3; o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4; } -static void CopyValue(const aiMatrix4x4& v, aiMatrix4x4& o) -{ +static void CopyValue(const aiMatrix4x4& v, aiMatrix4x4& o) { o.a1 = v.a1; o.a2 = v.a2; o.a3 = v.a3; o.a4 = v.a4; o.b1 = v.b1; o.b2 = v.b2; o.b3 = v.b3; o.b4 = v.b4; o.c1 = v.c1; o.c2 = v.c2; o.c3 = v.c3; o.c4 = v.c4; o.d1 = v.d1; o.d2 = v.d2; o.d3 = v.d3; o.d4 = v.d4; } -static void IdentityMatrix4(mat4& o) -{ +static void IdentityMatrix4(mat4& o) { o[ 0] = 1; o[ 1] = 0; o[ 2] = 0; o[ 3] = 0; o[ 4] = 0; o[ 5] = 1; o[ 6] = 0; o[ 7] = 0; o[ 8] = 0; o[ 9] = 0; o[10] = 1; o[11] = 0; @@ -169,7 +170,9 @@ static void IdentityMatrix4(mat4& o) inline Ref ExportData(Asset& a, std::string& meshName, Ref& buffer, unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) { - if (!count || !data) return Ref(); + if (!count || !data) { + return Ref(); + } unsigned int numCompsIn = AttribType::GetNumComponents(typeIn); unsigned int numCompsOut = AttribType::GetNumComponents(typeOut); @@ -638,11 +641,11 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, Refprimitives.back(); Ref vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if ( vertexJointAccessor ) { - unsigned int offset = vertexJointAccessor->bufferView->byteOffset; - unsigned int bytesLen = vertexJointAccessor->bufferView->byteLength; + size_t offset = vertexJointAccessor->bufferView->byteOffset; + size_t bytesLen = vertexJointAccessor->bufferView->byteLength; unsigned int s_bytesPerComp= ComponentTypeSize(ComponentType_UNSIGNED_SHORT); unsigned int bytesPerComp = ComponentTypeSize(vertexJointAccessor->componentType); - unsigned int s_bytesLen = bytesLen * s_bytesPerComp / bytesPerComp; + size_t s_bytesLen = bytesLen * s_bytesPerComp / bytesPerComp; Ref buf = vertexJointAccessor->bufferView->buffer; uint8_t* arrys = new uint8_t[s_bytesLen]; unsigned int i = 0; @@ -728,8 +731,10 @@ void glTF2Exporter::ExportMeshes() /******************** Normals ********************/ // Normalize all normals as the validator can emit a warning otherwise - for (auto i = 0u; i < aim->mNumVertices; ++i) { - aim->mNormals[i].Normalize(); + if ( nullptr != aim->mNormals) { + for ( auto i = 0u; i < aim->mNumVertices; ++i ) { + aim->mNormals[ i ].Normalize(); + } } Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); @@ -759,7 +764,7 @@ void glTF2Exporter::ExportMeshes() if (c) p.attributes.color.push_back(c); } - + /*************** Vertices indices ****************/ if (aim->mNumFaces > 0) { std::vector indices; @@ -891,6 +896,8 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n) { Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); + node->name = n->mName.C_Str(); + if (!n->mTransformation.IsIdentity()) { node->matrix.isPresent = true; CopyValue(n->mTransformation, node->matrix.value); diff --git a/code/glTF2Exporter.h b/code/glTF2Exporter.h index ff94be9e9..06bc5ad40 100644 --- a/code/glTF2Exporter.h +++ b/code/glTF2Exporter.h @@ -87,28 +87,15 @@ namespace Assimp // ------------------------------------------------------------------------------------------------ /** Helper class to export a given scene to an glTF file. */ // ------------------------------------------------------------------------------------------------ - class glTF2Exporter - { + class glTF2Exporter { public: /// Constructor for a specific scene to export glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties, bool binary); + ~glTF2Exporter(); - private: - - const char* mFilename; - IOSystem* mIOSystem; - const aiScene* mScene; - const ExportProperties* mProperties; - - std::map mTexturesByPath; - - std::shared_ptr mAsset; - - std::vector mBodyData; - + protected: void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); - void GetTexSampler(const aiMaterial* mat, glTF2::Ref texture, aiTextureType tt, unsigned int slot); void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); @@ -126,6 +113,15 @@ namespace Assimp unsigned int ExportNode(const aiNode* node, glTF2::Ref& parent); void ExportScene(); void ExportAnimations(); + + private: + const char* mFilename; + IOSystem* mIOSystem; + const aiScene* mScene; + const ExportProperties* mProperties; + std::map mTexturesByPath; + std::shared_ptr mAsset; + std::vector mBodyData; }; } diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index 02ae3c0f4..f1c02ee07 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -134,6 +134,30 @@ public: } } + // ---------------------------------------------------------------------------- + /** Extract a particular vertex from a anim mesh and interleave all components */ + explicit Vertex(const aiAnimMesh* msh, unsigned int idx) { + ai_assert(idx < msh->mNumVertices); + position = msh->mVertices[idx]; + + if (msh->HasNormals()) { + normal = msh->mNormals[idx]; + } + + if (msh->HasTangentsAndBitangents()) { + tangent = msh->mTangents[idx]; + bitangent = msh->mBitangents[idx]; + } + + for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) { + texcoords[i] = msh->mTextureCoords[i][idx]; + } + + for (unsigned int i = 0; msh->HasVertexColors(i); ++i) { + colors[i] = msh->mColors[i][idx]; + } + } + public: Vertex& operator += (const Vertex& v) { diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 70a604de9..8ac8e250a 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -149,7 +149,8 @@ struct aiMetadata { mValues[ i ].mType = rhs.mValues[ i ].mType; switch ( rhs.mValues[ i ].mType ) { case AI_BOOL: - mValues[ i ].mData = new bool( rhs.mValues[i].mData ); + mValues[ i ].mData = new bool; + ::memcpy( mValues[ i ].mData, rhs.mValues[ i ].mData, sizeof(bool) ); break; case AI_INT32: { int32_t v; diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 91b8917a8..58ebe3017 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -89,4 +89,5 @@ TEST_F( utglTF2ImportExport, importBinaryglTF2FromFileTest ) { TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { EXPECT_TRUE( exporterTest() ); } + #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/tools/assimp_cmd/Export.cpp b/tools/assimp_cmd/Export.cpp index 55c017e33..03f896822 100644 --- a/tools/assimp_cmd/Export.cpp +++ b/tools/assimp_cmd/Export.cpp @@ -106,7 +106,8 @@ int Assimp_Export(const char* const* params, unsigned int num) continue; } if (!strncmp( params[i], "-f",2)) { - outf = std::string(params[i]+2); + if ( strncmp( params[ i ], "-fi",3 )) + outf = std::string(params[i]+2); } else if ( !strncmp( params[i], "--format=",9)) { outf = std::string(params[i]+9); diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 14d00e1e1..41412b93d 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -261,7 +261,6 @@ void PrintHorBar() printf("-----------------------------------------------------------------\n"); } - // ------------------------------------------------------------------------------ // Import a specific file const aiScene* ImportModel( @@ -390,105 +389,101 @@ int ProcessStandardArguments( for (unsigned int i = 0; i < num;++i) { - if (! strcmp(params[i], "-ptv") || ! strcmp(params[i], "--pretransform-vertices")) { + const char *param = params[ i ]; + printf( "param = %s\n", param ); + if (! strcmp( param, "-ptv") || ! strcmp( param, "--pretransform-vertices")) { fill.ppFlags |= aiProcess_PreTransformVertices; } - else if (! strcmp(params[i], "-gsn") || ! strcmp(params[i], "--gen-smooth-normals")) { + else if (! strcmp( param, "-gsn") || ! strcmp( param, "--gen-smooth-normals")) { fill.ppFlags |= aiProcess_GenSmoothNormals; } - else if (! strcmp(params[i], "-gn") || ! strcmp(params[i], "--gen-normals")) { + else if (! strcmp( param, "-gn") || ! strcmp( param, "--gen-normals")) { fill.ppFlags |= aiProcess_GenNormals; } - else if (! strcmp(params[i], "-jiv") || ! strcmp(params[i], "--join-identical-vertices")) { + else if (! strcmp( param, "-jiv") || ! strcmp( param, "--join-identical-vertices")) { fill.ppFlags |= aiProcess_JoinIdenticalVertices; } - else if (! strcmp(params[i], "-rrm") || ! strcmp(params[i], "--remove-redundant-materials")) { + else if (! strcmp( param, "-rrm") || ! strcmp( param, "--remove-redundant-materials")) { fill.ppFlags |= aiProcess_RemoveRedundantMaterials; } - else if (! strcmp(params[i], "-fd") || ! strcmp(params[i], "--find-degenerates")) { + else if (! strcmp( param, "-fd") || ! strcmp( param, "--find-degenerates")) { fill.ppFlags |= aiProcess_FindDegenerates; } - else if (! strcmp(params[i], "-slm") || ! strcmp(params[i], "--split-large-meshes")) { + else if (! strcmp( param, "-slm") || ! strcmp( param, "--split-large-meshes")) { fill.ppFlags |= aiProcess_SplitLargeMeshes; } - else if (! strcmp(params[i], "-lbw") || ! strcmp(params[i], "--limit-bone-weights")) { + else if (! strcmp( param, "-lbw") || ! strcmp( param, "--limit-bone-weights")) { fill.ppFlags |= aiProcess_LimitBoneWeights; } - else if (! strcmp(params[i], "-vds") || ! strcmp(params[i], "--validate-data-structure")) { + else if (! strcmp( param, "-vds") || ! strcmp( param, "--validate-data-structure")) { fill.ppFlags |= aiProcess_ValidateDataStructure; } - else if (! strcmp(params[i], "-icl") || ! strcmp(params[i], "--improve-cache-locality")) { + else if (! strcmp( param, "-icl") || ! strcmp( param, "--improve-cache-locality")) { fill.ppFlags |= aiProcess_ImproveCacheLocality; } - else if (! strcmp(params[i], "-sbpt") || ! strcmp(params[i], "--sort-by-ptype")) { + else if (! strcmp( param, "-sbpt") || ! strcmp( param, "--sort-by-ptype")) { fill.ppFlags |= aiProcess_SortByPType; } - else if (! strcmp(params[i], "-lh") || ! strcmp(params[i], "--left-handed")) { + else if (! strcmp( param, "-lh") || ! strcmp( param, "--left-handed")) { fill.ppFlags |= aiProcess_ConvertToLeftHanded; } - else if (! strcmp(params[i], "-fuv") || ! strcmp(params[i], "--flip-uv")) { + else if (! strcmp( param, "-fuv") || ! strcmp( param, "--flip-uv")) { fill.ppFlags |= aiProcess_FlipUVs; } - else if (! strcmp(params[i], "-fwo") || ! strcmp(params[i], "--flip-winding-order")) { + else if (! strcmp( param, "-fwo") || ! strcmp( param, "--flip-winding-order")) { fill.ppFlags |= aiProcess_FlipWindingOrder; } - else if (! strcmp(params[i], "-tuv") || ! strcmp(params[i], "--transform-uv-coords")) { + else if (! strcmp( param, "-tuv") || ! strcmp( param, "--transform-uv-coords")) { fill.ppFlags |= aiProcess_TransformUVCoords; } - else if (! strcmp(params[i], "-guv") || ! strcmp(params[i], "--gen-uvcoords")) { + else if (! strcmp( param, "-guv") || ! strcmp( param, "--gen-uvcoords")) { fill.ppFlags |= aiProcess_GenUVCoords; } - else if (! strcmp(params[i], "-fid") || ! strcmp(params[i], "--find-invalid-data")) { + else if (! strcmp( param, "-fid") || ! strcmp( param, "--find-invalid-data")) { fill.ppFlags |= aiProcess_FindInvalidData; } - else if (! strcmp(params[i], "-fixn") || ! strcmp(params[i], "--fix-normals")) { + else if (! strcmp( param, "-fixn") || ! strcmp( param, "--fix-normals")) { fill.ppFlags |= aiProcess_FixInfacingNormals; } - else if (! strcmp(params[i], "-tri") || ! strcmp(params[i], "--triangulate")) { + else if (! strcmp( param, "-tri") || ! strcmp( param, "--triangulate")) { fill.ppFlags |= aiProcess_Triangulate; } - else if (! strcmp(params[i], "-cts") || ! strcmp(params[i], "--calc-tangent-space")) { + else if (! strcmp( param, "-cts") || ! strcmp( param, "--calc-tangent-space")) { fill.ppFlags |= aiProcess_CalcTangentSpace; } - else if (! strcmp(params[i], "-fi") || ! strcmp(params[i], "--find-instances")) { + else if (! strcmp( param, "-fi") || ! strcmp( param, "--find-instances")) { fill.ppFlags |= aiProcess_FindInstances; } - else if (! strcmp(params[i], "-og") || ! strcmp(params[i], "--optimize-graph")) { + else if (! strcmp( param, "-og") || ! strcmp( param, "--optimize-graph")) { fill.ppFlags |= aiProcess_OptimizeGraph; } - else if (! strcmp(params[i], "-om") || ! strcmp(params[i], "--optimize-meshes")) { + else if (! strcmp( param, "-om") || ! strcmp( param, "--optimize-meshes")) { fill.ppFlags |= aiProcess_OptimizeMeshes; } - else if (! strcmp(params[i], "-db") || ! strcmp(params[i], "--debone")) { + else if (! strcmp( param, "-db") || ! strcmp( param, "--debone")) { fill.ppFlags |= aiProcess_Debone; } - else if (! strcmp(params[i], "-sbc") || ! strcmp(params[i], "--split-by-bone-count")) { + else if (! strcmp( param, "-sbc") || ! strcmp( param, "--split-by-bone-count")) { fill.ppFlags |= aiProcess_SplitByBoneCount; } - - - else if (! strncmp(params[i], "-c",2) || ! strncmp(params[i], "--config=",9)) { - + else if (! strncmp( param, "-c",2) || ! strncmp( param, "--config=",9)) { const unsigned int ofs = (params[i][1] == '-' ? 9 : 2); // use default configurations - if (! strncmp(params[i]+ofs,"full",4)) { - fill.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; - } - else if (! strncmp(params[i]+ofs,"default",7)) { + if (!strncmp( param + ofs, "full", 4 )) { + fill.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; + } else if (!strncmp( param + ofs, "default", 7 )) { fill.ppFlags |= aiProcessPreset_TargetRealtime_Quality; - } - else if (! strncmp(params[i]+ofs,"fast",4)) { + } else if (! strncmp( param +ofs,"fast",4)) { fill.ppFlags |= aiProcessPreset_TargetRealtime_Fast; } - } - else if (! strcmp(params[i], "-l") || ! strcmp(params[i], "--show-log")) { + } else if (! strcmp( param, "-l") || ! strcmp( param, "--show-log")) { fill.showLog = true; } - else if (! strcmp(params[i], "-v") || ! strcmp(params[i], "--verbose")) { + else if (! strcmp( param, "-v") || ! strcmp( param, "--verbose")) { fill.verbose = true; } - else if (! strncmp(params[i], "--log-out=",10) || ! strncmp(params[i], "-lo",3)) { + else if (! strncmp( param, "--log-out=",10) || ! strncmp( param, "-lo",3)) { fill.logFile = std::string(params[i]+(params[i][1] == '-' ? 10 : 3)); if (!fill.logFile.length()) { fill.logFile = "assimp-log.txt"; diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 207c26fa9..156844a9b 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -2259,7 +2259,7 @@ int CDisplay::RenderTextureView() const float ny = (float)sRect.bottom; const float x = (float)sDesc.Width; const float y = (float)sDesc.Height; - float f = min((nx-30) / x,(ny-30) / y) * (m_fTextureZoom/1000.0f); + float f = std::min((nx-30) / x,(ny-30) / y) * (m_fTextureZoom/1000.0f); float fHalfX = (nx - (f * x)) / 2.0f; float fHalfY = (ny - (f * y)) / 2.0f; diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index f04ea28eb..1fb13f5a8 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -275,7 +275,7 @@ bool CMaterialManager::TryLongerPath(char* szTemp,aiString* p_szString) for (unsigned int i = 0; i < iSizeFound;++i) info.cFileName[i] = (CHAR)tolower(info.cFileName[i]); - if (0 == memcmp(info.cFileName,szFile2, min(iSizeFound,iSize))) + if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize))) { // we have it. Build the full path ... char* sz = strrchr(szTempB,'*'); diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 695e8cfd6..5a9cfd0ed 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -45,7 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include + +#ifdef __MINGW32__ +#include +#else #include +#endif namespace AssimpView { @@ -1049,9 +1054,9 @@ void DoExport(size_t formatId) ai_assert(strlen(szFileName) <= MAX_PATH); // invent a nice default file name - char* sz = max(strrchr(szFileName,'\\'),strrchr(szFileName,'/')); + char* sz = std::max(strrchr(szFileName,'\\'),strrchr(szFileName,'/')); if (sz) { - strncpy(sz,max(strrchr(g_szFileName,'\\'),strrchr(g_szFileName,'/')),MAX_PATH); + strncpy(sz,std::max(strrchr(g_szFileName,'\\'),strrchr(g_szFileName,'/')),MAX_PATH); } } else { diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index ac2d1e66d..33ca25799 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -43,10 +43,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" -#include #include #include +#ifdef __MINGW32__ +#include +#else +#include +#endif + using namespace std; namespace AssimpView { diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index 70bce2ce4..9317495c1 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -46,6 +46,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_SHADER_COMPILE_FLAGS D3DXSHADER_USE_LEGACY_D3DX9_31_DLL +// Because Dx headers include windef.h with min/max redefinition +#define NOMINMAX + // include resource definitions #include "resource.h" @@ -177,7 +180,7 @@ type clamp(intype in) { // for unsigned types only ... intype mask = (0x1u << (sizeof(type)*8))-1; - return (type)max((intype)0,min(in,mask)); + return (type)std::max((intype)0,std::min(in,mask)); }