From 3d4b54f8fcdd26308f20595ae7928a2d0470d771 Mon Sep 17 00:00:00 2001 From: rickomax Date: Wed, 19 Jul 2017 19:00:53 -0300 Subject: [PATCH 01/37] Fixed FBX 7500 Binary reading Seems that all FBX 7.5 Binary files uses 32 bits adresses. The code now is taking this in consideration. This commit fixes the https://github.com/assimp/assimp/issues/838 issue. --- code/FBXBinaryTokenizer.cpp | 113 ++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index a02458fa5..fb57b2f97 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -56,47 +56,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace FBX { -enum Flag -{ - e_unknown_0 = 1 << 0, - e_unknown_1 = 1 << 1, - e_unknown_2 = 1 << 2, - e_unknown_3 = 1 << 3, - e_unknown_4 = 1 << 4, - e_unknown_5 = 1 << 5, - e_unknown_6 = 1 << 6, - e_unknown_7 = 1 << 7, - e_unknown_8 = 1 << 8, - e_unknown_9 = 1 << 9, - e_unknown_10 = 1 << 10, - e_unknown_11 = 1 << 11, - e_unknown_12 = 1 << 12, - e_unknown_13 = 1 << 13, - e_unknown_14 = 1 << 14, - e_unknown_15 = 1 << 15, - e_unknown_16 = 1 << 16, - e_unknown_17 = 1 << 17, - e_unknown_18 = 1 << 18, - e_unknown_19 = 1 << 19, - e_unknown_20 = 1 << 20, - e_unknown_21 = 1 << 21, - e_unknown_22 = 1 << 22, - e_unknown_23 = 1 << 23, - e_flag_field_size_64_bit = 1 << 24, // Not sure what is - e_unknown_25 = 1 << 25, - e_unknown_26 = 1 << 26, - e_unknown_27 = 1 << 27, - e_unknown_28 = 1 << 28, - e_unknown_29 = 1 << 29, - e_unknown_30 = 1 << 30, - e_unknown_31 = 1 << 31 -}; - -bool check_flag(uint32_t flags, Flag to_check) -{ - return (flags & to_check) != 0; -} - +//enum Flag +//{ +// e_unknown_0 = 1 << 0, +// e_unknown_1 = 1 << 1, +// e_unknown_2 = 1 << 2, +// e_unknown_3 = 1 << 3, +// e_unknown_4 = 1 << 4, +// e_unknown_5 = 1 << 5, +// e_unknown_6 = 1 << 6, +// e_unknown_7 = 1 << 7, +// e_unknown_8 = 1 << 8, +// e_unknown_9 = 1 << 9, +// e_unknown_10 = 1 << 10, +// e_unknown_11 = 1 << 11, +// e_unknown_12 = 1 << 12, +// e_unknown_13 = 1 << 13, +// e_unknown_14 = 1 << 14, +// e_unknown_15 = 1 << 15, +// e_unknown_16 = 1 << 16, +// e_unknown_17 = 1 << 17, +// e_unknown_18 = 1 << 18, +// e_unknown_19 = 1 << 19, +// e_unknown_20 = 1 << 20, +// e_unknown_21 = 1 << 21, +// e_unknown_22 = 1 << 22, +// e_unknown_23 = 1 << 23, +// e_flag_field_size_64_bit = 1 << 24, // Not sure what is +// e_unknown_25 = 1 << 25, +// e_unknown_26 = 1 << 26, +// e_unknown_27 = 1 << 27, +// e_unknown_28 = 1 << 28, +// e_unknown_29 = 1 << 29, +// e_unknown_30 = 1 << 30, +// e_unknown_31 = 1 << 31 +//}; +// +//bool check_flag(uint32_t flags, Flag to_check) +//{ +// return (flags & to_check) != 0; +//} // ------------------------------------------------------------------------------------------------ Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset) : @@ -341,10 +340,11 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, // ------------------------------------------------------------------------------------------------ -bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, uint32_t const flags) +//TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent +bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, uint32_t const version) { // the first word contains the offset at which this block ends - const uint64_t end_offset = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) : */ReadWord(input, cursor, end); + const uint64_t end_offset = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // we may get 0 if reading reached the end of the file - // fbx files have a mysterious extra footer which I don't know @@ -362,10 +362,10 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, } // the second data word contains the number of properties in the scope - const uint64_t prop_count = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) : */ReadWord(input, cursor, end); + const uint64_t prop_count = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // the third data word contains the length of the property list - const uint64_t prop_length = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) :*/ ReadWord(input, cursor, end); + const uint64_t prop_length = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // now comes the name of the scope/key const char* sbeg, *send; @@ -392,7 +392,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // at the end of each nested block, there is a NUL record to indicate // that the sub-scope exists (i.e. to distinguish between P: and P : {}) // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit. - const size_t sentinel_block_length = /*check_flag(flags, e_flag_field_size_64_bit) ? (sizeof(uint64_t) * 3 + 1) : */(sizeof(uint32_t) * 3 + 1); + const size_t sentinel_block_length = version == 7500 ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1); if (Offset(input, cursor) < end_offset) { if (end_offset - Offset(input, cursor) < sentinel_block_length) { @@ -403,7 +403,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // XXX this is vulnerable to stack overflowing .. while(Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, flags); + ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, version); } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); @@ -438,19 +438,16 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le TokenizeError("magic bytes not found",0); } - - //uint32_t offset = 0x15; - const char* cursor = input + 0x15; - - const uint32_t flags = ReadWord(input, cursor, input + length); - - const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused - (void) padding_0; - const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused - (void) padding_1; + const char* cursor = input + 18; + const uint8_t unknown_1 = ReadByte(input, cursor, input + length); + const uint8_t unknown_2 = ReadByte(input, cursor, input + length); + const uint8_t unknown_3 = ReadByte(input, cursor, input + length); + const uint8_t unknown_4 = ReadByte(input, cursor, input + length); + const uint8_t unknown_5 = ReadByte(input, cursor, input + length); + const uint32_t version = ReadWord(input, cursor, input + length); while (cursor < input + length) { - if(!ReadScope(output_tokens, input, cursor, input + length, flags)) { + if (!ReadScope(output_tokens, input, cursor, input + length, version)) { break; } } From 147541ab7f8eeffd2828530703cd8dfe792e8248 Mon Sep 17 00:00:00 2001 From: rickomax Date: Wed, 19 Jul 2017 19:04:10 -0300 Subject: [PATCH 02/37] Complementing last fix Complementing last fix --- code/FBXBinaryTokenizer.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index fb57b2f97..d388c6446 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -340,11 +340,10 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, // ------------------------------------------------------------------------------------------------ -//TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent -bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, uint32_t const version) +bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits) { // the first word contains the offset at which this block ends - const uint64_t end_offset = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); + const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // we may get 0 if reading reached the end of the file - // fbx files have a mysterious extra footer which I don't know @@ -362,10 +361,10 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, } // the second data word contains the number of properties in the scope - const uint64_t prop_count = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); + const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // the third data word contains the length of the property list - const uint64_t prop_length = version == 7500 ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); + const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // now comes the name of the scope/key const char* sbeg, *send; @@ -392,7 +391,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // at the end of each nested block, there is a NUL record to indicate // that the sub-scope exists (i.e. to distinguish between P: and P : {}) // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit. - const size_t sentinel_block_length = version == 7500 ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1); + const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1); if (Offset(input, cursor) < end_offset) { if (end_offset - Offset(input, cursor) < sentinel_block_length) { @@ -403,7 +402,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // XXX this is vulnerable to stack overflowing .. while(Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, version); + ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); @@ -426,6 +425,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, } // ------------------------------------------------------------------------------------------------ +// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length) { ai_assert(input); @@ -445,9 +445,10 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le const uint8_t unknown_4 = ReadByte(input, cursor, input + length); const uint8_t unknown_5 = ReadByte(input, cursor, input + length); const uint32_t version = ReadWord(input, cursor, input + length); + const bool is64bits = version == 7500; while (cursor < input + length) { - if (!ReadScope(output_tokens, input, cursor, input + length, version)) { + if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { break; } } From b26fea4cf5b908bba03e026b358a1778559c1dc8 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Mon, 14 Aug 2017 21:51:59 -0700 Subject: [PATCH 03/37] Fix compiling problems under VS2017.3. 1. WordIterator's operator== and operator!= must take const WordIterator& as parameter type. 2. OpenMP doesn't work with new two phase lookups. Need to disable twoPhase. --- CMakeLists.txt | 6 ++++++ code/X3DImporter.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 676a48385..690351e8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,12 @@ find_package(OpenMP) if (OPENMP_FOUND) SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + + IF(MSVC) + IF(MSVC_VERSION GREATER 1910) + SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:twoPhase-") + ENDIF() + ENDIF() endif() CONFIGURE_FILE( diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index 111773563..669f46f95 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -95,8 +95,8 @@ struct WordIterator: public std::iterator end_ = other.end_; return *this; } - bool operator==(WordIterator &other) const { return start_ == other.start_; } - bool operator!=(WordIterator &other) const { return start_ != other.start_; } + bool operator==(const WordIterator &other) const { return start_ == other.start_; } + bool operator!=(const WordIterator &other) const { return start_ != other.start_; } WordIterator &operator++() { start_ += strcspn(start_, whitespace); start_ += strspn(start_, whitespace); From e0fc412e570f6964feb56a96b6b6d218234b10a1 Mon Sep 17 00:00:00 2001 From: Arshia001 Date: Fri, 18 Aug 2017 17:40:07 +0430 Subject: [PATCH 04/37] Fix OBJ discarding all material names if the material library is missing --- code/ObjFileParser.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index dfa77dba2..41677fce5 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -555,10 +555,15 @@ void ObjFileParser::getMaterialDesc() { // Search for material std::map::iterator it = m_pModel->m_MaterialMap.find(strName); if (it == m_pModel->m_MaterialMap.end()) { - // Not found, use default material - m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; - DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); - strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str(); + // Not found, so we don't know anything about the material except for its name. + // This may be the case if the material library is missing. We don't want to lose all + // materials if that happens, so create a new named material instead of discarding it + // completely. + DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", creating new material"); + m_pModel->m_pCurrentMaterial = new ObjFile::Material(); + m_pModel->m_pCurrentMaterial->MaterialName.Set(strName); + m_pModel->m_MaterialLib.push_back(strName); + m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial; } else { // Found, using detected material m_pModel->m_pCurrentMaterial = (*it).second; From 91f6a9a721e56fa026ff62a6722702e74e9bf1fe Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 19 Aug 2017 22:09:30 +0200 Subject: [PATCH 05/37] Readme: add TriLib to the official list of supported ports. --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index d09208203..5a59d0364 100644 --- a/Readme.md +++ b/Readme.md @@ -114,6 +114,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak * [.NET](port/AssimpNET/Readme.md) * [Pascal](port/AssimpPascal/Readme.md) * [Javascript (Alpha)](https://github.com/makc/assimp2json) +* [Unity 3d Plugin] (https://www.assetstore.unity3d.com/en/#!/content/91777) ### Other tools ### [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. From d0d45d1d22fad4ef4026ffca95b7b7916d8a83cc Mon Sep 17 00:00:00 2001 From: Lee Jeffery Date: Sun, 20 Aug 2017 19:07:09 +0100 Subject: [PATCH 06/37] Fix linking issue with irrXML --- contrib/irrXML/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/irrXML/CMakeLists.txt b/contrib/irrXML/CMakeLists.txt index 82ede3a04..980bd99a4 100644 --- a/contrib/irrXML/CMakeLists.txt +++ b/contrib/irrXML/CMakeLists.txt @@ -11,3 +11,7 @@ set( IrrXML_SRCS add_library(IrrXML STATIC ${IrrXML_SRCS}) set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" ) set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" ) + +install(TARGETS IrrXML + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT}) From 2e5e56c000567e7b7cf41d8357343772d818c01c Mon Sep 17 00:00:00 2001 From: Eduardo Costa Date: Mon, 21 Aug 2017 09:27:40 +0100 Subject: [PATCH 07/37] Re-enabling PACK_STRUCT for MDL files. When using this compiler: Apple LLVM version 7.3.0 (clang-703.0.31) Target: x86_64-apple-darwin15.4.0 Thread model: posix The MDL::Frame is aligned in 8-byte boundaries instead of 4. This generates this error when loading old Quake 1 MDL files: ERROR: Failed to load file: Invalid MDL file. The file is too small or contains invalid data (File: MDLLoader.cpp Line: 422) It seems this error was introduced by commit bd2af6591f20fd8777332d510056a037fbfa0df5 due to compilation warnings. --- code/MDLFileData.h | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/code/MDLFileData.h b/code/MDLFileData.h index a691851be..2afea8a95 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -164,7 +164,7 @@ struct Header { //! Could be the total size of the file (and not a float) float size; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -223,7 +223,7 @@ struct Header_MDL7 { //! Size of the Frame_MDL7 data structure used in the file uint16_t frame_stc_size; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -242,7 +242,7 @@ struct Bone_MDL7 { //! Optional name of the bone char name[1 /* DUMMY SIZE */]; -} /* PACK_STRUCT */; +} PACK_STRUCT; #if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS) # define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS (16 + 20) @@ -290,7 +290,7 @@ struct Group_MDL7 { //! Number of frames int32_t numframes; -} /* PACK_STRUCT */; +} PACK_STRUCT; #define AI_MDL7_SKINTYPE_MIPFLAG 0x08 #define AI_MDL7_SKINTYPE_MATERIAL 0x10 @@ -312,7 +312,7 @@ struct Deformer_MDL7 { int32_t group_index; int32_t elements; int32_t deformerdata_size; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -324,7 +324,7 @@ struct DeformerElement_MDL7 { int32_t element_index; char element_name[AI_MDL7_MAX_BONENAMESIZE]; int32_t weights; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct DeformerWeight_MDL7 @@ -334,7 +334,7 @@ struct DeformerWeight_MDL7 { //! for deformer_typ==0 (==bones) index == vertex index int32_t index; float weight; -} /* PACK_STRUCT */; +} PACK_STRUCT; // don't know why this was in the original headers ... typedef int32_t MD7_MATERIAL_ASCDEFSIZE; @@ -345,7 +345,7 @@ typedef int32_t MD7_MATERIAL_ASCDEFSIZE; */ struct ColorValue_MDL7 { float r,g,b,a; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Material_MDL7 @@ -366,7 +366,7 @@ struct Material_MDL7 { //! Phong power float Power; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Skin @@ -388,7 +388,7 @@ struct Skin { //! Texture data uint8_t *data; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -399,7 +399,7 @@ struct Skin { struct Skin_MDL5 { int32_t size, width, height; uint8_t *data; -} /* PACK_STRUCT */; +} PACK_STRUCT; // maximum length of texture file name #if (!defined AI_MDL7_MAX_TEXNAMESIZE) @@ -416,7 +416,7 @@ struct Skin_MDL7 { int32_t width; int32_t height; char texture_name[AI_MDL7_MAX_TEXNAMESIZE]; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct RGB565 @@ -426,7 +426,7 @@ struct RGB565 { uint16_t r : 5; uint16_t g : 6; uint16_t b : 5; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct ARGB4 @@ -455,7 +455,7 @@ struct GroupSkin { //! Data of each image uint8_t **data; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct TexCoord @@ -470,7 +470,7 @@ struct TexCoord { //! Texture coordinate in the ty direction int32_t t; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct TexCoord_MDL3 @@ -482,7 +482,7 @@ struct TexCoord_MDL3 { //! position, vertically in range 0..skinheight-1 int16_t v; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct TexCoord_MDL7 @@ -494,7 +494,7 @@ struct TexCoord_MDL7 { //! position, vertically in range 0..1 float v; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct SkinSet_MDL7 @@ -510,7 +510,7 @@ struct SkinSet_MDL7 //! Material index int32_t material; // size 4 -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Triangle @@ -523,7 +523,7 @@ struct Triangle //! Vertex indices int32_t vertex[3]; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Triangle_MDL3 @@ -536,7 +536,7 @@ struct Triangle_MDL3 //! Index of 3 skin vertices in range 0..numskinverts uint16_t index_uv[3]; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Triangle_MDL7 @@ -549,7 +549,7 @@ struct Triangle_MDL7 //! Two skinsets. The second will be used for multi-texturing SkinSet_MDL7 skinsets[2]; -} /* PACK_STRUCT */; +} PACK_STRUCT; #if (!defined AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) # define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV (6+sizeof(SkinSet_MDL7)-sizeof(uint32_t)) @@ -577,7 +577,7 @@ struct Vertex { uint8_t v[3]; uint8_t normalIndex; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -603,7 +603,7 @@ struct Vertex_MDL7 uint8_t norm162index; float norm[3]; }; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct BoneTransform_MDL7 @@ -620,7 +620,7 @@ struct BoneTransform_MDL7 //! I HATE 3DGS AND THE SILLY DEVELOPER WHO DESIGNED //! THIS STUPID FILE FORMAT! int8_t _unused_[2]; -} /* PACK_STRUCT */; +} PACK_STRUCT; #define AI_MDL7_MAX_FRAMENAMESIZE 16 @@ -654,7 +654,7 @@ struct SimpleFrame //! Vertex list of the frame Vertex *verts; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct Frame @@ -667,7 +667,7 @@ struct Frame //! Frame data SimpleFrame frame; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- @@ -684,7 +684,7 @@ struct SimpleFrame_MDLn_SP //! Vertex list of the frame Vertex_MDL4 *verts; -} /* PACK_STRUCT */; +} PACK_STRUCT; // ------------------------------------------------------------------------------------- /** \struct GroupFrame @@ -706,7 +706,7 @@ struct GroupFrame //! List of single frames SimpleFrame *frames; -} /* PACK_STRUCT */; +} PACK_STRUCT; #include "./../include/assimp/Compiler/poppack1.h" From 92beee99245dab00256f02d917845d0e2ce6b030 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Wed, 23 Aug 2017 17:52:53 +0200 Subject: [PATCH 08/37] Collada importer: Add support for line strip primitives --- code/ColladaParser.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index dbbbdcb18..7b6592351 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -2231,7 +2231,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) } #ifdef ASSIMP_BUILD_DEBUG - if (primType != Prim_TriFans && primType != Prim_TriStrips && + if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip && primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'. ai_assert(actualPrimitives == numPrimitives); } @@ -2400,6 +2400,10 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pP size_t numberOfVertices = indices.size() / numOffsets; numPrimitives = numberOfVertices - 2; } + if (pPrimType == Prim_LineStrip) { + size_t numberOfVertices = indices.size() / numOffsets; + numPrimitives = numberOfVertices - 1; + } pMesh->mFaceSize.reserve( numPrimitives); pMesh->mFacePosIndices.reserve( indices.size() / numOffsets); @@ -2416,6 +2420,11 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pP for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); break; + case Prim_LineStrip: + numPoints = 2; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; case Prim_Triangles: numPoints = 3; for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) From 37f5619149952ffdcfd01e7c34e6adb3b8bc6031 Mon Sep 17 00:00:00 2001 From: Mel Massadian Date: Wed, 23 Aug 2017 20:02:58 +0200 Subject: [PATCH 09/37] created a python3 version of the 3dviewer and fixed the / = float in py3 --- port/PyAssimp/pyassimp/helper.py | 54 +- port/PyAssimp/scripts/3d_viewer_py3.py | 1320 ++++++++++++++++++++++++ 2 files changed, 1353 insertions(+), 21 deletions(-) create mode 100755 port/PyAssimp/scripts/3d_viewer_py3.py diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index b281e94cf..4fa01d51d 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -9,6 +9,10 @@ import ctypes from ctypes import POINTER import operator +from distutils.sysconfig import get_python_lib +import re +import sys + try: import numpy except: numpy = None @@ -26,7 +30,15 @@ if os.name=='posix': additional_dirs.append('/usr/lib/x86_64-linux-gnu') additional_dirs.append('/usr/local/lib/') - # note - this won't catch libassimp.so.N.n, but + # check if running from anaconda. + if "conda" or "continuum" in sys.version.lower(): + cur_path = get_python_lib() + pattern = re.compile('.*\/lib\/') + conda_lib = pattern.match(cur_path).group() + logger.info("Adding Anaconda lib path:"+ conda_lib) + additional_dirs.append(conda_lib) + + # note - this won't catch libassimp.so.N.n, but # currently there's always a symlink called # libassimp.so in /usr/local/lib. ext_whitelist.append('.so') @@ -39,7 +51,7 @@ elif os.name=='nt': for dir_candidate in path_dirs: if 'assimp' in dir_candidate.lower(): additional_dirs.append(dir_candidate) - + #print(additional_dirs) def vec2tuple(x): """ Converts a VECTOR3D to a Tuple """ @@ -61,10 +73,10 @@ def transform(vector3, matrix4x4): m2[0]*x + m2[1]*y + m2[2]*z + m2[3], m3[0]*x + m3[1]*y + m3[2]*z + m3[3] ] - + def _inv(matrix4x4): m0,m1,m2,m3 = matrix4x4 - + det = m0[3]*m1[2]*m2[1]*m3[0] - m0[2]*m1[3]*m2[1]*m3[0] - \ m0[3]*m1[1]*m2[2]*m3[0] + m0[1]*m1[3]*m2[2]*m3[0] + \ m0[2]*m1[1]*m2[3]*m3[0] - m0[1]*m1[2]*m2[3]*m3[0] - \ @@ -77,7 +89,7 @@ def _inv(matrix4x4): m0[2]*m1[1]*m2[0]*m3[3] + m0[1]*m1[2]*m2[0]*m3[3] + \ m0[2]*m1[0]*m2[1]*m3[3] - m0[0]*m1[2]*m2[1]*m3[3] - \ m0[1]*m1[0]*m2[2]*m3[3] + m0[0]*m1[1]*m2[2]*m3[3] - + return[[( m1[2]*m2[3]*m3[1] - m1[3]*m2[2]*m3[1] + m1[3]*m2[1]*m3[2] - m1[1]*m2[3]*m3[2] - m1[2]*m2[1]*m3[3] + m1[1]*m2[2]*m3[3]) /det, ( m0[3]*m2[2]*m3[1] - m0[2]*m2[3]*m3[1] - m0[3]*m2[1]*m3[2] + m0[1]*m2[3]*m3[2] + m0[2]*m2[1]*m3[3] - m0[1]*m2[2]*m3[3]) /det, ( m0[2]*m1[3]*m3[1] - m0[3]*m1[2]*m3[1] + m0[3]*m1[1]*m3[2] - m0[1]*m1[3]*m3[2] - m0[2]*m1[1]*m3[3] + m0[1]*m1[2]*m3[3]) /det, @@ -94,7 +106,7 @@ def _inv(matrix4x4): ( m0[1]*m2[2]*m3[0] - m0[2]*m2[1]*m3[0] + m0[2]*m2[0]*m3[1] - m0[0]*m2[2]*m3[1] - m0[1]*m2[0]*m3[2] + m0[0]*m2[1]*m3[2]) /det, ( m0[2]*m1[1]*m3[0] - m0[1]*m1[2]*m3[0] - m0[2]*m1[0]*m3[1] + m0[0]*m1[2]*m3[1] + m0[1]*m1[0]*m3[2] - m0[0]*m1[1]*m3[2]) /det, ( m0[1]*m1[2]*m2[0] - m0[2]*m1[1]*m2[0] + m0[2]*m1[0]*m2[1] - m0[0]*m1[2]*m2[1] - m0[1]*m1[0]*m2[2] + m0[0]*m1[1]*m2[2]) /det]] - + def get_bounding_box(scene): bb_min = [1e10, 1e10, 1e10] # x,y,z bb_max = [-1e10, -1e10, -1e10] # x,y,z @@ -129,7 +141,7 @@ def get_bounding_box_for_node(node, bb_min, bb_max, transformation): t3[0]*T0[2] + t3[1]*T1[2] + t3[2]*T2[2] + t3[3]*T3[2], t3[0]*T0[3] + t3[1]*T1[3] + t3[2]*T2[3] + t3[3]*T3[3] ] ] - + for mesh in node.meshes: for v in mesh.vertices: v = transform(v, transformation) @@ -149,25 +161,25 @@ def get_bounding_box_for_node(node, bb_min, bb_max, transformation): def try_load_functions(library_path, dll): ''' Try to bind to aiImportFile and aiReleaseImport - + Arguments --------- library_path: path to current lib dll: ctypes handle to library - + Returns --------- If unsuccessful: None If successful: - Tuple containing (library_path, + Tuple containing (library_path, load from filename function, load from memory function, export to filename function, - release function, + release function, ctypes handle to assimp library) ''' - + try: load = dll.aiImportFile release = dll.aiReleaseImport @@ -176,7 +188,7 @@ def try_load_functions(library_path, dll): except AttributeError: #OK, this is a library, but it doesn't have the functions we need return None - + # library found! from .structs import Scene load.restype = POINTER(Scene) @@ -185,13 +197,13 @@ def try_load_functions(library_path, dll): def search_library(): ''' - Loads the assimp library. + Loads the assimp library. Throws exception AssimpError if no library_path is found - - Returns: tuple, (load from filename function, + + Returns: tuple, (load from filename function, load from memory function, export to filename function, - release function, + release function, dll) ''' #this path @@ -201,7 +213,7 @@ def search_library(): try: ctypes.windll.kernel32.SetErrorMode(0x8007) except AttributeError: - pass + pass candidates = [] # test every file @@ -209,7 +221,7 @@ def search_library(): if os.path.isdir(curfolder): for filename in os.listdir(curfolder): # our minimum requirement for candidates is that - # they should contain 'assimp' somewhere in + # they should contain 'assimp' somewhere in # their name if filename.lower().find('assimp')==-1 or\ os.path.splitext(filename)[-1].lower() not in ext_whitelist: @@ -248,10 +260,10 @@ def hasattr_silent(object, name): """ Calls hasttr() with the given parameters and preserves the legacy (pre-Python 3.2) functionality of silently catching exceptions. - + Returns the result of hasatter() or False if an exception was raised. """ - + try: return hasattr(object, name) except: diff --git a/port/PyAssimp/scripts/3d_viewer_py3.py b/port/PyAssimp/scripts/3d_viewer_py3.py new file mode 100755 index 000000000..4e4ecebe8 --- /dev/null +++ b/port/PyAssimp/scripts/3d_viewer_py3.py @@ -0,0 +1,1320 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +""" This program loads a model with PyASSIMP, and display it. + +Based on: +- pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 +- http://www.lighthouse3d.com/tutorials +- http://www.songho.ca/opengl/gl_transform.html +- http://code.activestate.com/recipes/325391/ +- ASSIMP's C++ SimpleOpenGL viewer + +Authors: Séverin Lemaignan, 2012-2016 +""" +import sys +import logging + +from functools import reduce + +logger = logging.getLogger("pyassimp") +gllogger = logging.getLogger("OpenGL") +gllogger.setLevel(logging.WARNING) +logging.basicConfig(level=logging.INFO) + +import OpenGL + +OpenGL.ERROR_CHECKING = False +OpenGL.ERROR_LOGGING = False +# OpenGL.ERROR_ON_COPY = True +# OpenGL.FULL_LOGGING = True +from OpenGL.GL import * +from OpenGL.arrays import vbo +from OpenGL.GL import shaders + +import pygame +import pygame.font +import pygame.image + +import math, random +from numpy import linalg + +import pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * +import transformations + +ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) + +# rendering mode +BASE = "BASE" +COLORS = "COLORS" +SILHOUETTE = "SILHOUETTE" +HELPERS = "HELPERS" + +# Entities type +ENTITY = "entity" +CAMERA = "camera" +MESH = "mesh" + +FLAT_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; + +varying vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +FLAT_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; + +out vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; +attribute vec3 a_normal; + +varying vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; +in vec3 a_normal; + +out vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_FRAGMENT_SHADER_120 = """ +#version 120 + +varying vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +BASIC_FRAGMENT_SHADER_130 = """ +#version 130 + +in vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +GOOCH_VERTEX_SHADER_120 = """ +#version 120 + +// attributes +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_VERTEX_SHADER_130 = """ +#version 130 + +// attributes +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +out vec3 o_normal; +out vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_FRAGMENT_SHADER_120 = """ +#version 120 + +// data from vertex shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + gl_FragColor.rgb = colorOut; + gl_FragColor.a = 1; +} +""" + +GOOCH_FRAGMENT_SHADER_130 = """ +#version 130 + +// data from vertex shader +in vec3 o_normal; +in vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +// output to framebuffer +out vec4 resultingColor; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + resultingColor.rgb = colorOut; + resultingColor.a = 1; +} +""" + +SILHOUETTE_VERTEX_SHADER_120 = """ +#version 120 + +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +varying vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" + +SILHOUETTE_VERTEX_SHADER_130 = """ +#version 130 + +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +out vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" +DEFAULT_CLIP_PLANE_NEAR = 0.001 +DEFAULT_CLIP_PLANE_FAR = 1000.0 + + +def get_world_transform(scene, node): + if node == scene.rootnode: + return numpy.identity(4, dtype=numpy.float32) + + parents = reversed(_get_parent_chain(scene, node, [])) + parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) + return numpy.dot(parent_transform, node.transformation) + + +def _get_parent_chain(scene, node, parents): + parent = node.parent + + parents.append(parent) + + if parent == scene.rootnode: + return parents + + return _get_parent_chain(scene, parent, parents) + + +class DefaultCamera: + def __init__(self, w, h, fov): + self.name = "default camera" + self.type = CAMERA + self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR + self.clipplanefar = DEFAULT_CLIP_PLANE_FAR + self.aspect = w / h + self.horizontalfov = fov * math.pi / 180 + self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], + [0.73, 0.31, -0.61, -6.51], + [-0.01, 0.89, 0.44, 5.34], + [0., 0., 0., 1.]], dtype=numpy.float32) + + self.transformation = numpy.dot(self.transformation, ROTATION_180_X) + + def __str__(self): + return self.name + + +class PyAssimp3DViewer: + base_name = "PyASSIMP 3D viewer" + + def __init__(self, model, w=1024, h=768): + + self.w = w + self.h = h + + pygame.init() + pygame.display.set_caption(self.base_name) + pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) + + glClearColor(0.18, 0.18, 0.18, 1.0) + + shader_compilation_succeeded = False + try: + self.set_shaders_v130() + self.prepare_shaders() + except RuntimeError, message: + sys.stderr.write("%s\n" % message) + sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") + + if not shader_compilation_succeeded: + self.set_shaders_v120() + self.prepare_shaders() + + self.scene = None + self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers + + self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking + self.colorid2node = {} # reverse dict of node2colorid + + self.currently_selected = None + self.moving = False + self.moving_situation = None + + self.default_camera = DefaultCamera(self.w, self.h, fov=70) + self.cameras = [self.default_camera] + + self.current_cam_index = 0 + self.current_cam = self.default_camera + self.set_camera_projection() + + self.load_model(model) + + # user interactions + self.focal_point = [0, 0, 0] + self.is_rotating = False + self.is_panning = False + self.is_zooming = False + + def set_shaders_v120(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 + + def set_shaders_v130(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 + + def prepare_shaders(self): + + ### Base shader + vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) + fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + + self.shader = shaders.compileProgram(vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse'), + ('a_vertex', + 'a_normal'), self.shader) + + ### Flat shader + flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) + self.flatshader = shaders.compileProgram(flatvertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_materialDiffuse',), + ('a_vertex',), self.flatshader) + + ### Silhouette shader + silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) + self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_modelViewMatrix', + 'u_materialDiffuse', + 'u_bordersize' # width of the silhouette + ), + ('a_vertex', + 'a_normal'), self.silhouette_shader) + + ### Gooch shader + gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) + gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse', + 'u_coolColor', + 'u_warmColor', + 'u_alpha', + 'u_beta' + ), + ('a_vertex', + 'a_normal'), self.gooch_shader) + + @staticmethod + def set_shader_accessors(uniforms, attributes, shader): + # add accessors to the shaders uniforms and attributes + for uniform in uniforms: + location = glGetUniformLocation(shader, uniform) + if location in (None, -1): + raise RuntimeError('No uniform: %s (maybe it is not used ' + 'anymore and has been optimized out by' + ' the shader compiler)' % uniform) + setattr(shader, uniform, location) + + for attribute in attributes: + location = glGetAttribLocation(shader, attribute) + if location in (None, -1): + raise RuntimeError('No attribute: %s' % attribute) + setattr(shader, attribute, location) + + @staticmethod + def prepare_gl_buffers(mesh): + + mesh.gl = {} + + # Fill the buffer for vertex and normals positions + v = numpy.array(mesh.vertices, 'f') + n = numpy.array(mesh.normals, 'f') + + mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) + + # Fill the buffer for vertex positions + mesh.gl["faces"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + numpy.array(mesh.faces, dtype=numpy.int32), + GL_STATIC_DRAW) + + mesh.gl["nbfaces"] = len(mesh.faces) + + # Unbind buffers + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + @staticmethod + def get_rgb_from_colorid(colorid): + r = (colorid >> 0) & 0xff + g = (colorid >> 8) & 0xff + b = (colorid >> 16) & 0xff + + return r, g, b + + def get_color_id(self): + id = random.randint(0, 256 * 256 * 256) + if id not in self.colorid2node: + return id + else: + return self.get_color_id() + + def glize(self, scene, node): + + logger.info("Loading node <%s>" % node) + node.selected = True if self.currently_selected and self.currently_selected == node else False + + node.transformation = node.transformation.astype(numpy.float32) + + if node.meshes: + node.type = MESH + colorid = self.get_color_id() + self.colorid2node[colorid] = node + self.node2colorid[node.name] = colorid + + elif node.name in [c.name for c in scene.cameras]: + + # retrieve the ASSIMP camera object + [cam] = [c for c in scene.cameras if c.name == node.name] + node.type = CAMERA + logger.info("Added camera <%s>" % node.name) + logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) + self.cameras.append(node) + node.clipplanenear = cam.clipplanenear + node.clipplanefar = cam.clipplanefar + + if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files + + # Rotate by 180deg around X to have Z pointing forward + node.transformation = numpy.dot(node.transformation, ROTATION_180_X) + else: + raise RuntimeError( + "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) + + if cam.aspect == 0.0: + logger.warning("Camera aspect not set. Setting to default 4:3") + node.aspect = 1.333 + else: + node.aspect = cam.aspect + + node.horizontalfov = cam.horizontalfov + + else: + node.type = ENTITY + + for child in node.children: + self.glize(scene, child) + + def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, processing=postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + # log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + self.glize(scene, scene.rootnode) + + # Finally release the model + pyassimp.release(scene) + logger.info("Ready for 3D rendering!") + + def cycle_cameras(self): + + self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) + self.current_cam = self.cameras[self.current_cam_index] + self.set_camera_projection(self.current_cam) + logger.info("Switched to camera <%s>" % self.current_cam) + + def set_overlay_projection(self): + glViewport(0, 0, self.w, self.h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def set_camera_projection(self, camera=None): + + if not camera: + camera = self.current_cam + + znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR + zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov / 2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + + self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def render_colors(self): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + glEnable(GL_CULL_FACE) + + glUseProgram(self.flatshader) + + glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) + + glUseProgram(0) + + def get_hovered_node(self, mousex, mousey): + """ + Attention: The performances of this method relies heavily on the size of the display! + """ + + # mouse out of the window? + if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: + return None + + self.render_colors() + # Capture image from the OpenGL buffer + buf = (GLubyte * (3 * self.w * self.h))(0) + glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) + + # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors + a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) + colors = numpy.zeros(len(buf) // 3, numpy.dtype('u1')[i::3] + + colorid = colors[mousex + mousey * self.w] + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if colorid in self.colorid2node: + return self.colorid2node[colorid] + + def render(self, wireframe=False, twosided=False): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + self.render_grid() + + self.recursive_render(self.scene.rootnode, None, mode=HELPERS) + + ### First, the silhouette + + if False: + shader = self.silhouette_shader + + # glDepthMask(GL_FALSE) + glCullFace(GL_FRONT) # cull front faces + + glUseProgram(shader) + glUniform1f(shader.u_bordersize, 0.01) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) + + glUseProgram(0) + + ### Then, inner shading + # glDepthMask(GL_TRUE) + glCullFace(GL_BACK) + + use_gooch = False + if use_gooch: + shader = self.gooch_shader + + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + ##### GOOCH specific + glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) + glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) + glUniform1f(shader.u_alpha, .25) + glUniform1f(shader.u_beta, .25) + ######### + else: + shader = self.shader + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader) + + glUseProgram(0) + + def render_axis(self, + transformation=numpy.identity(4, dtype=numpy.float32), + label=None, + size=0.2, + selected=False): + m = transformation.transpose() # OpenGL row major + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(3 if selected else 1) + + size = 2 * size if selected else size + + glBegin(GL_LINES) + + # draw line for x axis + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(size, 0.0, 0.0) + + # draw line for y axis + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, size, 0.0) + + # draw line for Z axis + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, size) + + glEnd() + + if label: + self.showtext(label) + + glPopMatrix() + + @staticmethod + def render_camera(camera, transformation): + + m = transformation.transpose() # OpenGL row major + + aspect = camera.aspect + + u = 0.1 # unit size (in m) + l = 3 * u # lenght of the camera cone + f = 3 * u # aperture of the camera cone + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(2) + glBegin(GL_LINE_STRIP) + + glColor3f(.2, .2, .2) + + glVertex3f(u, u, -u) + glVertex3f(u, -u, -u) + glVertex3f(-u, -u, -u) + glVertex3f(-u, u, -u) + glVertex3f(u, u, -u) + + glVertex3f(u, u, 0.0) + glVertex3f(u, -u, 0.0) + glVertex3f(-u, -u, 0.0) + glVertex3f(-u, u, 0.0) + glVertex3f(u, u, 0.0) + + glVertex3f(f * aspect, f, l) + glVertex3f(f * aspect, -f, l) + glVertex3f(-f * aspect, -f, l) + glVertex3f(-f * aspect, f, l) + glVertex3f(f * aspect, f, l) + + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(u, -u, -u) + glVertex3f(u, -u, 0.0) + glVertex3f(f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, -u, -u) + glVertex3f(-u, -u, 0.0) + glVertex3f(-f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, u, -u) + glVertex3f(-u, u, 0.0) + glVertex3f(-f * aspect, f, l) + glEnd() + + glPopMatrix() + + @staticmethod + def render_grid(): + + glLineWidth(1) + glColor3f(0.5, 0.5, 0.5) + glBegin(GL_LINES) + for i in range(-10, 11): + glVertex3f(i, -10.0, 0.0) + glVertex3f(i, 10.0, 0.0) + + for i in range(-10, 11): + glVertex3f(-10.0, i, 0.0) + glVertex3f(10.0, i, 0.0) + glEnd() + + def recursive_render(self, node, shader, mode=BASE, with_normals=True): + """ Main recursive rendering method. + """ + + normals = with_normals + + if mode == COLORS: + normals = False + + + if not hasattr(node, "selected"): + node.selected = False + + m = get_world_transform(self.scene, node) + + # HELPERS mode + ### + if mode == HELPERS: + # if node.type == ENTITY: + self.render_axis(m, + label=node.name if node != self.scene.rootnode else None, + selected=node.selected if hasattr(node, "selected") else False) + + if node.type == CAMERA: + self.render_camera(node, m) + + for child in node.children: + self.recursive_render(child, shader, mode) + + return + + # Mesh rendering modes + ### + if node.type == MESH: + + for mesh in node.meshes: + + stride = 24 # 6 * 4 bytes + + if node.selected and mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) + glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, + numpy.dot(self.view_matrix, m)) + + else: + if mode == COLORS: + colorid = self.node2colorid[node.name] + r, g, b = self.get_rgb_from_colorid(colorid) + glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) + elif mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) + else: + if node.selected: + diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red + else: + diffuse = mesh.material.properties["diffuse"] + if len(diffuse) == 3: # RGB instead of expected RGBA + diffuse.append(1.0) + glUniform4f(shader.u_materialDiffuse, *diffuse) + # if ambient: + # glUniform4f( shader.Material_ambient, *mat["ambient"] ) + + if mode == BASE: # not in COLORS or SILHOUETTE + normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() + glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) + + glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) + + vbo = mesh.gl["vbo"] + vbo.bind() + + glEnableVertexAttribArray(shader.a_vertex) + if normals: + glEnableVertexAttribArray(shader.a_normal) + + glVertexAttribPointer( + shader.a_vertex, + 3, GL_FLOAT, False, stride, vbo + ) + + if normals: + glVertexAttribPointer( + shader.a_normal, + 3, GL_FLOAT, False, stride, vbo + 12 + ) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) + + vbo.unbind() + glDisableVertexAttribArray(shader.a_vertex) + + if normals: + glDisableVertexAttribArray(shader.a_normal) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child, shader, mode) + + + def switch_to_overlay(self): + glPushMatrix() + self.set_overlay_projection() + + def switch_from_overlay(self): + self.set_camera_projection() + glPopMatrix() + + def select_node(self, node): + self.currently_selected = node + self.update_node_select(self.scene.rootnode) + + def update_node_select(self, node): + if node is self.currently_selected: + node.selected = True + else: + node.selected = False + + for child in node.children: + self.update_node_select(child) + + def loop(self): + + pygame.display.flip() + + if not self.process_events(): + return False # ESC has been pressed + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + return True + + def process_events(self): + + LEFT_BUTTON = 1 + MIDDLE_BUTTON = 2 + RIGHT_BUTTON = 3 + WHEEL_UP = 4 + WHEEL_DOWN = 5 + + dx, dy = pygame.mouse.get_rel() + mousex, mousey = pygame.mouse.get_pos() + + zooming_one_shot = False + + ok = True + + for evt in pygame.event.get(): + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: + hovered = self.get_hovered_node(mousex, self.h - mousey) + if hovered: + if self.currently_selected and self.currently_selected == hovered: + self.select_node(None) + else: + logger.info("Node %s selected" % hovered) + self.select_node(hovered) + else: + self.is_rotating = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: + self.is_rotating = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: + self.is_panning = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: + self.is_panning = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: + self.is_zooming = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: + self.is_zooming = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: + zooming_one_shot = True + self.is_zooming = True + dy = -10 if evt.button == WHEEL_UP else 10 + + if evt.type == pygame.KEYDOWN: + ok = (ok and self.process_keystroke(evt.key, evt.mod)) + + self.controls_3d(dx, dy, zooming_one_shot) + + return ok + + def process_keystroke(self, key, mod): + + # process arrow keys if an object is selected + if self.currently_selected: + up = 0 + strafe = 0 + + if key == pygame.K_UP: + up = 1 + if key == pygame.K_DOWN: + up = -1 + if key == pygame.K_LEFT: + strafe = -1 + if key == pygame.K_RIGHT: + strafe = 1 + + self.move_selected_node(up, strafe) + + if key == pygame.K_f: + pygame.display.toggle_fullscreen() + + if key == pygame.K_TAB: + self.cycle_cameras() + + if key in [pygame.K_ESCAPE, pygame.K_q]: + return False + + return True + + def controls_3d(self, dx, dy, zooming_one_shot=False): + + CAMERA_TRANSLATION_FACTOR = 0.01 + CAMERA_ROTATION_FACTOR = 0.01 + + if not (self.is_rotating or self.is_panning or self.is_zooming): + return + + current_pos = self.current_cam.transformation[:3, 3].copy() + distance = numpy.linalg.norm(self.focal_point - current_pos) + + if self.is_rotating: + """ Orbiting the camera is implemented the following way: + + - the rotation is split into a rotation around the *world* Z axis + (controlled by the horizontal mouse motion along X) and a + rotation around the *X* axis of the camera (pitch) *shifted to + the focal origin* (the world origin for now). This is controlled + by the vertical motion of the mouse (Y axis). + + - as a result, the resulting transformation of the camera in the + world frame C' is: + C' = (T · Rx · T⁻¹ · (Rz · C)⁻¹)⁻¹ + + where: + - C is the original camera transformation in the world frame, + - Rz is the rotation along the Z axis (in the world frame) + - T is the translation camera -> world (ie, the inverse of the + translation part of C + - Rx is the rotation around X in the (translated) camera frame + """ + + rotation_camera_x = dy * CAMERA_ROTATION_FACTOR + rotation_world_z = dx * CAMERA_ROTATION_FACTOR + world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) + cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) + + after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) + + inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) + + translation = transformations.translation_matrix( + transformations.decompose_matrix(inverse_transformation)[3]) + inverse_translation = transformations.inverse_matrix(translation) + + new_inverse = numpy.dot(inverse_translation, inverse_transformation) + new_inverse = numpy.dot(cam_x_rotation, new_inverse) + new_inverse = numpy.dot(translation, new_inverse) + + self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) + + if self.is_panning: + tx = -dx * CAMERA_TRANSLATION_FACTOR * distance + ty = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if self.is_zooming: + tz = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if zooming_one_shot: + self.is_zooming = False + + self.update_view_camera() + + def update_view_camera(self): + + self.view_matrix = linalg.inv(self.current_cam.transformation) + + # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) + self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + glMultMatrixf(self.view_matrix.transpose()) + + def move_selected_node(self, up, strafe): + self.currently_selected.transformation[0][3] += strafe + self.currently_selected.transformation[2][3] += up + + @staticmethod + def showtext(text, x=0, y=0, z=0, size=20): + + # TODO: alpha blending does not work... + # glEnable(GL_BLEND) + # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + font = pygame.font.Font(None, size) + text_surface = font.render(text, True, (10, 10, 10, 255), + (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) + text_data = pygame.image.tostring(text_surface, "RGBA", True) + glRasterPos3d(x, y, z) + glDrawPixels(text_surface.get_width(), + text_surface.get_height(), + GL_RGBA, GL_UNSIGNED_BYTE, + text_data) + + # glDisable(GL_BLEND) + + +def main(model, width, height): + app = PyAssimp3DViewer(model, w=width, h=height) + + clock = pygame.time.Clock() + + while app.loop(): + + app.update_view_camera() + + ## Main rendering + app.render() + + ## GUI text display + app.switch_to_overlay() + app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) + if app.currently_selected: + app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) + pos = app.h - 70 + + app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], + app.currently_selected.transformation[1, 3], + app.currently_selected.transformation[2, 3]), 30, pos) + + app.switch_from_overlay() + + # Make sure we do not go over 30fps + clock.tick(30) + + logger.info("Quitting! Bye bye!") + + +######################################################################### +######################################################################### + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " ") + sys.exit(2) + + main(model=sys.argv[1], width=1024, height=768) From 7182f89a518482c4d943ea532c2249883b8037ef Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Thu, 24 Aug 2017 14:40:53 +0200 Subject: [PATCH 10/37] FBX importer: Use actual min/max of animation keyframes when start/stop time is missing --- code/FBXConverter.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index ebe7ac4e6..ae98d24fd 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2368,8 +2368,13 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) int64_t start_time = st.LocalStart(); int64_t stop_time = st.LocalStop(); - double start_timeF = CONVERT_FBX_TIME( start_time ); - double stop_timeF = CONVERT_FBX_TIME( stop_time ); + bool has_local_startstop = start_time != 0 || stop_time != 0; + if ( !has_local_startstop ) { + // no time range given, so accept every keyframe and use the actual min/max time + // the +/- 20000 is a safety because GenerateNodeAnimations uses an epsilon of 10000 + start_time = INT64_MIN + 20000; + stop_time = INT64_MAX - 20000; + } try { for( const NodeMap::value_type& kv : node_map ) { @@ -2401,27 +2406,23 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) return; } - //adjust relative timing for animation - { - double start_fps = start_timeF * anim_fps; + double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; + double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; - for ( unsigned int c = 0; c < anim->mNumChannels; c++ ) - { - aiNodeAnim* channel = anim->mChannels[ c ]; - for ( uint32_t i = 0; i < channel->mNumPositionKeys; i++ ) - channel->mPositionKeys[ i ].mTime -= start_fps; - for ( uint32_t i = 0; i < channel->mNumRotationKeys; i++ ) - channel->mRotationKeys[ i ].mTime -= start_fps; - for ( uint32_t i = 0; i < channel->mNumScalingKeys; i++ ) - channel->mScalingKeys[ i ].mTime -= start_fps; - } - - max_time -= min_time; + // adjust relative timing for animation + for ( unsigned int c = 0; c < anim->mNumChannels; c++ ) { + aiNodeAnim* channel = anim->mChannels[ c ]; + for ( uint32_t i = 0; i < channel->mNumPositionKeys; i++ ) + channel->mPositionKeys[ i ].mTime -= start_time_fps; + for ( uint32_t i = 0; i < channel->mNumRotationKeys; i++ ) + channel->mRotationKeys[ i ].mTime -= start_time_fps; + for ( uint32_t i = 0; i < channel->mNumScalingKeys; i++ ) + channel->mScalingKeys[ i ].mTime -= start_time_fps; } // for some mysterious reason, mDuration is simply the maximum key -- the // validator always assumes animations to start at zero. - anim->mDuration = ( stop_timeF - start_timeF ) * anim_fps; + anim->mDuration = stop_time_fps - start_time_fps; anim->mTicksPerSecond = anim_fps; } From e90c615c2714d07acaae7c7e66fbe15873e95b6f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 24 Aug 2017 17:03:41 +0200 Subject: [PATCH 11/37] Update Readme.md use new patreon badge. --- Readme.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 5a59d0364..88dc6fbc3 100644 --- a/Readme.md +++ b/Readme.md @@ -8,7 +8,6 @@ A library to import and export various 3d-model-formats including scene-post-pro Coverity Scan Build Status -Patreon donate button [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master) [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -19,6 +18,11 @@ Additionally, assimp features various __mesh post processing tools__: normals an This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). +Monthly donations via Patreon: +
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp) + +
+ One-off donations via PayPal:
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4) From 80489963a15de3eea59810dbdbdeabdd6c103501 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Thu, 24 Aug 2017 17:18:54 +0200 Subject: [PATCH 12/37] FBX importer: don't rely ont INT64_MIN / ..MAX macros --- code/FBXConverter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index ae98d24fd..bbf0e4e11 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2371,9 +2371,9 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) bool has_local_startstop = start_time != 0 || stop_time != 0; if ( !has_local_startstop ) { // no time range given, so accept every keyframe and use the actual min/max time - // the +/- 20000 is a safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = INT64_MIN + 20000; - stop_time = INT64_MAX - 20000; + // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 + start_time = -9223372036854775807i64 + 20000; + stop_time = 9223372036854775807i64 - 20000; } try { From 9a12b6ef0bbff90a69030a2cfa7a8b8756b904b5 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Fri, 25 Aug 2017 11:17:07 +0200 Subject: [PATCH 13/37] FBX importer: Back to INT64_MIN but include also. --- code/FBXConverter.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index bbf0e4e11..d6b21daed 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -61,6 +61,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + namespace Assimp { namespace FBX { @@ -2371,9 +2373,9 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) bool has_local_startstop = start_time != 0 || stop_time != 0; if ( !has_local_startstop ) { // no time range given, so accept every keyframe and use the actual min/max time - // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = -9223372036854775807i64 + 20000; - stop_time = 9223372036854775807i64 - 20000; + // the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 + start_time = INT64_MIN + 20000; + stop_time = INT64_MAX - 20000; } try { From 12a28d33ce205c9ed61fa14e5687e679f820d6e4 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Fri, 25 Aug 2017 12:14:03 +0200 Subject: [PATCH 14/37] FBX importer: try a constant again (ll suffix this time) --- code/FBXConverter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index d6b21daed..f53ae0218 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -61,8 +61,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include - namespace Assimp { namespace FBX { @@ -2373,9 +2371,9 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) bool has_local_startstop = start_time != 0 || stop_time != 0; if ( !has_local_startstop ) { // no time range given, so accept every keyframe and use the actual min/max time - // the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = INT64_MIN + 20000; - stop_time = INT64_MAX - 20000; + // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 + start_time = -9223372036854775807ll + 20000; + stop_time = 9223372036854775807ll - 20000; } try { From f8ef94095a460beacfd7574d74237dde4ae1bc9c Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Tue, 29 Aug 2017 15:41:25 +0200 Subject: [PATCH 15/37] Update version check in FBX reader to check for version >= 7500 instead of exactly 7500. --- code/FBXBinaryTokenizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index d388c6446..46e85d888 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -445,7 +445,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le const uint8_t unknown_4 = ReadByte(input, cursor, input + length); const uint8_t unknown_5 = ReadByte(input, cursor, input + length); const uint32_t version = ReadWord(input, cursor, input + length); - const bool is64bits = version == 7500; + const bool is64bits = version >= 7500; while (cursor < input + length) { if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { From 1e3a9ded112cb8fb8a438a1d57111a6683f22c13 Mon Sep 17 00:00:00 2001 From: THISISAGOODNAME Date: Wed, 30 Aug 2017 23:18:36 +0800 Subject: [PATCH 16/37] Fix assimp_qt_viewer build failed on OSX --- tools/assimp_qt_viewer/glview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp index caf4ef320..429f2ca99 100644 --- a/tools/assimp_qt_viewer/glview.cpp +++ b/tools/assimp_qt_viewer/glview.cpp @@ -6,7 +6,11 @@ #include "glview.hpp" // Header files, OpenGL. -#include +#if defined(__APPLE__) +# include +#else +# include +#endif // Header files, DevIL. #include From 00e3b03c5ba2fbb0af21d42a9b6a54b512b19ba9 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 11:04:13 +0200 Subject: [PATCH 17/37] closes https://github.com/assimp/assimp/issues/1406: fix merge issue + improve 3MF-tests --- code/D3MFImporter.cpp | 8 ++------ test/unit/utD3MFImportExport.cpp | 11 +++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 0f06d4a1e..e97e22859 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -95,14 +95,10 @@ public: XmlSerializer(XmlReader* xmlReader) : xmlReader(xmlReader) { - + // empty } - void ImportXml(aiScene* scene) - { - - scene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - + void ImportXml(aiScene* scene) { scene->mRootNode = new aiNode(); std::vector children; diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index 7b7e8fb11..b77f44f86 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -43,13 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AbstractImportExportBase.h" #include +#include class utD3MFImporterExporter : public AbstractImportExportBase { public: - virtual bool importerTest() { + bool importerTest() override { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3MF/box.3mf", 0); - return nullptr != scene; + EXPECT_EQ( 1u, scene->mNumMeshes ); + aiMesh *mesh = scene->mMeshes[ 0 ]; + EXPECT_NE( nullptr, mesh ); + EXPECT_EQ( 12u, mesh->mNumFaces ); + EXPECT_EQ( 8u, mesh->mNumVertices ); + + return ( nullptr != scene ); } }; From b4da9c4f56b10aff0a27da5561931aec623ac8b2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 11:30:31 +0200 Subject: [PATCH 18/37] Fix review findings: remove unused includes --- code/Q3BSPZipArchive.cpp | 5 ----- code/Q3BSPZipArchive.h | 1 - 2 files changed, 6 deletions(-) diff --git a/code/Q3BSPZipArchive.cpp b/code/Q3BSPZipArchive.cpp index 86f399659..7428c04c3 100644 --- a/code/Q3BSPZipArchive.cpp +++ b/code/Q3BSPZipArchive.cpp @@ -39,14 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - - #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER #include "Q3BSPZipArchive.h" -#include #include -#include #include namespace Assimp { @@ -137,7 +133,6 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) { return mapping; } -// ------------------------------------------------------------------------------------------------ ZipFile::ZipFile(size_t size) : m_Size(size) { ai_assert(m_Size != 0); diff --git a/code/Q3BSPZipArchive.h b/code/Q3BSPZipArchive.h index 280c44fc0..5430bac6f 100644 --- a/code/Q3BSPZipArchive.h +++ b/code/Q3BSPZipArchive.h @@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #include #include From 11f70e21404ac9d199088c36bbdbc6c2871ae4a8 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 11:39:10 +0200 Subject: [PATCH 19/37] Tests: add 3D-importer test. --- test/CMakeLists.txt | 1 + test/unit/utOpenGEXImportExport.cpp | 2 - test/unit/utQ3DImportExport.cpp | 61 +++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 test/unit/utQ3DImportExport.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2d065e3be..8627efe14 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -130,6 +130,7 @@ SET( TEST_SRCS unit/utVector3.cpp unit/utXImporterExporter.cpp unit/utD3MFImportExport.cpp + unit/utQ3DImportExport.cpp unit/utProfiler.cpp ) diff --git a/test/unit/utOpenGEXImportExport.cpp b/test/unit/utOpenGEXImportExport.cpp index 60e8ce3a2..021a7bf81 100644 --- a/test/unit/utOpenGEXImportExport.cpp +++ b/test/unit/utOpenGEXImportExport.cpp @@ -54,8 +54,6 @@ public: Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OpenGEX/Example.ogex", 0 ); return nullptr != scene; - - return true; } }; diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp new file mode 100644 index 000000000..6d76e001f --- /dev/null +++ b/test/unit/utQ3DImportExport.cpp @@ -0,0 +1,61 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "UnitTestPCH.h" + +#include "AbstractImportExportBase.h" + +#include + +using namespace Assimp; + +class utQ3DImportExport : public AbstractImportExportBase { +public: + bool importerTest() override { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Q3D/earth.q3o", 0); + return nullptr != scene; + } +}; + +TEST_F(utQ3DImportExport, importTest) { + EXPECT_TRUE(importerTest()); +} From 82f0dae8350282b6aac1574660ad7c5bfcf4d865 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 11:53:00 +0200 Subject: [PATCH 20/37] FIx build --- test/unit/utQ3DImportExport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp index 6d76e001f..8f3c52b28 100644 --- a/test/unit/utQ3DImportExport.cpp +++ b/test/unit/utQ3DImportExport.cpp @@ -49,9 +49,9 @@ using namespace Assimp; class utQ3DImportExport : public AbstractImportExportBase { public: - bool importerTest() override { + virtual bool importerTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Q3D/earth.q3o", 0); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/Q3D/earth.q3o", 0 ); return nullptr != scene; } }; From 2df704edef1de3d17b5ca0edd7764f63d2fe9fd7 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 14:06:56 +0200 Subject: [PATCH 21/37] fix the buil --- test/unit/utQ3DImportExport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp index 8f3c52b28..d8195309f 100644 --- a/test/unit/utQ3DImportExport.cpp +++ b/test/unit/utQ3DImportExport.cpp @@ -57,5 +57,5 @@ public: }; TEST_F(utQ3DImportExport, importTest) { - EXPECT_TRUE(importerTest()); + EXPECT_TRUE( importerTest() ); } From f8146e4da261cca2fe7a00eae22e226f3cdf21cb Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 31 Aug 2017 14:15:23 +0200 Subject: [PATCH 22/37] fix the buil --- test/unit/utD3MFImportExport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index b77f44f86..0c322420c 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class utD3MFImporterExporter : public AbstractImportExportBase { public: - bool importerTest() override { + virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3MF/box.3mf", 0); EXPECT_EQ( 1u, scene->mNumMeshes ); From 3de9bbb73d7fe3bae53b73efecadc781d1d7cccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Sat, 2 Sep 2017 19:44:51 +0200 Subject: [PATCH 23/37] fixed spelling error --- code/PlyLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index 090473893..d348fe113 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -538,7 +538,7 @@ void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInst ai_assert(NULL != instElement); if (mGeneratedMesh == NULL) - throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces"); + throw DeadlyImportError("Invalid .ply file: Vertices should be declared before faces"); bool bOne = false; From 042597552acdfa9c837190253cef2c07963f9cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Sat, 2 Sep 2017 19:46:57 +0200 Subject: [PATCH 24/37] split setup.py into multiple lines to make it easier for patching in Debian... --- port/PyAssimp/setup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/port/PyAssimp/setup.py b/port/PyAssimp/setup.py index e683f7a81..26cf9b400 100644 --- a/port/PyAssimp/setup.py +++ b/port/PyAssimp/setup.py @@ -8,6 +8,9 @@ setup(name='pyassimp', description='Python bindings for the Open Asset Import Library (ASSIMP)', url='https://github.com/assimp/assimp', packages=['pyassimp'], - data_files=[('share/pyassimp', ['README.md']), - ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')])], requires=['numpy'] + data_files=[ + ('share/pyassimp', ['README.md']), + ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]) + ], + requires=['numpy'] ) From eb0ace4e185794384c4eefa41d8e83902344082b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Sun, 3 Sep 2017 23:03:48 +0200 Subject: [PATCH 25/37] exclude repository-settings from source-package generated via 'git archive' --- .gitattributes | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitattributes b/.gitattributes index 7f9357f62..f3df90d38 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,3 +13,10 @@ CHANGES text eol=lf CREDITS text eol=lf LICENSE text eol=lf Readme.md text eol=lf +# make sure that repo-specific settings (.gitignore, CI-setup,...) +# are excluded from the source-package generated via 'git archive' +.git* export-ignore +/.travis* export-ignore +/.coveralls* export-ignore +appveyor.yml export-ignore + From c143d2e02cab75cdf5171b6f0dfc42569c061888 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 7 Sep 2017 20:30:17 +0200 Subject: [PATCH 26/37] closes https://github.com/assimp/assimp/issues/1404: set name with merged meshes for output mesh. --- code/3DSConverter.cpp | 9 +++-- code/SceneCombiner.cpp | 16 ++++++-- include/assimp/SceneCombiner.h | 7 +--- test/CMakeLists.txt | 1 + test/unit/utSceneCombiner.cpp | 70 ++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 test/unit/utSceneCombiner.cpp diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index da8c918a7..820c28f90 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -56,18 +56,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; +static const unsigned int NotSet = 0xcdcdcdcd; + // ------------------------------------------------------------------------------------------------ // Setup final material indices, generae a default material if necessary void Discreet3DSImporter::ReplaceDefaultMaterial() { - // Try to find an existing material that matches the // typical default material setting: // - no textures // - diffuse color (in grey!) // NOTE: This is here to workaround the fact that some // exporters are writing a default material, too. - unsigned int idx = 0xcdcdcdcd; + unsigned int idx( NotSet ); for (unsigned int i = 0; i < mScene->mMaterials.size();++i) { std::string s = mScene->mMaterials[i].mName; @@ -93,7 +94,9 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() } idx = i; } - if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); + if ( NotSet == idx ) { + idx = ( unsigned int )mScene->mMaterials.size(); + } // now iterate through all meshes and through all faces and // find all faces that are using the default material diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index 9bcce4275..6fb120325 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "time.h" #include #include +#include #include #include "ScenePrivate.h" @@ -757,7 +758,7 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator // ------------------------------------------------------------------------------------------------ // Merge a list of meshes -void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, +void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/, std::vector::const_iterator begin, std::vector::const_iterator end) { @@ -772,8 +773,14 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, aiMesh* out = *_out = new aiMesh(); out->mMaterialIndex = (*begin)->mMaterialIndex; + std::string name; // Find out how much output storage we'll need - for (std::vector::const_iterator it = begin; it != end;++it) { + for (std::vector::const_iterator it = begin; it != end; ++it) { + const char *meshName( (*it)->mName.C_Str() ); + name += std::string( meshName ); + if ( it != end - 1 ) { + name += "."; + } out->mNumVertices += (*it)->mNumVertices; out->mNumFaces += (*it)->mNumFaces; out->mNumBones += (*it)->mNumBones; @@ -781,6 +788,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, // combine primitive type flags out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; } + out->mName.Set( name.c_str() ); if (out->mNumVertices) { aiVector3D* pv2; @@ -789,7 +797,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, if ((**begin).HasPositions()) { pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) { + for (std::vector::const_iterator it = begin; it != end; ++it) { if ((*it)->mVertices) { ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D)); } @@ -809,7 +817,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, pv2 += (*it)->mNumVertices; } } - // copy tangents and bitangents + // copy tangents and bi-tangents if ((**begin).HasTangentsAndBitangents()) { pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; diff --git a/include/assimp/SceneCombiner.h b/include/assimp/SceneCombiner.h index ca4e68c7f..ebb5dda00 100644 --- a/include/assimp/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -217,10 +217,9 @@ public: static void MergeScenes(aiScene** dest,std::vector& src, unsigned int flags = 0); - // ------------------------------------------------------------------- - /** Merges two or more scenes and attaches all sceenes to a specific - * position in the node graph of the masteer scene. + /** Merges two or more scenes and attaches all scenes to a specific + * position in the node graph of the master scene. * * @param dest Receives a pointer to the destination scene. If the * pointer doesn't point to NULL when the function is called, the @@ -236,7 +235,6 @@ public: std::vector& src, unsigned int flags = 0); - // ------------------------------------------------------------------- /** Merges two or more meshes * @@ -255,7 +253,6 @@ public: std::vector::const_iterator begin, std::vector::const_iterator end); - // ------------------------------------------------------------------- /** Merges two or more bones * diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8627efe14..cb559deb3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -116,6 +116,7 @@ SET( TEST_SRCS unit/utRemoveRedundantMaterials.cpp unit/utRemoveVCProcess.cpp unit/utScenePreprocessor.cpp + unit/utSceneCombiner.cpp unit/utSharedPPData.cpp unit/utStringUtils.cpp unit/utSMDImportExport.cpp diff --git a/test/unit/utSceneCombiner.cpp b/test/unit/utSceneCombiner.cpp new file mode 100644 index 000000000..f0e4d5d90 --- /dev/null +++ b/test/unit/utSceneCombiner.cpp @@ -0,0 +1,70 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "UnitTestPCH.h" +#include +#include + +using namespace ::Assimp; + +class utSceneCombiner : public ::testing::Test { + // empty +}; + +TEST_F( utSceneCombiner, MergeMeshes_ValidNames_Test ) { + std::vector merge_list; + aiMesh *mesh1 = new aiMesh; + mesh1->mName.Set( "mesh_1" ); + merge_list.push_back( mesh1 ); + + aiMesh *mesh2 = new aiMesh; + mesh2->mName.Set( "mesh_2" ); + merge_list.push_back( mesh2 ); + + aiMesh *mesh3 = new aiMesh; + mesh3->mName.Set( "mesh_3" ); + merge_list.push_back( mesh3 ); + + aiMesh *out( nullptr ); + SceneCombiner::MergeMeshes( &out, 0, merge_list.begin(), merge_list.end() ); + std::string outName = out->mName.C_Str(); + EXPECT_EQ( "mesh_1.mesh_2.mesh_3", outName ); +} From e4c15575614e1bd4715443cb502a3afc49cbeef1 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 7 Sep 2017 22:02:09 +0200 Subject: [PATCH 27/37] Traivis: make build amtrix smaller. --- .travis.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index ffebab3cb..38849dae4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,14 +28,16 @@ env: - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc=" - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME} matrix: - - LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON - - LINUX=1 TRAVIS_NO_EXPORT=NO ENABLE_COVERALLS=OFF - - LINUX=1 SHARED_BUILD=ON ENABLE_COVERALLS=OFF - - LINUX=1 SHARED_BUILD=OFF ENABLE_COVERALLS=OFF - -compiler: - - gcc - - clang + - os: linux LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON + compiler: gcc + - os: linux LINUX=1 TRAVIS_NO_EXPORT=NO ENABLE_COVERALLS=OFF + compiler: clang + - os: linux LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO ENABLE_COVERALLS=OFF + compiler: gcc + - os: linux LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO ENABLE_COVERALLS=OFF + compiler: clang + - os: osx + osx_image: xcode8.2 install: - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi From c2baa0f59d06cc670c624c388761dd32ec1b8bee Mon Sep 17 00:00:00 2001 From: Giuseppe Barbieri Date: Fri, 8 Sep 2017 15:46:23 +0200 Subject: [PATCH 28/37] Added a link to pure jvm assimp port --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index 88dc6fbc3..a5c31881a 100644 --- a/Readme.md +++ b/Readme.md @@ -119,6 +119,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak * [Pascal](port/AssimpPascal/Readme.md) * [Javascript (Alpha)](https://github.com/makc/assimp2json) * [Unity 3d Plugin] (https://www.assetstore.unity3d.com/en/#!/content/91777) +* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, ~collada) ### Other tools ### [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. From 2ec46cc1882f5f2ebb4402eee0ff181a7132d169 Mon Sep 17 00:00:00 2001 From: Amit Cirt Date: Sat, 9 Sep 2017 19:04:15 +0300 Subject: [PATCH 29/37] fix name lost in mesh and nodes when load with aiProcess_PreTransformVertices flag --- code/PretransformVertices.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 1339053f7..7bfed4292 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -160,6 +160,11 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; ai_assert(0 != num_ref); --num_ref; + // Save the name of the last mesh + if (num_ref==0) + { + pcMeshOut->mName = pcMesh->mName; + } if (identity) { // copy positions without modifying them @@ -626,9 +631,10 @@ void PretransformVertices::Execute( aiScene* pScene) // now delete all nodes in the scene and build a new // flat node graph with a root node and some level 1 children + aiNode* newRoot = new aiNode(); + newRoot->mName = pScene->mRootNode->mName; delete pScene->mRootNode; pScene->mRootNode = new aiNode(); - pScene->mRootNode->mName.Set(""); if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) { @@ -646,7 +652,7 @@ void PretransformVertices::Execute( aiScene* pScene) { aiNode* pcNode = *nodes = new aiNode(); pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"mesh_%u",i); + pcNode->mName = pScene->mMeshes[i]->mName; // setup mesh indices pcNode->mNumMeshes = 1; From 97b67d5cb5c5ca0ccb9ccf62390dee3dbec1d3ee Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Sun, 10 Sep 2017 18:47:24 +1000 Subject: [PATCH 30/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/AssbinExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp index e97f27a8a..4ea261718 100644 --- a/code/AssbinExporter.cpp +++ b/code/AssbinExporter.cpp @@ -325,7 +325,7 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); - size_t nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); + unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); Write(&chunk,node->mName); Write(&chunk,node->mTransformation); From 98532b45bfab304e579c7aef0b16a6cd00142500 Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Sun, 10 Sep 2017 19:04:44 +1000 Subject: [PATCH 31/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/ColladaExporter.cpp | 10 +++++----- code/ColladaLoader.cpp | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 745975e5d..06604bc8e 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -866,8 +866,8 @@ void ColladaExporter::WriteController( size_t pIndex) std::vector bind_poses; bind_poses.reserve(mesh->mNumBones * 16); - for( size_t i = 0; i < mesh->mNumBones; ++i) - for( size_t j = 0; j < 4; ++j) + for(unsigned int i = 0; i < mesh->mNumBones; ++i) + for( unsigned int j = 0; j < 4; ++j) bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4); WriteFloatArray( idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real*) bind_poses.data(), bind_poses.size() / 16); @@ -924,11 +924,11 @@ void ColladaExporter::WriteController( size_t pIndex) ai_uint weight_index = 0; std::vector joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1); - for( size_t i = 0; i < mesh->mNumBones; ++i) - for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + for( unsigned int i = 0; i < mesh->mNumBones; ++i) + for( unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) { unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId; - for( size_t k = 0; k < num_influences[vId]; ++k) + for( ai_uint k = 0; k < num_influences[vId]; ++k) { if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1) { diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index c68eb27c9..f7ef903f4 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -728,7 +728,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED; dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()]; - dstMesh->mNumAnimMeshes = animMeshes.size(); + dstMesh->mNumAnimMeshes = static_cast(animMeshes.size()); for (unsigned int i = 0; i < animMeshes.size(); i++) dstMesh->mAnimMeshes[i] = animMeshes.at(i); } @@ -1377,9 +1377,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars { aiNodeAnim* dstAnim = new aiNodeAnim; dstAnim->mNodeName = nodeName; - dstAnim->mNumPositionKeys = resultTrafos.size(); - dstAnim->mNumRotationKeys= resultTrafos.size(); - dstAnim->mNumScalingKeys = resultTrafos.size(); + dstAnim->mNumPositionKeys = static_cast(resultTrafos.size()); + dstAnim->mNumRotationKeys = static_cast(resultTrafos.size()); + dstAnim->mNumScalingKeys = static_cast(resultTrafos.size()); dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()]; dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; @@ -1445,11 +1445,11 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars ++morphAnimChannelIndex; } - morphAnim->mNumKeys = morphTimeValues.size(); + morphAnim->mNumKeys = static_cast(morphTimeValues.size()); morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys]; for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) { - morphAnim->mKeys[key].mNumValuesAndWeights = morphChannels.size(); + morphAnim->mKeys[key].mNumValuesAndWeights = static_cast(morphChannels.size()); morphAnim->mKeys[key].mValues = new unsigned int [morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double [morphChannels.size()]; @@ -1470,13 +1470,13 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars { aiAnimation* anim = new aiAnimation; anim->mName.Set( pName); - anim->mNumChannels = anims.size(); + anim->mNumChannels = static_cast(anims.size()); if (anim->mNumChannels > 0) { anim->mChannels = new aiNodeAnim*[anims.size()]; std::copy( anims.begin(), anims.end(), anim->mChannels); } - anim->mNumMorphMeshChannels = morphAnims.size(); + anim->mNumMorphMeshChannels = static_cast(morphAnims.size()); if (anim->mNumMorphMeshChannels > 0) { anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels]; From b7f1277175236b6ce935b9ca9cc2b210b47905b3 Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Sun, 10 Sep 2017 19:07:37 +1000 Subject: [PATCH 32/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/ObjFileMtlImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index 69f35a67d..36bb6c2cb 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -304,7 +304,7 @@ void ObjFileMtlImporter::createMaterial() m_pModel->m_pCurrentMaterial = new ObjFile::Material(); m_pModel->m_pCurrentMaterial->MaterialName.Set( name ); if (m_pModel->m_pCurrentMesh) { - m_pModel->m_pCurrentMesh->m_uiMaterialIndex = m_pModel->m_MaterialLib.size() - 1; + m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast(m_pModel->m_MaterialLib.size() - 1); } m_pModel->m_MaterialLib.push_back( name ); m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial; From 6e02bcd8d6b187d10f30c536dbd2e3bf3c3af85d Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Sun, 10 Sep 2017 19:10:59 +1000 Subject: [PATCH 33/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/PlyParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index d978b513b..f4b68a83f 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -618,7 +618,7 @@ bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pc } streamBuffer.getNextBlock(buffer); - unsigned int bufferSize = buffer.size(); + unsigned int bufferSize = static_cast(buffer.size()); const char* pCur = (char*)&buffer[0]; if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE)) { @@ -1025,7 +1025,7 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer &streamBuffer, buffer = std::vector(buffer.end() - bufferSize, buffer.end()); buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end()); nbuffer.clear(); - bufferSize = buffer.size(); + bufferSize = static_cast(buffer.size()); pCur = (char*)&buffer[0]; } else From 6db0a63d6ef5e2b70014d342810955abc6cec088 Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Sun, 10 Sep 2017 19:13:12 +1000 Subject: [PATCH 34/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/IFCProfile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/IFCProfile.cpp b/code/IFCProfile.cpp index e94d98a04..595159a6b 100644 --- a/code/IFCProfile.cpp +++ b/code/IFCProfile.cpp @@ -128,7 +128,7 @@ void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout.verts.push_back( IfcVector3( std::cos(angle)*radius, std::sin(angle)*radius, 0.f )); } - meshout.vertcnt.push_back(segments); + meshout.vertcnt.push_back(static_cast(segments)); } else if( const IfcIShapeProfileDef* const ishape = def.ToPtr()) { // construct simplified IBeam shape From 1167edaeca09b07a8ea20036d83d626180d48175 Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Mon, 11 Sep 2017 00:09:35 +1000 Subject: [PATCH 35/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/MMDImporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/MMDImporter.cpp b/code/MMDImporter.cpp index 149761c34..84797cba2 100644 --- a/code/MMDImporter.cpp +++ b/code/MMDImporter.cpp @@ -278,7 +278,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel, bone_vertex_map[vsBDEF2_ptr->bone_index1].push_back( aiVertexWeight(index, vsBDEF2_ptr->bone_weight)); bone_vertex_map[vsBDEF2_ptr->bone_index2].push_back( - aiVertexWeight(index, 1.0 - vsBDEF2_ptr->bone_weight)); + aiVertexWeight(index, 1.0f - vsBDEF2_ptr->bone_weight)); break; case pmx::PmxVertexSkinningType::BDEF4: bone_vertex_map[vsBDEF4_ptr->bone_index1].push_back( @@ -295,7 +295,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel, bone_vertex_map[vsSDEF_ptr->bone_index1].push_back( aiVertexWeight(index, vsSDEF_ptr->bone_weight)); bone_vertex_map[vsSDEF_ptr->bone_index2].push_back( - aiVertexWeight(index, 1.0 - vsSDEF_ptr->bone_weight)); + aiVertexWeight(index, 1.0f - vsSDEF_ptr->bone_weight)); break; case pmx::PmxVertexSkinningType::QDEF: const auto vsQDEF_ptr = @@ -325,7 +325,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel, aiMatrix4x4::Translation(-pos, pBone->mOffsetMatrix); auto it = bone_vertex_map.find(ii); if (it != bone_vertex_map.end()) { - pBone->mNumWeights = it->second.size(); + pBone->mNumWeights = static_cast(it->second.size()); pBone->mWeights = it->second.data(); it->second.swap(*(new vector)); } From e40cd6c13c0d5c85e932c4d958c4c13d8b6d1d20 Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Mon, 11 Sep 2017 00:09:40 +1000 Subject: [PATCH 36/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/X3DImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index 669f46f95..aaf99b309 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -558,7 +558,7 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector WordIterator wordItBegin(val, val + strlen(val)); WordIterator wordItEnd; - std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atof(match); }); + std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return static_cast(atof(match)); }); } } From 698cd5826d5be44964a24fb32a1c3c92f0d8daac Mon Sep 17 00:00:00 2001 From: Jared Mulconry Date: Mon, 11 Sep 2017 00:16:26 +1000 Subject: [PATCH 37/37] Fixed warnings when compiling for x64 on MSVC through VS 2017 v15.3.3. --- code/glTF2Asset.inl | 2 +- code/glTF2Exporter.cpp | 10 +++++----- code/glTFExporter.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/glTF2Asset.inl b/code/glTF2Asset.inl index 44a1cce00..09e647cca 100644 --- a/code/glTF2Asset.inl +++ b/code/glTF2Asset.inl @@ -242,7 +242,7 @@ Ref LazyDict::Create(const char* id) } T* inst = new T(); inst->id = id; - inst->index = mObjs.size(); + inst->index = static_cast(mObjs.size()); return Add(inst); } diff --git a/code/glTF2Exporter.cpp b/code/glTF2Exporter.cpp index 11694a89d..7daef7000 100644 --- a/code/glTF2Exporter.cpp +++ b/code/glTF2Exporter.cpp @@ -886,7 +886,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmPositionKeys[frameIndex].mTime / ticksPerSecond; } - Ref timeAccessor = ExportData(mAsset, animId, buffer, numKeyframes, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); + Ref timeAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); if (timeAccessor) animRef->Parameters.TIME = timeAccessor; } @@ -899,7 +899,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmPositionKeys[frameIndex].mValue; } - Ref tranAccessor = ExportData(mAsset, animId, buffer, numKeyframes, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref tranAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( tranAccessor ) { animRef->Parameters.translation = tranAccessor; } @@ -915,7 +915,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmScalingKeys[frameIndex].mValue; } - Ref scaleAccessor = ExportData(mAsset, animId, buffer, numKeyframes, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref scaleAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( scaleAccessor ) { animRef->Parameters.scale = scaleAccessor; } @@ -934,7 +934,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmRotationKeys[frameIndex].mValue.w; } - Ref rotAccessor = ExportData(mAsset, animId, buffer, numKeyframes, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + Ref rotAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if ( rotAccessor ) { animRef->Parameters.rotation = rotAccessor; } @@ -989,7 +989,7 @@ void glTF2Exporter::ExportAnimations() Animation::AnimChannel tmpAnimChannel; Animation::AnimSampler tmpAnimSampler; - tmpAnimChannel.sampler = animRef->Samplers.size(); + tmpAnimChannel.sampler = static_cast(animRef->Samplers.size()); tmpAnimChannel.target.path = channelType; tmpAnimSampler.output = channelType; tmpAnimSampler.id = name + "_" + channelType; diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index f3fa5e526..8967a7aa7 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -875,7 +875,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmPositionKeys[frameIndex].mTime / ticksPerSecond; } - Ref timeAccessor = ExportData(mAsset, animId, buffer, numKeyframes, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); + Ref timeAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); if (timeAccessor) animRef->Parameters.TIME = timeAccessor; } @@ -888,7 +888,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmPositionKeys[frameIndex].mValue; } - Ref tranAccessor = ExportData(mAsset, animId, buffer, numKeyframes, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref tranAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( tranAccessor ) { animRef->Parameters.translation = tranAccessor; } @@ -904,7 +904,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmScalingKeys[frameIndex].mValue; } - Ref scaleAccessor = ExportData(mAsset, animId, buffer, numKeyframes, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref scaleAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( scaleAccessor ) { animRef->Parameters.scale = scaleAccessor; } @@ -923,7 +923,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmRotationKeys[frameIndex].mValue.w; } - Ref rotAccessor = ExportData(mAsset, animId, buffer, numKeyframes, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + Ref rotAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if ( rotAccessor ) { animRef->Parameters.rotation = rotAccessor; }