diff --git a/.gitignore b/.gitignore index 12cd76a87..2a3b68a50 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ test/gtest/src/gtest-stamp/Debug/gtest-build *.lib test/gtest/src/gtest-stamp/Debug/ tools/assimp_view/assimp_viewer.vcxproj.user +*.pyc # Unix editor backups *~ diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index cc2e734fc..5884125a2 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -129,30 +129,26 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offse // ------------------------------------------------------------------------------------------------ -uint32_t Offset(const char* begin, const char* cursor) -{ +uint32_t Offset(const char* begin, const char* cursor) { ai_assert(begin <= cursor); + return static_cast(cursor - begin); } - // ------------------------------------------------------------------------------------------------ -void TokenizeError(const std::string& message, const char* begin, const char* cursor) -{ +void TokenizeError(const std::string& message, const char* begin, const char* cursor) { TokenizeError(message, Offset(begin, cursor)); } - // ------------------------------------------------------------------------------------------------ -uint32_t ReadWord(const char* input, const char*& cursor, const char* end) -{ +uint32_t ReadWord(const char* input, const char*& cursor, const char* end) { const size_t k_to_read = sizeof( uint32_t ); if(Offset(cursor, end) < k_to_read ) { TokenizeError("cannot ReadWord, out of bounds",input, cursor); } uint32_t word; - memcpy(&word, cursor, 4); + ::memcpy(&word, cursor, 4); AI_SWAP4(word); cursor += k_to_read; @@ -167,7 +163,8 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor); } - uint64_t dword = *reinterpret_cast(cursor); + uint64_t dword /*= *reinterpret_cast(cursor)*/; + ::memcpy( &dword, cursor, sizeof( uint64_t ) ); AI_SWAP8(dword); cursor += k_to_read; @@ -176,24 +173,21 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) } // ------------------------------------------------------------------------------------------------ -uint8_t ReadByte(const char* input, const char*& cursor, const char* end) -{ +uint8_t ReadByte(const char* input, const char*& cursor, const char* end) { if(Offset(cursor, end) < sizeof( uint8_t ) ) { TokenizeError("cannot ReadByte, out of bounds",input, cursor); } - uint8_t word = *reinterpret_cast(cursor); + uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/ + ::memcpy( &word, cursor, sizeof( uint8_t ) ); ++cursor; return word; } - // ------------------------------------------------------------------------------------------------ -unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end, - bool long_length = false, - bool allow_null = false) -{ +unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, + const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) { const uint32_t len_len = long_length ? 4 : 1; if(Offset(cursor, end) < len_len) { TokenizeError("cannot ReadString, out of bounds reading length",input, cursor); @@ -222,8 +216,7 @@ unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const ch } // ------------------------------------------------------------------------------------------------ -void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) -{ +void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) { if(Offset(cursor, end) < 1) { TokenizeError("cannot ReadData, out of bounds reading length",input, cursor); } @@ -422,7 +415,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, return true; } -} +} // anonymous namespace // ------------------------------------------------------------------------------------------------ // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index 8d43a2436..4868b3e72 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -433,7 +433,11 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, // deal with this more elegantly and with less redundancy, but right // now it seems unavoidable. if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") { - std::vector tempData; + if ( !HasElement( source, indexDataElementName ) ) { + return; + } + + std::vector tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); data_out.resize(vertex_count); @@ -450,10 +454,12 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); data_out.resize(vertex_count); + if ( !HasElement( source, indexDataElementName ) ) { + return; + } std::vector uvIndices; ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - for (size_t i = 0, e = uvIndices.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; diff --git a/code/FBXParser.cpp b/code/FBXParser.cpp index d4d06567b..935fe5b08 100644 --- a/code/FBXParser.cpp +++ b/code/FBXParser.cpp @@ -1197,6 +1197,14 @@ std::string ParseTokenAsString(const Token& t) return i; } +bool HasElement( const Scope& sc, const std::string& index ) { + const Element* el = sc[ index ]; + if ( nullptr == el ) { + return false; + } + + return true; +} // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found diff --git a/code/FBXParser.h b/code/FBXParser.h index 4d3766d70..736adcea0 100644 --- a/code/FBXParser.h +++ b/code/FBXParser.h @@ -218,6 +218,8 @@ void ParseVectorDataArray(std::vector& out, const Element& el); void ParseVectorDataArray(std::vector& out, const Element& e); void ParseVectorDataArray(std::vector& out, const Element& el); +bool HasElement( const Scope& sc, const std::string& index ); + // extract a required element from a scope, abort if the element cannot be found const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL); diff --git a/code/glTF2AssetWriter.inl b/code/glTF2AssetWriter.inl index 6b1a50887..fa406fc71 100644 --- a/code/glTF2AssetWriter.inl +++ b/code/glTF2AssetWriter.inl @@ -156,7 +156,10 @@ namespace glTF2 { inline void Write(Value& obj, Buffer& b, AssetWriter& w) { obj.AddMember("byteLength", static_cast(b.byteLength), w.mAl); - obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl); + + const auto uri = b.GetURI(); + const auto relativeUri = uri.substr(uri.find_last_of("/\\") + 1u); + obj.AddMember("uri", Value(relativeUri, w.mAl).Move(), w.mAl); } inline void Write(Value& obj, BufferView& bv, AssetWriter& w) @@ -167,7 +170,9 @@ namespace glTF2 { if (bv.byteStride != 0) { obj.AddMember("byteStride", bv.byteStride, w.mAl); } - obj.AddMember("target", int(bv.target), w.mAl); + if (bv.target != 0) { + obj.AddMember("target", int(bv.target), w.mAl); + } } inline void Write(Value& /*obj*/, Camera& /*c*/, AssetWriter& /*w*/) @@ -177,17 +182,23 @@ namespace glTF2 { inline void Write(Value& obj, Image& img, AssetWriter& w) { - std::string uri; - if (img.HasData()) { - uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); - uri += ";base64,"; - Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + if (img.bufferView) { + obj.AddMember("bufferView", img.bufferView->index, w.mAl); + obj.AddMember("mimeType", Value(img.mimeType, w.mAl).Move(), w.mAl); } else { - uri = img.uri; - } + std::string uri; + if (img.HasData()) { + uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); + uri += ";base64,"; + Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + } + else { + uri = img.uri; + } - obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl); + obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl); + } } namespace { @@ -569,13 +580,17 @@ namespace glTF2 { throw DeadlyExportError("Could not open output file: " + std::string(path)); } + Ref bodyBuffer = mAsset.GetBodyBuffer(); + if (bodyBuffer->byteLength > 0) { + rapidjson::Value glbBodyBuffer; + glbBodyBuffer.SetObject(); + glbBodyBuffer.AddMember("byteLength", bodyBuffer->byteLength, mAl); + mDoc["buffers"].PushBack(glbBodyBuffer, mAl); + } + // Padding with spaces as required by the spec uint32_t padding = 0x20202020; - // Adapt JSON so that it is not pointing to an external file, - // as this is required by the GLB spec'. - mDoc["buffers"][0].RemoveMember("uri"); - // // JSON chunk // @@ -608,28 +623,25 @@ namespace glTF2 { // uint32_t binaryChunkLength = 0; - if (mAsset.buffers.Size() > 0) { - Ref b = mAsset.buffers.Get(0u); - if (b->byteLength > 0) { - binaryChunkLength = (b->byteLength + 3) & ~3; // Round up to next multiple of 4 - auto paddingLength = binaryChunkLength - b->byteLength; + if (bodyBuffer->byteLength > 0) { + binaryChunkLength = (bodyBuffer->byteLength + 3) & ~3; // Round up to next multiple of 4 + auto paddingLength = binaryChunkLength - bodyBuffer->byteLength; - GLB_Chunk binaryChunk; - binaryChunk.chunkLength = binaryChunkLength; - binaryChunk.chunkType = ChunkType_BIN; - AI_SWAP4(binaryChunk.chunkLength); + GLB_Chunk binaryChunk; + binaryChunk.chunkLength = binaryChunkLength; + binaryChunk.chunkType = ChunkType_BIN; + AI_SWAP4(binaryChunk.chunkLength); - size_t bodyOffset = sizeof(GLB_Header) + sizeof(GLB_Chunk) + jsonChunk.chunkLength; - outfile->Seek(bodyOffset, aiOrigin_SET); - if (outfile->Write(&binaryChunk, 1, sizeof(GLB_Chunk)) != sizeof(GLB_Chunk)) { - throw DeadlyExportError("Failed to write body data header!"); - } - if (outfile->Write(b->GetPointer(), 1, b->byteLength) != b->byteLength) { - throw DeadlyExportError("Failed to write body data!"); - } - if (paddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) { - throw DeadlyExportError("Failed to write body data padding!"); - } + size_t bodyOffset = sizeof(GLB_Header) + sizeof(GLB_Chunk) + jsonChunk.chunkLength; + outfile->Seek(bodyOffset, aiOrigin_SET); + if (outfile->Write(&binaryChunk, 1, sizeof(GLB_Chunk)) != sizeof(GLB_Chunk)) { + throw DeadlyExportError("Failed to write body data header!"); + } + if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) { + throw DeadlyExportError("Failed to write body data!"); + } + if (paddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) { + throw DeadlyExportError("Failed to write body data padding!"); } } diff --git a/code/glTF2Exporter.cpp b/code/glTF2Exporter.cpp index 22ceb57d2..221a3bf9f 100644 --- a/code/glTF2Exporter.cpp +++ b/code/glTF2Exporter.cpp @@ -109,6 +109,10 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai mAsset.reset( new Asset( pIOSystem ) ); + if (isBinary) { + mAsset->SetAsBinary(); + } + ExportMetadata(); ExportMaterials(); diff --git a/include/assimp/types.h b/include/assimp/types.h index 0012a0bba..e7bec2f85 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -110,8 +110,7 @@ extern "C" { /** Maximum dimension for strings, ASSIMP strings are zero terminated. */ #ifdef __cplusplus -static -const size_t MAXLEN = 1024; + static const size_t MAXLEN = 1024; #else # define MAXLEN 1024 #endif diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 85bb53add..7d9282745 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -51,11 +51,8 @@ if os.name=='posix': elif os.name=='nt': ext_whitelist.append('.dll') path_dirs = os.environ['PATH'].split(';') - for dir_candidate in path_dirs: - if 'assimp' in dir_candidate.lower(): - additional_dirs.append(dir_candidate) + additional_dirs.extend(path_dirs) -#print(additional_dirs) def vec2tuple(x): """ Converts a VECTOR3D to a Tuple """ return (x.x, x.y, x.z) diff --git a/test/models/FBX/box.fbx b/test/models/FBX/box.fbx new file mode 100644 index 000000000..cd60d72da Binary files /dev/null and b/test/models/FBX/box.fbx differ diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 2807f801c..975f2acef 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -61,3 +61,9 @@ public: TEST_F( utFBXImporterExporter, importXFromFileTest ) { EXPECT_TRUE( importerTest() ); } + +TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/box.fbx", aiProcess_ValidateDataStructure ); + EXPECT_NE( nullptr, scene ); +}