From 1d6ed840fb9382c3234b719bbb97f72c836ac4d2 Mon Sep 17 00:00:00 2001 From: Florian Born Date: Wed, 20 Apr 2022 12:14:35 +0200 Subject: [PATCH 001/162] Replace single allocations in fbx loader by block allocation --- code/Common/StackAllocator.cpp | 84 ++++++++++++++++++++++++++++++++ code/Common/StackAllocator.h | 89 ++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 code/Common/StackAllocator.cpp create mode 100644 code/Common/StackAllocator.h diff --git a/code/Common/StackAllocator.cpp b/code/Common/StackAllocator.cpp new file mode 100644 index 000000000..c789099a2 --- /dev/null +++ b/code/Common/StackAllocator.cpp @@ -0,0 +1,84 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 "StackAllocator.h" +#include + +using namespace Assimp; + + +StackAllocator::StackAllocator() { +} + +StackAllocator::~StackAllocator() { + FreeAll(); +} + +void *StackAllocator::Allocate(size_t byteSize) { + if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block + { + // double block size every time, up to maximum of g_maxBytesPerBlock. + // Block size must be at least as large as byteSize, but we want to use this for small allocations anyway. + m_blockAllocationSize = std::max(std::min(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize); + uint8_t *data = (uint8_t *)malloc(m_blockAllocationSize); + m_storageBlocks.push_back(data); + m_subIndex = byteSize; + return data; + } + + uint8_t *data = m_storageBlocks.back(); + data += m_subIndex; + m_subIndex += byteSize; + + return data; +} + +void StackAllocator::FreeAll() { + for (size_t i = 0; i < m_storageBlocks.size(); i++) { + free(m_storageBlocks[i]); + } + std::deque empty; + m_storageBlocks.swap(empty); + // start over: + m_blockAllocationSize = g_startBytesPerBlock; + m_subIndex = g_maxBytesPerBlock; +} diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h new file mode 100644 index 000000000..b0f1ecfe1 --- /dev/null +++ b/code/Common/StackAllocator.h @@ -0,0 +1,89 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file StackAllocator.h + * @brief A very bare-bone allocator class that is suitable when + * allocating many small objects, e.g. during parsing. + * Individual objects are not freed, instead only the whole memory + * can be deallocated. + */ +#ifndef AI_STACK_ALLOCATOR_H_INC +#define AI_STACK_ALLOCATOR_H_INC + + +#include + +namespace Assimp +{ + +/** @brief A very bare-bone allocator class that is suitable when + * allocating many small objects, e.g. during parsing. + * Individual objects are not freed, instead only the whole memory + * can be deallocated. +*/ +class StackAllocator { +public: + // Constructs the allocator + StackAllocator(); + // Destructs the allocator and frees all memory + ~StackAllocator(); + + // Returns a pointer to byteSize bytes of heap memory that persists + // for the lifetime of the allocator (or until FreeAll is called). + void *Allocate(size_t byteSize); + + // Releases all the memory owned by this allocator. + // Memory provided through function Allocate is not valid anymore after this function has been called. + void FreeAll(); + +private: + constexpr const static size_t g_maxBytesPerBlock = 64 * 1024 * 1024; // The maximum size (in bytes) of a block + constexpr const static size_t g_startBytesPerBlock = 16 * 1024; // Size of the first block. Next blocks will double in size until maximum size of g_maxBytesPerBlock + size_t m_blockAllocationSize = g_startBytesPerBlock; // Block size of the current block + size_t m_subIndex = g_maxBytesPerBlock; // The current byte offset in the current block + std::deque m_storageBlocks; // A list of blocks +}; + + +} // namespace Assimp + +#endif // include guard From 2b3c49cb93d404a023fe8b852ebdb3e331fa6a15 Mon Sep 17 00:00:00 2001 From: Florian Born Date: Wed, 20 Apr 2022 12:33:39 +0200 Subject: [PATCH 002/162] All allocation changes --- code/AssetLib/FBX/FBXBinaryTokenizer.cpp | 10 ++++------ code/AssetLib/FBX/FBXDocument.cpp | 23 ++++++++++------------- code/AssetLib/FBX/FBXDocument.h | 2 ++ code/AssetLib/FBX/FBXImporter.cpp | 10 ++++------ code/AssetLib/FBX/FBXParser.cpp | 20 ++++++++------------ code/AssetLib/FBX/FBXParser.h | 17 +++++++++++------ code/AssetLib/FBX/FBXTokenizer.cpp | 20 ++++++++++---------- code/AssetLib/FBX/FBXTokenizer.h | 7 ++++--- code/CMakeLists.txt | 2 ++ 9 files changed, 55 insertions(+), 56 deletions(-) diff --git a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp index 1a4d11856..43154e2ab 100644 --- a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp +++ b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp @@ -341,8 +341,7 @@ 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, bool const is64bits) -{ +bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, 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 = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); @@ -408,7 +407,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, is64bits); + ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits); } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); @@ -431,8 +430,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, size_t length) -{ +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) { ai_assert(input); ASSIMP_LOG_DEBUG("Tokenizing binary FBX file"); @@ -465,7 +463,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) try { while (cursor < end ) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { + if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) { break; } } diff --git a/code/AssetLib/FBX/FBXDocument.cpp b/code/AssetLib/FBX/FBXDocument.cpp index b49ee625a..17b347f86 100644 --- a/code/AssetLib/FBX/FBXDocument.cpp +++ b/code/AssetLib/FBX/FBXDocument.cpp @@ -235,7 +235,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptrCompound(); for(const ElementMap::value_type& el : sobjects.Elements()) { @@ -377,7 +372,7 @@ void Document::ReadObjects() { DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); } - objects[id] = new LazyObject(id, *el.second, *this); + objects[id] = new_LazyObject(id, *el.second, *this); // grab all animation stacks upfront since there is no listing of them if(!strcmp(el.first.c_str(),"AnimationStack")) { @@ -444,8 +439,10 @@ void Document::ReadPropertyTemplates() { } // ------------------------------------------------------------------------------------------------ -void Document::ReadConnections() { - const Scope& sc = parser.GetRootScope(); +void Document::ReadConnections() +{ + StackAllocator &allocator = parser.GetAllocator(); + const Scope &sc = parser.GetRootScope(); // read property templates from "Definitions" section const Element* const econns = sc["Connections"]; if(!econns || !econns->Compound()) { @@ -484,7 +481,7 @@ void Document::ReadConnections() { } // add new connection - const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this); + const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this); src_connections.insert(ConnectionMap::value_type(src,c)); dest_connections.insert(ConnectionMap::value_type(dest,c)); } diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index c61a47410..142e870ff 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -80,6 +80,8 @@ class BlendShape; class Skin; class Cluster; +#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject +#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection /** Represents a delay-parsed FBX objects. Many objects in the scene * are not needed by assimp, so it makes no sense to parse them diff --git a/code/AssetLib/FBX/FBXImporter.cpp b/code/AssetLib/FBX/FBXImporter.cpp index 0f63acc8f..96c5a9f14 100644 --- a/code/AssetLib/FBX/FBXImporter.cpp +++ b/code/AssetLib/FBX/FBXImporter.cpp @@ -160,17 +160,18 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy TokenList tokens; try { + Assimp::StackAllocator tempAllocator; bool is_binary = false; if (!strncmp(begin, "Kaydara FBX Binary", 18)) { is_binary = true; - TokenizeBinary(tokens, begin, contents.size()); + TokenizeBinary(tokens, begin, contents.size(), tempAllocator); } else { - Tokenize(tokens, begin); + Tokenize(tokens, begin, tempAllocator); } // use this information to construct a very rudimentary // parse-tree representing the FBX scope structure - Parser parser(tokens, is_binary); + Parser parser(tokens, tempAllocator, is_binary); // take the raw parse-tree and convert it to a FBX DOM Document doc(parser, settings); @@ -189,10 +190,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Set FBX file scale is relative to CM must be converted to M for // assimp universal format (M) SetFileScale(size_relative_to_cm * 0.01f); - - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun()); } catch (std::exception &) { - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun()); throw; } } diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index e20377a3c..e6cc39f46 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -117,6 +117,7 @@ namespace FBX { // ------------------------------------------------------------------------------------------------ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { TokenPtr n = nullptr; + StackAllocator &allocator = parser.GetAllocator(); do { n = parser.AdvanceToNextToken(); if(!n) { @@ -145,7 +146,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) } if (n->Type() == TokenType_OPEN_BRACKET) { - compound.reset(new Scope(parser)); + compound.reset(new_Scope(parser)); // current token should be a TOK_CLOSE_BRACKET n = parser.CurrentToken(); @@ -178,6 +179,7 @@ Scope::Scope(Parser& parser,bool topLevel) } } + StackAllocator &allocator = parser.GetAllocator(); TokenPtr n = parser.AdvanceToNextToken(); if (n == nullptr) { ParseError("unexpected end of file"); @@ -208,22 +210,16 @@ Scope::Scope(Parser& parser,bool topLevel) } // ------------------------------------------------------------------------------------------------ -Scope::~Scope() { - for(ElementMap::value_type& v : elements) { - delete v.second; - } +Scope::~Scope() +{ } // ------------------------------------------------------------------------------------------------ -Parser::Parser (const TokenList& tokens, bool is_binary) -: tokens(tokens) -, last() -, current() -, cursor(tokens.begin()) -, is_binary(is_binary) +Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) : + tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary) { ASSIMP_LOG_DEBUG("Parsing FBX tokens"); - root.reset(new Scope(*this,true)); + root = new_Scope(*this, true); } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/FBX/FBXParser.h b/code/AssetLib/FBX/FBXParser.h index 314481e42..5eed61fef 100644 --- a/code/AssetLib/FBX/FBXParser.h +++ b/code/AssetLib/FBX/FBXParser.h @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "Common/StackAllocator.h" #include "FBXCompileConfig.h" #include "FBXTokenizer.h" @@ -68,8 +69,8 @@ typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; typedef std::pair ElementCollection; -# define new_Scope new Scope -# define new_Element new Element +#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope +#define new_Element new (allocator.Allocate(sizeof(Element))) Element /** FBX data entity that consists of a key:value tuple. @@ -159,17 +160,21 @@ class Parser public: /** Parse given a token list. Does not take ownership of the tokens - * the objects must persist during the entire parser lifetime */ - Parser (const TokenList& tokens,bool is_binary); + Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary); ~Parser(); const Scope& GetRootScope() const { - return *root.get(); + return *root; } bool IsBinary() const { return is_binary; } + StackAllocator &GetAllocator() { + return allocator; + } + private: friend class Scope; friend class Element; @@ -180,10 +185,10 @@ private: private: const TokenList& tokens; - + StackAllocator &allocator; TokenPtr last, current; TokenList::const_iterator cursor; - std::unique_ptr root; + Scope *root; const bool is_binary; }; diff --git a/code/AssetLib/FBX/FBXTokenizer.cpp b/code/AssetLib/FBX/FBXTokenizer.cpp index 8698abac6..7f03b71da 100644 --- a/code/AssetLib/FBX/FBXTokenizer.cpp +++ b/code/AssetLib/FBX/FBXTokenizer.cpp @@ -96,7 +96,8 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, // process a potential data token up to 'cur', adding it to 'output_tokens'. // ------------------------------------------------------------------------------------------------ -void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end, +void ProcessDataToken(TokenList &output_tokens, StackAllocator &token_allocator, + const char*& start, const char*& end, unsigned int line, unsigned int column, TokenType type = TokenType_DATA, @@ -133,8 +134,7 @@ void ProcessDataToken( TokenList& output_tokens, const char*& start, const char* } // ------------------------------------------------------------------------------------------------ -void Tokenize(TokenList& output_tokens, const char* input) -{ +void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) { ai_assert(input); ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file"); @@ -166,7 +166,7 @@ void Tokenize(TokenList& output_tokens, const char* input) in_double_quotes = false; token_end = cur; - ProcessDataToken(output_tokens,token_begin,token_end,line,column); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column); pending_data_token = false; } continue; @@ -183,30 +183,30 @@ void Tokenize(TokenList& output_tokens, const char* input) continue; case ';': - ProcessDataToken(output_tokens,token_begin,token_end,line,column); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column); comment = true; continue; case '{': - ProcessDataToken(output_tokens,token_begin,token_end, line, column); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column)); continue; case '}': - ProcessDataToken(output_tokens,token_begin,token_end,line,column); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column)); continue; case ',': if (pending_data_token) { - ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true); } output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column)); continue; case ':': if (pending_data_token) { - ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true); } else { TokenizeError("unexpected colon", line, column); @@ -228,7 +228,7 @@ void Tokenize(TokenList& output_tokens, const char* input) } } - ProcessDataToken(output_tokens,token_begin,token_end,line,column,type); + ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type); } pending_data_token = false; diff --git a/code/AssetLib/FBX/FBXTokenizer.h b/code/AssetLib/FBX/FBXTokenizer.h index 877950945..d5f7999e4 100644 --- a/code/AssetLib/FBX/FBXTokenizer.h +++ b/code/AssetLib/FBX/FBXTokenizer.h @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define INCLUDED_AI_FBX_TOKENIZER_H #include "FBXCompileConfig.h" +#include "Common/StackAllocator.h" #include #include #include @@ -158,7 +159,7 @@ private: typedef const Token* TokenPtr; typedef std::vector< TokenPtr > TokenList; -#define new_Token new Token +#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token /** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens. @@ -168,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList; * @param output_tokens Receives a list of all tokens in the input data. * @param input_buffer Textual input buffer to be processed, 0-terminated. * @throw DeadlyImportError if something goes wrong */ -void Tokenize(TokenList& output_tokens, const char* input); +void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &tokenAllocator); /** Tokenizer function for binary FBX files. @@ -179,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input); * @param input_buffer Binary input buffer to be processed. * @param length Length of input buffer, in bytes. There is no 0-terminal. * @throw DeadlyImportError if something goes wrong */ -void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length); +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &tokenAllocator); } // ! FBX diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 5b08c0f37..e7eaf1d84 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -193,6 +193,8 @@ SET( Common_SRCS Common/ScenePreprocessor.cpp Common/ScenePreprocessor.h Common/SkeletonMeshBuilder.cpp + Common/StackAllocator.h + Common/StackAllocator.cpp Common/StandardShapes.cpp Common/TargetAnimation.cpp Common/TargetAnimation.h From d3646c3118b9b93fa7fe5dc9a979424450f8f72a Mon Sep 17 00:00:00 2001 From: Florian Born Date: Wed, 20 Apr 2022 16:11:09 +0200 Subject: [PATCH 003/162] Proper destruction of individual objects --- code/AssetLib/FBX/FBXDocument.cpp | 13 ++++++++++++- code/AssetLib/FBX/FBXDocument.h | 2 ++ code/AssetLib/FBX/FBXImporter.cpp | 14 +++++++++----- code/AssetLib/FBX/FBXParser.cpp | 17 ++++++++++++++--- code/AssetLib/FBX/FBXParser.h | 7 ++++--- code/AssetLib/FBX/FBXTokenizer.h | 1 + code/AssetLib/FBX/FBXUtil.h | 11 +++++++++++ code/Common/StackAllocator.h | 4 ++++ 8 files changed, 57 insertions(+), 12 deletions(-) diff --git a/code/AssetLib/FBX/FBXDocument.cpp b/code/AssetLib/FBX/FBXDocument.cpp index 17b347f86..437bf210b 100644 --- a/code/AssetLib/FBX/FBXDocument.cpp +++ b/code/AssetLib/FBX/FBXDocument.cpp @@ -257,7 +257,18 @@ Document::Document(Parser& parser, const ImportSettings& settings) : } // ------------------------------------------------------------------------------------------------ -Document::~Document() { +Document::~Document() +{ + // The document does not own the memory for the following objects, but we need to call their d'tor + // so they can properly free memory like string members: + + for (ObjectMap::value_type &v : objects) { + delete_LazyObject(v.second); + } + + for (ConnectionMap::value_type &v : src_connections) { + delete_Connection(v.second); + } // |dest_connections| contain the same Connection objects as the |src_connections| } diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index 142e870ff..11ee17f4c 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -82,6 +82,8 @@ class Cluster; #define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject #define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection +#define delete_LazyObject(_p) (_p)->~LazyObject() +#define delete_Connection(_p) (_p)->~Connection() /** Represents a delay-parsed FBX objects. Many objects in the scene * are not needed by assimp, so it makes no sense to parse them diff --git a/code/AssetLib/FBX/FBXImporter.cpp b/code/AssetLib/FBX/FBXImporter.cpp index 96c5a9f14..fa2122c4f 100644 --- a/code/AssetLib/FBX/FBXImporter.cpp +++ b/code/AssetLib/FBX/FBXImporter.cpp @@ -158,9 +158,8 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // broadphase tokenizing pass in which we identify the core // syntax elements of FBX (brackets, commas, key:value mappings) TokenList tokens; - try { - - Assimp::StackAllocator tempAllocator; + Assimp::StackAllocator tempAllocator; + try { bool is_binary = false; if (!strncmp(begin, "Kaydara FBX Binary", 18)) { is_binary = true; @@ -190,8 +189,13 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Set FBX file scale is relative to CM must be converted to M for // assimp universal format (M) SetFileScale(size_relative_to_cm * 0.01f); - } catch (std::exception &) { - throw; + + // This collection does not own the memory for the tokens, but we need to call their d'tor + std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun()); + + } catch (std::exception &) { + std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun()); + throw; } } diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index e6cc39f46..976cdb90b 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -115,7 +115,9 @@ namespace Assimp { namespace FBX { // ------------------------------------------------------------------------------------------------ -Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { +Element::Element(const Token& key_token, Parser& parser) : + key_token(key_token), compound(nullptr) +{ TokenPtr n = nullptr; StackAllocator &allocator = parser.GetAllocator(); do { @@ -146,7 +148,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) } if (n->Type() == TokenType_OPEN_BRACKET) { - compound.reset(new_Scope(parser)); + compound = new_Scope(parser); // current token should be a TOK_CLOSE_BRACKET n = parser.CurrentToken(); @@ -166,6 +168,10 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) // ------------------------------------------------------------------------------------------------ Element::~Element() { + if (compound) { + delete_Scope(compound); + } + // no need to delete tokens, they are owned by the parser } @@ -212,6 +218,11 @@ Scope::Scope(Parser& parser,bool topLevel) // ------------------------------------------------------------------------------------------------ Scope::~Scope() { + // This collection does not own the memory for the elements, but we need to call their d'tor: + + for (ElementMap::value_type &v : elements) { + delete_Element(v.second); + } } // ------------------------------------------------------------------------------------------------ @@ -225,7 +236,7 @@ Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binar // ------------------------------------------------------------------------------------------------ Parser::~Parser() { - // empty + delete_Scope(root); } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/FBX/FBXParser.h b/code/AssetLib/FBX/FBXParser.h index 5eed61fef..9b654239b 100644 --- a/code/AssetLib/FBX/FBXParser.h +++ b/code/AssetLib/FBX/FBXParser.h @@ -71,7 +71,8 @@ typedef std::pair Element #define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope #define new_Element new (allocator.Allocate(sizeof(Element))) Element - +#define delete_Scope(_p) (_p)->~Scope() +#define delete_Element(_p) (_p)->~Element() /** FBX data entity that consists of a key:value tuple. * @@ -91,7 +92,7 @@ public: ~Element(); const Scope* Compound() const { - return compound.get(); + return compound; } const Token& KeyToken() const { @@ -105,7 +106,7 @@ public: private: const Token& key_token; TokenList tokens; - std::unique_ptr compound; + Scope* compound; }; /** FBX data entity that consists of a 'scope', a collection diff --git a/code/AssetLib/FBX/FBXTokenizer.h b/code/AssetLib/FBX/FBXTokenizer.h index d5f7999e4..7e395d5e9 100644 --- a/code/AssetLib/FBX/FBXTokenizer.h +++ b/code/AssetLib/FBX/FBXTokenizer.h @@ -160,6 +160,7 @@ typedef const Token* TokenPtr; typedef std::vector< TokenPtr > TokenList; #define new_Token new (token_allocator.Allocate(sizeof(Token))) Token +#define delete_Token(_p) (_p)->~Token() /** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens. diff --git a/code/AssetLib/FBX/FBXUtil.h b/code/AssetLib/FBX/FBXUtil.h index 0e0bb75be..4674a5054 100644 --- a/code/AssetLib/FBX/FBXUtil.h +++ b/code/AssetLib/FBX/FBXUtil.h @@ -66,6 +66,17 @@ struct delete_fun } }; +/** helper for std::for_each to call the destructor on all items in a container without freeing their heap*/ +template +struct destructor_fun { + void operator()(const volatile T* del) { + if (del) { + del->~T(); + } + } +}; + + /** Get a string representation for a #TokenType. */ const char* TokenTypeString(TokenType t); diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index b0f1ecfe1..b670b7434 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -67,6 +67,10 @@ public: // Destructs the allocator and frees all memory ~StackAllocator(); + // non copyable + StackAllocator(const StackAllocator &) = delete; + StackAllocator &operator=(const StackAllocator &) = delete; + // Returns a pointer to byteSize bytes of heap memory that persists // for the lifetime of the allocator (or until FreeAll is called). void *Allocate(size_t byteSize); From 320775b9392cd809b663440839b9124da844518c Mon Sep 17 00:00:00 2001 From: Florian Born Date: Wed, 20 Apr 2022 16:39:36 +0200 Subject: [PATCH 004/162] Compile fix --- code/Common/StackAllocator.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index b670b7434..cc252f8df 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include namespace Assimp { From 0355ae967feefd5811ddf4c37d91e43fff880a13 Mon Sep 17 00:00:00 2001 From: Florian Born Date: Wed, 20 Apr 2022 17:57:03 +0200 Subject: [PATCH 005/162] compile fix on other platforms --- code/Common/StackAllocator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/Common/StackAllocator.cpp b/code/Common/StackAllocator.cpp index c789099a2..259a565be 100644 --- a/code/Common/StackAllocator.cpp +++ b/code/Common/StackAllocator.cpp @@ -59,7 +59,7 @@ void *StackAllocator::Allocate(size_t byteSize) { // double block size every time, up to maximum of g_maxBytesPerBlock. // Block size must be at least as large as byteSize, but we want to use this for small allocations anyway. m_blockAllocationSize = std::max(std::min(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize); - uint8_t *data = (uint8_t *)malloc(m_blockAllocationSize); + uint8_t *data = new uint8_t[m_blockAllocationSize]; m_storageBlocks.push_back(data); m_subIndex = byteSize; return data; @@ -74,7 +74,7 @@ void *StackAllocator::Allocate(size_t byteSize) { void StackAllocator::FreeAll() { for (size_t i = 0; i < m_storageBlocks.size(); i++) { - free(m_storageBlocks[i]); + delete [] m_storageBlocks[i]; } std::deque empty; m_storageBlocks.swap(empty); From 7f0509ae87b852216ca853d7b7094fdb1cecf627 Mon Sep 17 00:00:00 2001 From: Florian Born Date: Thu, 21 Apr 2022 11:33:04 +0200 Subject: [PATCH 006/162] Stack allocator is now inline --- code/CMakeLists.txt | 2 +- code/Common/StackAllocator.h | 10 ++++++---- code/Common/{StackAllocator.cpp => StackAllocator.inl} | 8 ++++---- 3 files changed, 11 insertions(+), 9 deletions(-) rename code/Common/{StackAllocator.cpp => StackAllocator.inl} (93%) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index e7eaf1d84..75a5cb377 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -194,7 +194,7 @@ SET( Common_SRCS Common/ScenePreprocessor.h Common/SkeletonMeshBuilder.cpp Common/StackAllocator.h - Common/StackAllocator.cpp + Common/StackAllocator.inl Common/StandardShapes.cpp Common/TargetAnimation.cpp Common/TargetAnimation.h diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index cc252f8df..aff36fa47 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -64,9 +64,9 @@ namespace Assimp class StackAllocator { public: // Constructs the allocator - StackAllocator(); + inline StackAllocator(); // Destructs the allocator and frees all memory - ~StackAllocator(); + inline ~StackAllocator(); // non copyable StackAllocator(const StackAllocator &) = delete; @@ -74,11 +74,11 @@ public: // Returns a pointer to byteSize bytes of heap memory that persists // for the lifetime of the allocator (or until FreeAll is called). - void *Allocate(size_t byteSize); + inline void *Allocate(size_t byteSize); // Releases all the memory owned by this allocator. // Memory provided through function Allocate is not valid anymore after this function has been called. - void FreeAll(); + inline void FreeAll(); private: constexpr const static size_t g_maxBytesPerBlock = 64 * 1024 * 1024; // The maximum size (in bytes) of a block @@ -91,4 +91,6 @@ private: } // namespace Assimp +#include "StackAllocator.inl" + #endif // include guard diff --git a/code/Common/StackAllocator.cpp b/code/Common/StackAllocator.inl similarity index 93% rename from code/Common/StackAllocator.cpp rename to code/Common/StackAllocator.inl index 259a565be..d973b7794 100644 --- a/code/Common/StackAllocator.cpp +++ b/code/Common/StackAllocator.inl @@ -46,14 +46,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -StackAllocator::StackAllocator() { +inline StackAllocator::StackAllocator() { } -StackAllocator::~StackAllocator() { +inline StackAllocator::~StackAllocator() { FreeAll(); } -void *StackAllocator::Allocate(size_t byteSize) { +inline void *StackAllocator::Allocate(size_t byteSize) { if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block { // double block size every time, up to maximum of g_maxBytesPerBlock. @@ -72,7 +72,7 @@ void *StackAllocator::Allocate(size_t byteSize) { return data; } -void StackAllocator::FreeAll() { +inline void StackAllocator::FreeAll() { for (size_t i = 0; i < m_storageBlocks.size(); i++) { delete [] m_storageBlocks[i]; } From a415f33fb561d8e2531205aa61d1228e47158c19 Mon Sep 17 00:00:00 2001 From: Florian Born Date: Thu, 21 Apr 2022 16:09:28 +0200 Subject: [PATCH 007/162] merge failure, parts in this file were missing --- code/AssetLib/FBX/FBXDocument.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index 11ee17f4c..c701056f6 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -1076,7 +1076,7 @@ private: /** DOM root for a FBX file */ class Document { public: - Document(const Parser& parser, const ImportSettings& settings); + Document(Parser& parser, const ImportSettings& settings); ~Document(); @@ -1160,7 +1160,7 @@ private: const ImportSettings& settings; ObjectMap objects; - const Parser& parser; + Parser& parser; PropertyTemplateMap templates; ConnectionMap src_connections; From 417481d17f3864c8b7b47e000a857d1f4279946b Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 00:44:51 +0200 Subject: [PATCH 008/162] Rewrote gltf2 node extras import and added node extras export. No support for AI_AIVECTOR3D metadata type. No support for json arrays of metadata, just json objects. --- code/AssetLib/glTF2/glTF2Asset.h | 47 ++++++++++++++++++- code/AssetLib/glTF2/glTF2Asset.inl | 46 ++++++++++++++++++- code/AssetLib/glTF2/glTF2AssetWriter.inl | 41 ++++++++++++++++- code/AssetLib/glTF2/glTF2Exporter.cpp | 57 +++++++++++++++++++++++- code/AssetLib/glTF2/glTF2Importer.cpp | 34 +++++++++++--- code/Common/SceneCombiner.cpp | 3 ++ 6 files changed, 218 insertions(+), 10 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index c597fc951..bdc62dbc2 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,6 +376,51 @@ struct CustomExtension { } }; +struct ExtrasValue; + +//! Represents a union of metadata values +struct ExtrasValue { + std::string name; + + Nullable mBoolValue; + Nullable mInt32Value; + Nullable mUint64Value; + Nullable mFloatValue; + Nullable mDoubleValue; + Nullable mStringValue; + Nullable> mMetadataValue; + + ExtrasValue() = default; + ~ExtrasValue() = default; + + ExtrasValue(const ExtrasValue& other) : + name(other.name), + mStringValue(other.mStringValue), + mDoubleValue(other.mDoubleValue), + mUint64Value(other.mUint64Value), + mInt32Value(other.mInt32Value), + mBoolValue(other.mBoolValue), + mMetadataValue(other.mMetadataValue) { + } +}; + +//! Represents metadata in an glTF object +struct Extras { + std::vector mValues; + + inline bool HasExtras() const { + return mValues.size() != 0; + } + + Extras() = default; + ~Extras() = default; + + Extras(const Extras &other) : + mValues(other.mValues) { + // empty + } +}; + //! Base class for all glTF top-level objects struct Object { int index; //!< The index of this object within its property container @@ -384,7 +429,7 @@ struct Object { std::string name; //!< The user-defined name of this object CustomExtension customExtensions; - CustomExtension extras; + Extras extras; //! Objects marked as special are not exported (used to emulate the binary body buffer) virtual bool IsSpecial() const { return false; } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d6..5dc51e7fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,6 +139,50 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } +inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { + ExtrasValue ret; + ret.name = name; + + if (obj.IsObject()) { + ret.mMetadataValue.value.reserve(obj.MemberCount()); + ret.mMetadataValue.isPresent = true; + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + } else if (obj.IsNumber()) { + if (obj.IsUint64()) { + ret.mUint64Value.value = obj.GetUint64(); + ret.mUint64Value.isPresent = true; + } else if (obj.IsInt()) { + ret.mInt32Value.value = obj.GetInt64(); + ret.mInt32Value.isPresent = true; + } else if (obj.IsDouble()) { + ret.mDoubleValue.value = obj.GetDouble(); + ret.mDoubleValue.isPresent = true; + } + } else if (obj.IsString()) { + ReadValue(obj, ret.mStringValue); + ret.mStringValue.isPresent = true; + } else if (obj.IsBool()) { + ret.mBoolValue.value = obj.GetBool(); + ret.mBoolValue.isPresent = true; + } + return ret; +} + +inline Extras ReadExtras(Value &obj) { + Extras ret; + + ret.mValues.reserve(obj.MemberCount()); + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + + return ret; +} + inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride) { if (src_stride == dst_stride) { @@ -248,7 +292,7 @@ inline void Object::ReadExtensions(Value &val) { inline void Object::ReadExtras(Value &val) { if (Value *curExtras = FindObject(val, "extras")) { - this->extras = glTF2::ReadExtensions("extras", *curExtras); + this->extras = glTF2::ReadExtras(*curExtras); } } diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 0be139595..e1fcaefd4 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,6 +620,44 @@ namespace glTF2 { } } + inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + Value valueNode; + + if (value.mStringValue.isPresent) { + MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl); + } else if (value.mDoubleValue.isPresent) { + MakeValue(valueNode, value.mDoubleValue.value, w.mAl); + } else if (value.mUint64Value.isPresent) { + MakeValue(valueNode, value.mUint64Value.value, w.mAl); + } else if (value.mInt32Value.isPresent) { + MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mBoolValue.isPresent) { + MakeValue(valueNode, value.mBoolValue.value, w.mAl); + } else if (value.mMetadataValue.isPresent) { + valueNode.SetObject(); + for (auto const &subvalue : value.mMetadataValue.value) { + WriteExtrasValue(valueNode, subvalue, w); + } + } + + parent.AddMember(StringRef(value.name), valueNode, w.mAl); + } + + inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) { + if (!extras.HasExtras()) { + return; + } + + Value extrasNode; + extrasNode.SetObject(); + + for (auto const &value : extras.mValues) { + WriteExtrasValue(extrasNode, value, w); + } + + obj.AddMember("extras", extrasNode, w.mAl); + } + inline void Write(Value& obj, Node& n, AssetWriter& w) { if (n.matrix.isPresent) { @@ -655,6 +693,8 @@ namespace glTF2 { if(n.skeletons.size()) { AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); } + + WriteExtras(obj, n.extras, w); } inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/) @@ -728,7 +768,6 @@ namespace glTF2 { } } - inline AssetWriter::AssetWriter(Asset& a) : mDoc() , mAsset(a) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index da7591d52..f8b1995d9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,6 +445,57 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { + + value.name = name.C_Str(); + switch (metadataEntry.mType) { + case AI_BOOL: + value.mBoolValue.value = *static_cast(metadataEntry.mData); + value.mBoolValue.isPresent = true; + break; + case AI_INT32: + value.mInt32Value.value = *static_cast(metadataEntry.mData); + value.mInt32Value.isPresent = true; + break; + case AI_UINT64: + value.mUint64Value.value = *static_cast(metadataEntry.mData); + value.mUint64Value.isPresent = true; + break; + case AI_FLOAT: + value.mFloatValue.value = *static_cast(metadataEntry.mData); + value.mFloatValue.isPresent = true; + break; + case AI_DOUBLE: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; + case AI_AISTRING: + value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); + value.mStringValue.isPresent = true; + break; + case AI_AIMETADATA: + const aiMetadata *subMetadata = static_cast(metadataEntry.mData); + value.mMetadataValue.value.resize(subMetadata->mNumProperties); + value.mMetadataValue.isPresent = true; + + for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + } + break; + } +} + +inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { + if (metadata == nullptr) { + return; + } + + extras.mValues.resize(metadata->mNumProperties); + for (unsigned int i = 0; i < metadata->mNumProperties; ++i) { + ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i)); + } +} + inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) { switch (map) { case aiTextureMapMode_Clamp: @@ -1344,7 +1395,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) { return node.GetIndex(); } -/* + /* * Export node and recursively calls ExportNode for all children. * Since these nodes are not the root node, we also export the parent Ref */ @@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; + if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { + ExportNodeExtras(n->mMetaData, node->extras); + } + if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { aiQuaternion quaternion; diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 293d3dea7..a14e6ad6f 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,11 +1033,33 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) { - if (extension.mValues.isPresent) { - for (auto const &subExtension : extension.mValues.value) { - ParseExtensions(metadata, subExtension); +void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { + + if (value.mBoolValue.isPresent) { + metadata->Add(value.name, value.mBoolValue.value); + } else if (value.mInt32Value.isPresent) { + metadata->Add(value.name, value.mInt32Value.value); + } else if (value.mUint64Value.isPresent) { + metadata->Add(value.name, value.mUint64Value.value); + } else if (value.mFloatValue.isPresent) { + metadata->Add(value.name, value.mFloatValue.value); + } else if (value.mDoubleValue.isPresent) { + metadata->Add(value.name, value.mDoubleValue.value); + } else if (value.mStringValue.isPresent) { + metadata->Add(value.name, aiString(value.mStringValue.value)); + } else if (value.mMetadataValue.isPresent) { + aiMetadata subMetadata; + for (auto const &subValue : value.mMetadataValue.value) { + ParseExtrasValue(&subMetadata, subValue); } + + metadata->Add(value.name, subMetadata); + } +} + +void ParseExtras(aiMetadata* metadata, const Extras& extras) { + for (auto const &value : extras.mValues) { + ParseExtrasValue(metadata, value); } } @@ -1059,12 +1081,12 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || node.extras) { + if (node.customExtensions || !node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); } - if (node.extras) { + if (node.extras.HasExtras()) { ParseExtras(ainode->mMetaData, node.extras); } } diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 2c2539e54..1d32436c2 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) { case AI_AIVECTOR3D: out.mData = new aiVector3D(*static_cast(in.mData)); break; + case AI_AIMETADATA: + out.mData = new aiMetadata(*static_cast(in.mData)); + break; default: ai_assert(false); break; From 5a2b811ba34cfd45d58349b3c3d1894e23f3e05e Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:04:05 +0200 Subject: [PATCH 009/162] Fixed extras presence check in gltf2 import. --- code/AssetLib/glTF2/glTF2Exporter.cpp | 6 ++---- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index f8b1995d9..d3c88e479 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -486,7 +486,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { - if (metadata == nullptr) { + if (metadata == nullptr || metadata->mNumProperties == 0) { return; } @@ -1406,9 +1406,7 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; - if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { - ExportNodeExtras(n->mMetaData, node->extras); - } + ExportNodeExtras(n->mMetaData, node->extras); if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index a14e6ad6f..e88cd0f08 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1081,7 +1081,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || !node.extras.HasExtras()) { + if (node.customExtensions || node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); From 517fd3c76c81450e3967ffc1df5f7b90c1a7d94c Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:07:42 +0200 Subject: [PATCH 010/162] Added missing member copy in gltf2::ExtrasValue ctor. --- code/AssetLib/glTF2/glTF2Asset.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index bdc62dbc2..064634e40 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,9 +376,7 @@ struct CustomExtension { } }; -struct ExtrasValue; - -//! Represents a union of metadata values +//! Represents a union of metadata values. Only one nullable is supposed to be set. struct ExtrasValue { std::string name; @@ -396,6 +394,7 @@ struct ExtrasValue { ExtrasValue(const ExtrasValue& other) : name(other.name), mStringValue(other.mStringValue), + mFloatValue(other.mFloatValue), mDoubleValue(other.mDoubleValue), mUint64Value(other.mUint64Value), mInt32Value(other.mInt32Value), @@ -404,7 +403,7 @@ struct ExtrasValue { } }; -//! Represents metadata in an glTF object +//! Represents metadata in an glTF2 object struct Extras { std::vector mValues; From bdee65e577caa6f2eea8e6e22d2175407cde5de3 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:33:05 +0200 Subject: [PATCH 011/162] Got rid of gltf2::ExtrasValue and used gltf2::CustomExtension instead --- code/AssetLib/glTF2/glTF2Asset.h | 29 +------------------- code/AssetLib/glTF2/glTF2Asset.inl | 34 +----------------------- code/AssetLib/glTF2/glTF2AssetWriter.inl | 10 +++---- code/AssetLib/glTF2/glTF2Exporter.cpp | 16 +++++------ code/AssetLib/glTF2/glTF2Importer.cpp | 26 +----------------- 5 files changed, 14 insertions(+), 101 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 064634e40..9a117205d 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,36 +376,9 @@ struct CustomExtension { } }; -//! Represents a union of metadata values. Only one nullable is supposed to be set. -struct ExtrasValue { - std::string name; - - Nullable mBoolValue; - Nullable mInt32Value; - Nullable mUint64Value; - Nullable mFloatValue; - Nullable mDoubleValue; - Nullable mStringValue; - Nullable> mMetadataValue; - - ExtrasValue() = default; - ~ExtrasValue() = default; - - ExtrasValue(const ExtrasValue& other) : - name(other.name), - mStringValue(other.mStringValue), - mFloatValue(other.mFloatValue), - mDoubleValue(other.mDoubleValue), - mUint64Value(other.mUint64Value), - mInt32Value(other.mInt32Value), - mBoolValue(other.mBoolValue), - mMetadataValue(other.mMetadataValue) { - } -}; - //! Represents metadata in an glTF2 object struct Extras { - std::vector mValues; + std::vector mValues; inline bool HasExtras() const { return mValues.size() != 0; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 5dc51e7fa..3a7d127d3 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,45 +139,13 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } -inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { - ExtrasValue ret; - ret.name = name; - - if (obj.IsObject()) { - ret.mMetadataValue.value.reserve(obj.MemberCount()); - ret.mMetadataValue.isPresent = true; - for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { - auto &val = it->value; - ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); - } - } else if (obj.IsNumber()) { - if (obj.IsUint64()) { - ret.mUint64Value.value = obj.GetUint64(); - ret.mUint64Value.isPresent = true; - } else if (obj.IsInt()) { - ret.mInt32Value.value = obj.GetInt64(); - ret.mInt32Value.isPresent = true; - } else if (obj.IsDouble()) { - ret.mDoubleValue.value = obj.GetDouble(); - ret.mDoubleValue.isPresent = true; - } - } else if (obj.IsString()) { - ReadValue(obj, ret.mStringValue); - ret.mStringValue.isPresent = true; - } else if (obj.IsBool()) { - ret.mBoolValue.value = obj.GetBool(); - ret.mBoolValue.isPresent = true; - } - return ret; -} - inline Extras ReadExtras(Value &obj) { Extras ret; ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index e1fcaefd4..3acec58a5 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,7 +620,7 @@ namespace glTF2 { } } - inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) { Value valueNode; if (value.mStringValue.isPresent) { @@ -629,13 +629,13 @@ namespace glTF2 { MakeValue(valueNode, value.mDoubleValue.value, w.mAl); } else if (value.mUint64Value.isPresent) { MakeValue(valueNode, value.mUint64Value.value, w.mAl); - } else if (value.mInt32Value.isPresent) { - MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mInt64Value.isPresent) { + MakeValue(valueNode, value.mInt64Value.value, w.mAl); } else if (value.mBoolValue.isPresent) { MakeValue(valueNode, value.mBoolValue.value, w.mAl); - } else if (value.mMetadataValue.isPresent) { + } else if (value.mValues.isPresent) { valueNode.SetObject(); - for (auto const &subvalue : value.mMetadataValue.value) { + for (auto const &subvalue : value.mValues.value) { WriteExtrasValue(valueNode, subvalue, w); } } diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index d3c88e479..028ab5c17 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,7 +445,7 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } -inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) { value.name = name.C_Str(); switch (metadataEntry.mType) { @@ -454,17 +454,13 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mBoolValue.isPresent = true; break; case AI_INT32: - value.mInt32Value.value = *static_cast(metadataEntry.mData); - value.mInt32Value.isPresent = true; + value.mInt64Value.value = *static_cast(metadataEntry.mData); + value.mInt64Value.isPresent = true; break; case AI_UINT64: value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; - case AI_FLOAT: - value.mFloatValue.value = *static_cast(metadataEntry.mData); - value.mFloatValue.isPresent = true; - break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -475,11 +471,11 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name break; case AI_AIMETADATA: const aiMetadata *subMetadata = static_cast(metadataEntry.mData); - value.mMetadataValue.value.resize(subMetadata->mNumProperties); - value.mMetadataValue.isPresent = true; + value.mValues.value.resize(subMetadata->mNumProperties); + value.mValues.isPresent = true; for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { - ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i)); } break; } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index e88cd0f08..f34465444 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,33 +1033,9 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { - - if (value.mBoolValue.isPresent) { - metadata->Add(value.name, value.mBoolValue.value); - } else if (value.mInt32Value.isPresent) { - metadata->Add(value.name, value.mInt32Value.value); - } else if (value.mUint64Value.isPresent) { - metadata->Add(value.name, value.mUint64Value.value); - } else if (value.mFloatValue.isPresent) { - metadata->Add(value.name, value.mFloatValue.value); - } else if (value.mDoubleValue.isPresent) { - metadata->Add(value.name, value.mDoubleValue.value); - } else if (value.mStringValue.isPresent) { - metadata->Add(value.name, aiString(value.mStringValue.value)); - } else if (value.mMetadataValue.isPresent) { - aiMetadata subMetadata; - for (auto const &subValue : value.mMetadataValue.value) { - ParseExtrasValue(&subMetadata, subValue); - } - - metadata->Add(value.name, subMetadata); - } -} - void ParseExtras(aiMetadata* metadata, const Extras& extras) { for (auto const &value : extras.mValues) { - ParseExtrasValue(metadata, value); + ParseExtensions(metadata, value); } } From 99c31045886039034bae70d44ba59320508d4e57 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 00:44:51 +0200 Subject: [PATCH 012/162] Rewrote gltf2 node extras import and added node extras export. No support for AI_AIVECTOR3D metadata type. No support for json arrays of metadata, just json objects. --- code/AssetLib/glTF2/glTF2Asset.h | 47 ++++++++++++++++++- code/AssetLib/glTF2/glTF2Asset.inl | 46 ++++++++++++++++++- code/AssetLib/glTF2/glTF2AssetWriter.inl | 41 ++++++++++++++++- code/AssetLib/glTF2/glTF2Exporter.cpp | 57 +++++++++++++++++++++++- code/AssetLib/glTF2/glTF2Importer.cpp | 34 +++++++++++--- code/Common/SceneCombiner.cpp | 3 ++ 6 files changed, 218 insertions(+), 10 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 44ab6c9c8..a4a615131 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,6 +378,51 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; +struct ExtrasValue; + +//! Represents a union of metadata values +struct ExtrasValue { + std::string name; + + Nullable mBoolValue; + Nullable mInt32Value; + Nullable mUint64Value; + Nullable mFloatValue; + Nullable mDoubleValue; + Nullable mStringValue; + Nullable> mMetadataValue; + + ExtrasValue() = default; + ~ExtrasValue() = default; + + ExtrasValue(const ExtrasValue& other) : + name(other.name), + mStringValue(other.mStringValue), + mDoubleValue(other.mDoubleValue), + mUint64Value(other.mUint64Value), + mInt32Value(other.mInt32Value), + mBoolValue(other.mBoolValue), + mMetadataValue(other.mMetadataValue) { + } +}; + +//! Represents metadata in an glTF object +struct Extras { + std::vector mValues; + + inline bool HasExtras() const { + return mValues.size() != 0; + } + + Extras() = default; + ~Extras() = default; + + Extras(const Extras &other) : + mValues(other.mValues) { + // empty + } +}; + //! Base class for all glTF top-level objects struct Object { int index; //!< The index of this object within its property container @@ -386,7 +431,7 @@ struct Object { std::string name; //!< The user-defined name of this object CustomExtension customExtensions; - CustomExtension extras; + Extras extras; //! Objects marked as special are not exported (used to emulate the binary body buffer) virtual bool IsSpecial() const { return false; } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d6..5dc51e7fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,6 +139,50 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } +inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { + ExtrasValue ret; + ret.name = name; + + if (obj.IsObject()) { + ret.mMetadataValue.value.reserve(obj.MemberCount()); + ret.mMetadataValue.isPresent = true; + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + } else if (obj.IsNumber()) { + if (obj.IsUint64()) { + ret.mUint64Value.value = obj.GetUint64(); + ret.mUint64Value.isPresent = true; + } else if (obj.IsInt()) { + ret.mInt32Value.value = obj.GetInt64(); + ret.mInt32Value.isPresent = true; + } else if (obj.IsDouble()) { + ret.mDoubleValue.value = obj.GetDouble(); + ret.mDoubleValue.isPresent = true; + } + } else if (obj.IsString()) { + ReadValue(obj, ret.mStringValue); + ret.mStringValue.isPresent = true; + } else if (obj.IsBool()) { + ret.mBoolValue.value = obj.GetBool(); + ret.mBoolValue.isPresent = true; + } + return ret; +} + +inline Extras ReadExtras(Value &obj) { + Extras ret; + + ret.mValues.reserve(obj.MemberCount()); + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + + return ret; +} + inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride) { if (src_stride == dst_stride) { @@ -248,7 +292,7 @@ inline void Object::ReadExtensions(Value &val) { inline void Object::ReadExtras(Value &val) { if (Value *curExtras = FindObject(val, "extras")) { - this->extras = glTF2::ReadExtensions("extras", *curExtras); + this->extras = glTF2::ReadExtras(*curExtras); } } diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 0be139595..e1fcaefd4 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,6 +620,44 @@ namespace glTF2 { } } + inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + Value valueNode; + + if (value.mStringValue.isPresent) { + MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl); + } else if (value.mDoubleValue.isPresent) { + MakeValue(valueNode, value.mDoubleValue.value, w.mAl); + } else if (value.mUint64Value.isPresent) { + MakeValue(valueNode, value.mUint64Value.value, w.mAl); + } else if (value.mInt32Value.isPresent) { + MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mBoolValue.isPresent) { + MakeValue(valueNode, value.mBoolValue.value, w.mAl); + } else if (value.mMetadataValue.isPresent) { + valueNode.SetObject(); + for (auto const &subvalue : value.mMetadataValue.value) { + WriteExtrasValue(valueNode, subvalue, w); + } + } + + parent.AddMember(StringRef(value.name), valueNode, w.mAl); + } + + inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) { + if (!extras.HasExtras()) { + return; + } + + Value extrasNode; + extrasNode.SetObject(); + + for (auto const &value : extras.mValues) { + WriteExtrasValue(extrasNode, value, w); + } + + obj.AddMember("extras", extrasNode, w.mAl); + } + inline void Write(Value& obj, Node& n, AssetWriter& w) { if (n.matrix.isPresent) { @@ -655,6 +693,8 @@ namespace glTF2 { if(n.skeletons.size()) { AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); } + + WriteExtras(obj, n.extras, w); } inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/) @@ -728,7 +768,6 @@ namespace glTF2 { } } - inline AssetWriter::AssetWriter(Asset& a) : mDoc() , mAsset(a) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index da7591d52..f8b1995d9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,6 +445,57 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { + + value.name = name.C_Str(); + switch (metadataEntry.mType) { + case AI_BOOL: + value.mBoolValue.value = *static_cast(metadataEntry.mData); + value.mBoolValue.isPresent = true; + break; + case AI_INT32: + value.mInt32Value.value = *static_cast(metadataEntry.mData); + value.mInt32Value.isPresent = true; + break; + case AI_UINT64: + value.mUint64Value.value = *static_cast(metadataEntry.mData); + value.mUint64Value.isPresent = true; + break; + case AI_FLOAT: + value.mFloatValue.value = *static_cast(metadataEntry.mData); + value.mFloatValue.isPresent = true; + break; + case AI_DOUBLE: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; + case AI_AISTRING: + value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); + value.mStringValue.isPresent = true; + break; + case AI_AIMETADATA: + const aiMetadata *subMetadata = static_cast(metadataEntry.mData); + value.mMetadataValue.value.resize(subMetadata->mNumProperties); + value.mMetadataValue.isPresent = true; + + for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + } + break; + } +} + +inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { + if (metadata == nullptr) { + return; + } + + extras.mValues.resize(metadata->mNumProperties); + for (unsigned int i = 0; i < metadata->mNumProperties; ++i) { + ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i)); + } +} + inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) { switch (map) { case aiTextureMapMode_Clamp: @@ -1344,7 +1395,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) { return node.GetIndex(); } -/* + /* * Export node and recursively calls ExportNode for all children. * Since these nodes are not the root node, we also export the parent Ref */ @@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; + if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { + ExportNodeExtras(n->mMetaData, node->extras); + } + if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { aiQuaternion quaternion; diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 293d3dea7..a14e6ad6f 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,11 +1033,33 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) { - if (extension.mValues.isPresent) { - for (auto const &subExtension : extension.mValues.value) { - ParseExtensions(metadata, subExtension); +void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { + + if (value.mBoolValue.isPresent) { + metadata->Add(value.name, value.mBoolValue.value); + } else if (value.mInt32Value.isPresent) { + metadata->Add(value.name, value.mInt32Value.value); + } else if (value.mUint64Value.isPresent) { + metadata->Add(value.name, value.mUint64Value.value); + } else if (value.mFloatValue.isPresent) { + metadata->Add(value.name, value.mFloatValue.value); + } else if (value.mDoubleValue.isPresent) { + metadata->Add(value.name, value.mDoubleValue.value); + } else if (value.mStringValue.isPresent) { + metadata->Add(value.name, aiString(value.mStringValue.value)); + } else if (value.mMetadataValue.isPresent) { + aiMetadata subMetadata; + for (auto const &subValue : value.mMetadataValue.value) { + ParseExtrasValue(&subMetadata, subValue); } + + metadata->Add(value.name, subMetadata); + } +} + +void ParseExtras(aiMetadata* metadata, const Extras& extras) { + for (auto const &value : extras.mValues) { + ParseExtrasValue(metadata, value); } } @@ -1059,12 +1081,12 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || node.extras) { + if (node.customExtensions || !node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); } - if (node.extras) { + if (node.extras.HasExtras()) { ParseExtras(ainode->mMetaData, node.extras); } } diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 2c2539e54..1d32436c2 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) { case AI_AIVECTOR3D: out.mData = new aiVector3D(*static_cast(in.mData)); break; + case AI_AIMETADATA: + out.mData = new aiMetadata(*static_cast(in.mData)); + break; default: ai_assert(false); break; From 233198baefa8be47bbea4235d438e337c8eda0f2 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:04:05 +0200 Subject: [PATCH 013/162] Fixed extras presence check in gltf2 import. --- code/AssetLib/glTF2/glTF2Exporter.cpp | 6 ++---- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index f8b1995d9..d3c88e479 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -486,7 +486,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { - if (metadata == nullptr) { + if (metadata == nullptr || metadata->mNumProperties == 0) { return; } @@ -1406,9 +1406,7 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; - if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { - ExportNodeExtras(n->mMetaData, node->extras); - } + ExportNodeExtras(n->mMetaData, node->extras); if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index a14e6ad6f..e88cd0f08 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1081,7 +1081,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || !node.extras.HasExtras()) { + if (node.customExtensions || node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); From cb4d0ab7aa497f0ab4ac53e4ace079a7eb53d95f Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:07:42 +0200 Subject: [PATCH 014/162] Added missing member copy in gltf2::ExtrasValue ctor. --- code/AssetLib/glTF2/glTF2Asset.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index a4a615131..722e6d119 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,9 +378,7 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; -struct ExtrasValue; - -//! Represents a union of metadata values +//! Represents a union of metadata values. Only one nullable is supposed to be set. struct ExtrasValue { std::string name; @@ -398,6 +396,7 @@ struct ExtrasValue { ExtrasValue(const ExtrasValue& other) : name(other.name), mStringValue(other.mStringValue), + mFloatValue(other.mFloatValue), mDoubleValue(other.mDoubleValue), mUint64Value(other.mUint64Value), mInt32Value(other.mInt32Value), @@ -406,7 +405,7 @@ struct ExtrasValue { } }; -//! Represents metadata in an glTF object +//! Represents metadata in an glTF2 object struct Extras { std::vector mValues; From da58fbe8fbe3252b5406cdfd2be6562d9d14ce69 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:33:05 +0200 Subject: [PATCH 015/162] Got rid of gltf2::ExtrasValue and used gltf2::CustomExtension instead --- code/AssetLib/glTF2/glTF2Asset.h | 29 +------------------- code/AssetLib/glTF2/glTF2Asset.inl | 34 +----------------------- code/AssetLib/glTF2/glTF2AssetWriter.inl | 10 +++---- code/AssetLib/glTF2/glTF2Exporter.cpp | 16 +++++------ code/AssetLib/glTF2/glTF2Importer.cpp | 26 +----------------- 5 files changed, 14 insertions(+), 101 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 722e6d119..1aa37b569 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,36 +378,9 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; -//! Represents a union of metadata values. Only one nullable is supposed to be set. -struct ExtrasValue { - std::string name; - - Nullable mBoolValue; - Nullable mInt32Value; - Nullable mUint64Value; - Nullable mFloatValue; - Nullable mDoubleValue; - Nullable mStringValue; - Nullable> mMetadataValue; - - ExtrasValue() = default; - ~ExtrasValue() = default; - - ExtrasValue(const ExtrasValue& other) : - name(other.name), - mStringValue(other.mStringValue), - mFloatValue(other.mFloatValue), - mDoubleValue(other.mDoubleValue), - mUint64Value(other.mUint64Value), - mInt32Value(other.mInt32Value), - mBoolValue(other.mBoolValue), - mMetadataValue(other.mMetadataValue) { - } -}; - //! Represents metadata in an glTF2 object struct Extras { - std::vector mValues; + std::vector mValues; inline bool HasExtras() const { return mValues.size() != 0; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 5dc51e7fa..3a7d127d3 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,45 +139,13 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } -inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { - ExtrasValue ret; - ret.name = name; - - if (obj.IsObject()) { - ret.mMetadataValue.value.reserve(obj.MemberCount()); - ret.mMetadataValue.isPresent = true; - for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { - auto &val = it->value; - ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); - } - } else if (obj.IsNumber()) { - if (obj.IsUint64()) { - ret.mUint64Value.value = obj.GetUint64(); - ret.mUint64Value.isPresent = true; - } else if (obj.IsInt()) { - ret.mInt32Value.value = obj.GetInt64(); - ret.mInt32Value.isPresent = true; - } else if (obj.IsDouble()) { - ret.mDoubleValue.value = obj.GetDouble(); - ret.mDoubleValue.isPresent = true; - } - } else if (obj.IsString()) { - ReadValue(obj, ret.mStringValue); - ret.mStringValue.isPresent = true; - } else if (obj.IsBool()) { - ret.mBoolValue.value = obj.GetBool(); - ret.mBoolValue.isPresent = true; - } - return ret; -} - inline Extras ReadExtras(Value &obj) { Extras ret; ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index e1fcaefd4..3acec58a5 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,7 +620,7 @@ namespace glTF2 { } } - inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) { Value valueNode; if (value.mStringValue.isPresent) { @@ -629,13 +629,13 @@ namespace glTF2 { MakeValue(valueNode, value.mDoubleValue.value, w.mAl); } else if (value.mUint64Value.isPresent) { MakeValue(valueNode, value.mUint64Value.value, w.mAl); - } else if (value.mInt32Value.isPresent) { - MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mInt64Value.isPresent) { + MakeValue(valueNode, value.mInt64Value.value, w.mAl); } else if (value.mBoolValue.isPresent) { MakeValue(valueNode, value.mBoolValue.value, w.mAl); - } else if (value.mMetadataValue.isPresent) { + } else if (value.mValues.isPresent) { valueNode.SetObject(); - for (auto const &subvalue : value.mMetadataValue.value) { + for (auto const &subvalue : value.mValues.value) { WriteExtrasValue(valueNode, subvalue, w); } } diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index d3c88e479..028ab5c17 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,7 +445,7 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } -inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) { value.name = name.C_Str(); switch (metadataEntry.mType) { @@ -454,17 +454,13 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mBoolValue.isPresent = true; break; case AI_INT32: - value.mInt32Value.value = *static_cast(metadataEntry.mData); - value.mInt32Value.isPresent = true; + value.mInt64Value.value = *static_cast(metadataEntry.mData); + value.mInt64Value.isPresent = true; break; case AI_UINT64: value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; - case AI_FLOAT: - value.mFloatValue.value = *static_cast(metadataEntry.mData); - value.mFloatValue.isPresent = true; - break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -475,11 +471,11 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name break; case AI_AIMETADATA: const aiMetadata *subMetadata = static_cast(metadataEntry.mData); - value.mMetadataValue.value.resize(subMetadata->mNumProperties); - value.mMetadataValue.isPresent = true; + value.mValues.value.resize(subMetadata->mNumProperties); + value.mValues.isPresent = true; for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { - ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i)); } break; } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index e88cd0f08..f34465444 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,33 +1033,9 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { - - if (value.mBoolValue.isPresent) { - metadata->Add(value.name, value.mBoolValue.value); - } else if (value.mInt32Value.isPresent) { - metadata->Add(value.name, value.mInt32Value.value); - } else if (value.mUint64Value.isPresent) { - metadata->Add(value.name, value.mUint64Value.value); - } else if (value.mFloatValue.isPresent) { - metadata->Add(value.name, value.mFloatValue.value); - } else if (value.mDoubleValue.isPresent) { - metadata->Add(value.name, value.mDoubleValue.value); - } else if (value.mStringValue.isPresent) { - metadata->Add(value.name, aiString(value.mStringValue.value)); - } else if (value.mMetadataValue.isPresent) { - aiMetadata subMetadata; - for (auto const &subValue : value.mMetadataValue.value) { - ParseExtrasValue(&subMetadata, subValue); - } - - metadata->Add(value.name, subMetadata); - } -} - void ParseExtras(aiMetadata* metadata, const Extras& extras) { for (auto const &value : extras.mValues) { - ParseExtrasValue(metadata, value); + ParseExtensions(metadata, value); } } From abfe8ad413f031c144b4b4bdf00e7541092a9135 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Mon, 1 Aug 2022 14:39:10 +0200 Subject: [PATCH 016/162] Added suggested changes and fixed automated check errors --- code/AssetLib/glTF2/glTF2Asset.h | 27 +-------------------------- code/AssetLib/glTF2/glTF2Asset.inl | 2 +- code/AssetLib/glTF2/glTF2Exporter.cpp | 10 +++++++++- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 1a44b8377..754d6b593 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -383,32 +383,7 @@ struct Extras { std::vector mValues; inline bool HasExtras() const { - return mValues.size() != 0; - } - - Extras() = default; - ~Extras() = default; - - Extras(const Extras &other) : - mValues(other.mValues) { - // empty - } -}; - -//! Represents metadata in an glTF2 object -struct Extras { - std::vector mValues; - - inline bool HasExtras() const { - return mValues.size() != 0; - } - - Extras() = default; - ~Extras() = default; - - Extras(const Extras &other) : - mValues(other.mValues) { - // empty + return !mValues.empty(); } }; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 3a7d127d3..891fa27b5 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -145,7 +145,7 @@ inline Extras ReadExtras(Value &obj) { ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); + ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 028ab5c17..2996a8805 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -461,6 +461,10 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; + case AI_FLOAT: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -469,7 +473,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); value.mStringValue.isPresent = true; break; - case AI_AIMETADATA: + case AI_AIMETADATA: { const aiMetadata *subMetadata = static_cast(metadataEntry.mData); value.mValues.value.resize(subMetadata->mNumProperties); value.mValues.isPresent = true; @@ -479,6 +483,10 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } break; } + default: + // AI_AIVECTOR3D not handled + break; + } } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { From b2ea018fd57326a6421375cc7999d08a7ee341a2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 11 Sep 2022 17:04:58 +0200 Subject: [PATCH 017/162] Use user-define element destructor. --- code/AssetLib/FBX/FBXParser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/FBX/FBXParser.h b/code/AssetLib/FBX/FBXParser.h index 597096548..67707342e 100644 --- a/code/AssetLib/FBX/FBXParser.h +++ b/code/AssetLib/FBX/FBXParser.h @@ -89,7 +89,7 @@ class Element { public: Element(const Token& key_token, Parser& parser); - ~Element() = default; + ~Element(): const Scope* Compound() const { return compound; From 822b2406943f4bc426b9260a5bba523d65aabe26 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 8 Nov 2022 23:09:50 +0200 Subject: [PATCH 018/162] Support both pbrSpecGlos and materials_specular --- code/AssetLib/glTF2/glTF2Asset.h | 17 +++++++++++++ code/AssetLib/glTF2/glTF2Asset.inl | 22 +++++++++++++++- code/AssetLib/glTF2/glTF2AssetWriter.h | 1 + code/AssetLib/glTF2/glTF2AssetWriter.inl | 27 ++++++++++++++++++-- code/AssetLib/glTF2/glTF2Exporter.cpp | 32 +++++++++++++++++++++--- code/AssetLib/glTF2/glTF2Exporter.h | 2 ++ code/AssetLib/glTF2/glTF2Importer.cpp | 15 ++++++++++- include/assimp/material.h | 1 + 8 files changed, 110 insertions(+), 7 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 3becc4d9b..b241a4b59 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * glTF Extensions Support: * KHR_materials_pbrSpecularGlossiness full + * KHR_materials_specular full * KHR_materials_unlit full * KHR_lights_punctual full * KHR_materials_sheen full @@ -718,6 +719,7 @@ const vec4 defaultBaseColor = { 1, 1, 1, 1 }; const vec3 defaultEmissiveFactor = { 0, 0, 0 }; const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 }; const vec3 defaultSpecularFactor = { 1, 1, 1 }; +const vec3 defaultSpecularColorFactor = { 0, 0, 0 }; const vec3 defaultSheenFactor = { 0, 0, 0 }; const vec3 defaultAttenuationColor = { 1, 1, 1 }; @@ -761,6 +763,16 @@ struct PbrSpecularGlossiness { void SetDefaults(); }; +struct MaterialSpecular { + float specularFactor; + vec3 specularColorFactor; + TextureInfo specularTexture; + TextureInfo specularColorTexture; + + MaterialSpecular() { SetDefaults(); } + void SetDefaults(); +}; + struct MaterialSheen { vec3 sheenColorFactor; float sheenRoughnessFactor; @@ -818,6 +830,9 @@ struct Material : public Object { //extension: KHR_materials_pbrSpecularGlossiness Nullable pbrSpecularGlossiness; + //extension: KHR_materials_specular + Nullable materialSpecular; + //extension: KHR_materials_sheen Nullable materialSheen; @@ -1098,6 +1113,7 @@ public: //! Keeps info about the enabled extensions struct Extensions { bool KHR_materials_pbrSpecularGlossiness; + bool KHR_materials_specular; bool KHR_materials_unlit; bool KHR_lights_punctual; bool KHR_texture_transform; @@ -1112,6 +1128,7 @@ public: Extensions() : KHR_materials_pbrSpecularGlossiness(false), + KHR_materials_specular(false), KHR_materials_unlit(false), KHR_lights_punctual(false), KHR_texture_transform(false), diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d6..aaa652dcd 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1236,7 +1236,7 @@ inline void Material::Read(Value &material, Asset &r) { ReadMember(material, "alphaCutoff", this->alphaCutoff); if (Value *extensions = FindObject(material, "extensions")) { - if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { + if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { //TODO: Maybe ignore this if KHR_materials_specular is also defined if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) { PbrSpecularGlossiness pbrSG; @@ -1249,6 +1249,19 @@ inline void Material::Read(Value &material, Asset &r) { this->pbrSpecularGlossiness = Nullable(pbrSG); } } + + if (r.extensionsUsed.KHR_materials_specular) { + if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) { + MaterialSpecular specular; + + ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor); + ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture); + ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor); + ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture); + + this->materialSpecular = Nullable(specular); + } + } // Extension KHR_texture_transform is handled in ReadTextureProperty @@ -1337,6 +1350,12 @@ inline void PbrSpecularGlossiness::SetDefaults() { glossinessFactor = 1.0f; } +inline void MaterialSpecular::SetDefaults() { + //KHR_materials_specular properties + SetVector(specularColorFactor, defaultSpecularColorFactor); + specularFactor = 0.f; +} + inline void MaterialSheen::SetDefaults() { //KHR_materials_sheen properties SetVector(sheenColorFactor, defaultSheenFactor); @@ -2018,6 +2037,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) { } CHECK_EXT(KHR_materials_pbrSpecularGlossiness); + CHECK_EXT(KHR_materials_specular); CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_lights_punctual); CHECK_EXT(KHR_texture_transform); diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.h b/code/AssetLib/glTF2/glTF2AssetWriter.h index 089a15844..5489ec2d4 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.h +++ b/code/AssetLib/glTF2/glTF2AssetWriter.h @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * glTF Extensions Support: * KHR_materials_pbrSpecularGlossiness: full + * KHR_materials_specular: full * KHR_materials_unlit: full * KHR_materials_sheen: full * KHR_materials_clearcoat: full diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 0be139595..c57603bb0 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -418,6 +418,25 @@ namespace glTF2 { exts.AddMember("KHR_materials_unlit", unlit, w.mAl); } + if (m.materialSpecular.isPresent) { + Value materialSpecular(rapidjson::Type::kObjectType); + materialSpecular.SetObject(); + + MaterialSpecular &specular = m.materialSpecular.value; + + if (specular.specularFactor != 0.f) { + WriteFloat(materialSpecular, specular.specularFactor, "specularFactor", w.mAl); + WriteTex(materialSpecular, specular.specularTexture, "specularTexture", w.mAl); + } + if (specular.specularColorFactor[0] != defaultSpecularColorFactor[0] && specular.specularColorFactor[1] != defaultSpecularColorFactor[1] && specular.specularColorFactor[2] != defaultSpecularColorFactor[2]) { + WriteVec(materialSpecular, specular.specularColorFactor, "specularColorFactor", w.mAl); + WriteTex(materialSpecular, specular.specularColorTexture, "specularColorTexture", w.mAl); + } + + if (!materialSpecular.ObjectEmpty()) { + exts.AddMember("KHR_materials_specular", materialSpecular, w.mAl); + } + if (m.materialSheen.isPresent) { Value materialSheen(rapidjson::Type::kObjectType); @@ -536,7 +555,7 @@ namespace glTF2 { inline void Write(Value& obj, Mesh& m, AssetWriter& w) { - /****************** Primitives *******************/ + /****************** Primitives *******************/ Value primitives; primitives.SetArray(); primitives.Reserve(unsigned(m.primitives.size()), w.mAl); @@ -915,6 +934,10 @@ namespace glTF2 { exts.PushBack(StringRef("KHR_materials_unlit"), mAl); } + if (this->mAsset.extensionsUsed.KHR_materials_specular) { + exts.PushBack(StringRef("KHR_materials_specular"), mAl); + } + if (this->mAsset.extensionsUsed.KHR_materials_sheen) { exts.PushBack(StringRef("KHR_materials_sheen"), mAl); } @@ -962,7 +985,7 @@ namespace glTF2 { if (d.mObjs.empty()) return; Value* container = &mDoc; - const char* context = "Document"; + const char* context = "Document"; if (d.mExtId) { Value* exts = FindObject(mDoc, "extensions"); diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 3bfe49fba..15c193d36 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -644,7 +644,10 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo bool result = false; // If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension // NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular - + // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. + if (mat.Get(AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS) != AI_SUCCESS) { + return false; + } if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) { result = true; } else { @@ -674,6 +677,24 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo return result; } +bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) { + // Specular requires either/or + if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) { + return false; + } + + // default factors of zero disables specular, so do not export + if (specular.specularFactor == 0.0f && (specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2])) { + return false; + } + + // Add any appropriate textures + GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR); + GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR); + + return true; +} + bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { // Return true if got any valid Sheen properties or textures if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) { @@ -816,7 +837,7 @@ void glTF2Exporter::ExportMaterials() { { // KHR_materials_pbrSpecularGlossiness extension - // NOTE: This extension is being considered for deprecation (Dec 2020) + // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. PbrSpecularGlossiness pbrSG; if (GetMatSpecGloss(mat, pbrSG)) { mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; @@ -833,7 +854,12 @@ void glTF2Exporter::ExportMaterials() { } else { // These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness if (!m->pbrSpecularGlossiness.isPresent) { - // Sheen + MaterialSpecular specular; + if (GetMatSpecular(mat, specular)) { + mAsset->extensionsUsed.KHR_materials_specular = true; + m->materialSpecular = Nullable(specular); + } + MaterialSheen sheen; if (GetMatSheen(mat, sheen)) { mAsset->extensionsUsed.KHR_materials_sheen = true; diff --git a/code/AssetLib/glTF2/glTF2Exporter.h b/code/AssetLib/glTF2/glTF2Exporter.h index 99425228e..f211d2d53 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.h +++ b/code/AssetLib/glTF2/glTF2Exporter.h @@ -76,6 +76,7 @@ struct OcclusionTextureInfo; struct Node; struct Texture; struct PbrSpecularGlossiness; +struct MaterialSpecular; struct MaterialSheen; struct MaterialClearcoat; struct MaterialTransmission; @@ -116,6 +117,7 @@ protected: aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec4 &prop, const char *propName, int type, int idx) const; aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec3 &prop, const char *propName, int type, int idx) const; bool GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG); + bool GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular); bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen); bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat); bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 947edc8d5..1757026fe 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -283,8 +283,9 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); // pbrSpecularGlossiness - if (mat.pbrSpecularGlossiness.isPresent) { + if (mat.pbrSpecularGlossiness.isPresent) { // TODO: Consider importing this only if KHR_materials_specular isn't also defined PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; + aimat->AddProperty(new int(1), 1, AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS); SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); @@ -307,6 +308,18 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); + // KHR_materials_specular + if (mat.materialSpecular.isPresent) { + MaterialSpecular &specular = mat.materialSpecular.value; + // Default values of zero disables Specular + if (std::memcmp(specular.specularColorFactor, defaultSpecularColorFactor, sizeof(glTFCommon::vec3)) != 0 || specular.specularFactor != 0.0f) { + SetMaterialColorProperty(r, specular.specularColorFactor, aimat, AI_MATKEY_COLOR_SPECULAR); + aimat->AddProperty(&specular.specularFactor, 1, AI_MATKEY_SPECULAR_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularTexture, aimat, aiTextureType_SPECULAR); + SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularColorTexture, aimat, aiTextureType_SPECULAR); + } + } + // KHR_materials_sheen if (mat.materialSheen.isPresent) { MaterialSheen &sheen = mat.materialSheen.value; diff --git a/include/assimp/material.h b/include/assimp/material.h index 0052888d1..92f7ab8ca 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -1000,6 +1000,7 @@ extern "C" { // Specular Color. // Note: Metallic/Roughness may also have a Specular Color // AI_MATKEY_COLOR_SPECULAR +#define AI_MATKEY_USE_PBR_SPECULAR_GLOSSINESS "$mat.useGltfPbrSpecularGlossiness", 0, 0 #define AI_MATKEY_SPECULAR_FACTOR "$mat.specularFactor", 0, 0 // Glossiness factor. 0.0 = Completely Rough, 1.0 = Perfectly Smooth #define AI_MATKEY_GLOSSINESS_FACTOR "$mat.glossinessFactor", 0, 0 From ffaf378ee6107221c3a731039d3872910801137f Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 10 Nov 2022 20:37:46 +0200 Subject: [PATCH 019/162] fixed misnamed matkey --- include/assimp/material.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/assimp/material.h b/include/assimp/material.h index 92f7ab8ca..3a623d10e 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -1000,7 +1000,7 @@ extern "C" { // Specular Color. // Note: Metallic/Roughness may also have a Specular Color // AI_MATKEY_COLOR_SPECULAR -#define AI_MATKEY_USE_PBR_SPECULAR_GLOSSINESS "$mat.useGltfPbrSpecularGlossiness", 0, 0 +#define AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS "$mat.useGltfPbrSpecularGlossiness", 0, 0 #define AI_MATKEY_SPECULAR_FACTOR "$mat.specularFactor", 0, 0 // Glossiness factor. 0.0 = Completely Rough, 1.0 = Perfectly Smooth #define AI_MATKEY_GLOSSINESS_FACTOR "$mat.glossinessFactor", 0, 0 From 1cd5841b2f331ba630d7a873a4e59dbf3449d711 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 18 Nov 2022 17:24:37 +0200 Subject: [PATCH 020/162] . --- code/AssetLib/glTF2/glTF2AssetWriter.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index c57603bb0..de1e25fc1 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -435,6 +435,7 @@ namespace glTF2 { if (!materialSpecular.ObjectEmpty()) { exts.AddMember("KHR_materials_specular", materialSpecular, w.mAl); + } } if (m.materialSheen.isPresent) { From 371d5c78f494af360333c6246e9ff91c3d2520f6 Mon Sep 17 00:00:00 2001 From: Justice Colby Date: Mon, 21 Nov 2022 15:49:48 -0800 Subject: [PATCH 021/162] Updated ConvertMaterials function to assign appopriate material index when using material references. --- code/AssetLib/X/XFileImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/X/XFileImporter.cpp b/code/AssetLib/X/XFileImporter.cpp index b96b041aa..d777eee32 100644 --- a/code/AssetLib/X/XFileImporter.cpp +++ b/code/AssetLib/X/XFileImporter.cpp @@ -580,7 +580,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vectormMaterials[b]->Get( AI_MATKEY_NAME, name); if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) { - oldMat.sceneIndex = a; + oldMat.sceneIndex = b; break; } } From fa00571049b601d970ebc61331fc9fbb66e217ce Mon Sep 17 00:00:00 2001 From: Adam Beili <54665621+Beilinson@users.noreply.github.com> Date: Sun, 26 Mar 2023 14:52:44 +0200 Subject: [PATCH 022/162] fixed compilation bug --- code/AssetLib/glTF2/glTF2Exporter.cpp | 35 ++++++++++++--------------- code/AssetLib/glTF2/glTF2Importer.cpp | 25 +++++++++---------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 464a045b9..17140aa6a 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -640,14 +640,16 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial &mat, vec3 &prop, const cha return result; } +// This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) { - bool result = false; - // If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension - // NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular - // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. - if (mat.Get(AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS) != AI_SUCCESS) { + int usePbrSpecGloss; + if (mat.Get(AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS, usePbrSpecGloss) != AI_SUCCESS) { return false; } + + bool result = false; + + // If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) { result = true; } else { @@ -678,21 +680,16 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo } bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) { - // Specular requires either/or - if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) { - return false; + // Specular requires either/or, default factors of zero disables specular, so do not export + bool result = false; + if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) == AI_SUCCESS && specular.specularFactor != 0.0f) { + GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR); + result = true; + } else if (mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) == AI_SUCCESS && !(specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2])) { + GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR); + result = true; } - - // default factors of zero disables specular, so do not export - if (specular.specularFactor == 0.0f && (specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2])) { - return false; - } - - // Add any appropriate textures - GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR); - GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR); - - return true; + return result; } bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 805ae0548..f298e7037 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -278,8 +278,19 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); + // KHR_materials_specular + if (mat.materialSpecular.isPresent) { + MaterialSpecular &specular = mat.materialSpecular.value; + // Default values of zero disables Specular + if (std::memcmp(specular.specularColorFactor, defaultSpecularColorFactor, sizeof(glTFCommon::vec3)) != 0 || specular.specularFactor != 0.0f) { + SetMaterialColorProperty(r, specular.specularColorFactor, aimat, AI_MATKEY_COLOR_SPECULAR); + aimat->AddProperty(&specular.specularFactor, 1, AI_MATKEY_SPECULAR_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularTexture, aimat, aiTextureType_SPECULAR); + SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularColorTexture, aimat, aiTextureType_SPECULAR); + } + } // pbrSpecularGlossiness - if (mat.pbrSpecularGlossiness.isPresent) { // TODO: Consider importing this only if KHR_materials_specular isn't also defined + else if (mat.pbrSpecularGlossiness.isPresent) { PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; aimat->AddProperty(new int(1), 1, AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS); @@ -304,18 +315,6 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); - // KHR_materials_specular - if (mat.materialSpecular.isPresent) { - MaterialSpecular &specular = mat.materialSpecular.value; - // Default values of zero disables Specular - if (std::memcmp(specular.specularColorFactor, defaultSpecularColorFactor, sizeof(glTFCommon::vec3)) != 0 || specular.specularFactor != 0.0f) { - SetMaterialColorProperty(r, specular.specularColorFactor, aimat, AI_MATKEY_COLOR_SPECULAR); - aimat->AddProperty(&specular.specularFactor, 1, AI_MATKEY_SPECULAR_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularTexture, aimat, aiTextureType_SPECULAR); - SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularColorTexture, aimat, aiTextureType_SPECULAR); - } - } - // KHR_materials_sheen if (mat.materialSheen.isPresent) { MaterialSheen &sheen = mat.materialSheen.value; From 83053f3d564a0ba624c0165364403e8b2e6bcba3 Mon Sep 17 00:00:00 2001 From: Adam Beili <54665621+Beilinson@users.noreply.github.com> Date: Sun, 26 Mar 2023 16:55:38 +0200 Subject: [PATCH 023/162] Made usePbrSpecGloss a exportproperty, fixed mat_specular to spec --- code/AssetLib/glTF2/glTF2Exporter.cpp | 34 +++++++++++++-------------- code/AssetLib/glTF2/glTF2Importer.cpp | 1 - include/assimp/config.h.in | 11 +++++++++ include/assimp/material.h | 1 - test/unit/utglTF2ImportExport.cpp | 4 +++- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 17140aa6a..3a1441ad9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -642,13 +642,7 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial &mat, vec3 &prop, const cha // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) { - int usePbrSpecGloss; - if (mat.Get(AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS, usePbrSpecGloss) != AI_SUCCESS) { - return false; - } - bool result = false; - // If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) { result = true; @@ -681,15 +675,21 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) { // Specular requires either/or, default factors of zero disables specular, so do not export - bool result = false; - if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) == AI_SUCCESS && specular.specularFactor != 0.0f) { - GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR); - result = true; - } else if (mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) == AI_SUCCESS && !(specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2])) { - GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR); - result = true; + if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) { + return false; } - return result; + // The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0 + const bool colorFactorIsZero = specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2]; + if (specular.specularFactor == 0.0f && colorFactorIsZero) { + return false; + } else if (specular.specularFactor == 0.0f) { + specular.specularFactor = 1.0f; + } else if (colorFactorIsZero) { + specular.specularColorFactor[0] = specular.specularColorFactor[1] = specular.specularColorFactor[2] = 1.0f; + } + GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR); + GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR); + return true; } bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { @@ -755,7 +755,7 @@ bool glTF2Exporter::GetMatEmissiveStrength(const aiMaterial &mat, glTF2::Materia return mat.Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveStrength.emissiveStrength) == aiReturn_SUCCESS; } -void glTF2Exporter::ExportMaterials() { +void glTF2Exporter::ExportMaterials(ExportProperties *pProperties) { aiString aiName; for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { ai_assert(mScene->mMaterials[i] != nullptr); @@ -836,9 +836,9 @@ void glTF2Exporter::ExportMaterials() { m->alphaMode = alphaMode.C_Str(); } - { + // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. + if (pProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) { // KHR_materials_pbrSpecularGlossiness extension - // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. PbrSpecularGlossiness pbrSG; if (GetMatSpecGloss(mat, pbrSG)) { mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index f298e7037..4a3ee4928 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -292,7 +292,6 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M // pbrSpecularGlossiness else if (mat.pbrSpecularGlossiness.isPresent) { PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; - aimat->AddProperty(new int(1), 1, AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS); SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index ad16fa88c..9e843a20d 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -1065,6 +1065,17 @@ enum aiComponent */ #define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS" +/** @brief Specifies whether to use the deprecated KHR_materials_pbrSpecularGlossiness extension + * + * When this flag is undefined any material with specularity will use the new KHR_materials_specular + * extension. Enabling this flag will revert to the deprecated extension. Note that exporting + * KHR_materials_pbrSpecularGlossiness with extensions other than KHR_materials_unlit is unsupported, + * including the basic pbrMetallicRoughness spec. + * + * Property type: Bool. Default value: false. + */ +#define AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS "USE_GLTF_PBR_SPECULAR_GLOSSINESS" + /** * @brief Specifies the blob name, assimp uses for exporting. * diff --git a/include/assimp/material.h b/include/assimp/material.h index f583ad8a8..80551e53d 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -1000,7 +1000,6 @@ extern "C" { // Specular Color. // Note: Metallic/Roughness may also have a Specular Color // AI_MATKEY_COLOR_SPECULAR -#define AI_MATKEY_USE_GLTF_PBR_SPECULAR_GLOSSINESS "$mat.useGltfPbrSpecularGlossiness", 0, 0 #define AI_MATKEY_SPECULAR_FACTOR "$mat.specularFactor", 0, 0 // Glossiness factor. 0.0 = Completely Rough, 1.0 = Perfectly Smooth #define AI_MATKEY_GLOSSINESS_FACTOR "$mat.glossinessFactor", 0, 0 diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index ef3fc4137..c7d01fbcb 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -220,7 +220,9 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); // Export - EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb")); + ExportProperties props; + props.SetPropertyBool(, true); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props)); // And re-import EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true)); From b6ecba9114e4bfa5edcf93b9f7ceea5c73b4fd9b Mon Sep 17 00:00:00 2001 From: Adam Beili <54665621+Beilinson@users.noreply.github.com> Date: Sun, 26 Mar 2023 17:03:46 +0200 Subject: [PATCH 024/162] fix --- code/AssetLib/glTF2/glTF2Exporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 3a1441ad9..777df50fd 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -755,7 +755,7 @@ bool glTF2Exporter::GetMatEmissiveStrength(const aiMaterial &mat, glTF2::Materia return mat.Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveStrength.emissiveStrength) == aiReturn_SUCCESS; } -void glTF2Exporter::ExportMaterials(ExportProperties *pProperties) { +void glTF2Exporter::ExportMaterials() { aiString aiName; for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { ai_assert(mScene->mMaterials[i] != nullptr); @@ -837,7 +837,7 @@ void glTF2Exporter::ExportMaterials(ExportProperties *pProperties) { } // This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default. - if (pProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) { + if (mProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) { // KHR_materials_pbrSpecularGlossiness extension PbrSpecularGlossiness pbrSG; if (GetMatSpecGloss(mat, pbrSG)) { From 8ac0af5c58788e48412dc19fca49808fdd357c3f Mon Sep 17 00:00:00 2001 From: Adam Beili <54665621+Beilinson@users.noreply.github.com> Date: Sun, 26 Mar 2023 17:13:16 +0200 Subject: [PATCH 025/162] . --- code/AssetLib/glTF2/glTF2Asset.inl | 2 +- code/AssetLib/glTF2/glTF2AssetWriter.inl | 2 +- test/unit/utglTF2ImportExport.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db773513b..3a3ba376e 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1236,7 +1236,7 @@ inline void Material::Read(Value &material, Asset &r) { ReadMember(material, "alphaCutoff", this->alphaCutoff); if (Value *extensions = FindObject(material, "extensions")) { - if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { //TODO: Maybe ignore this if KHR_materials_specular is also defined + if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) { PbrSpecularGlossiness pbrSG; diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index ef1c66b3b..f6fc7adff 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -424,7 +424,7 @@ namespace glTF2 { MaterialSpecular &specular = m.materialSpecular.value; - if (specular.specularFactor != 0.f) { + if (specular.specularFactor != 0.0f) { WriteFloat(materialSpecular, specular.specularFactor, "specularFactor", w.mAl); WriteTex(materialSpecular, specular.specularTexture, "specularTexture", w.mAl); } diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index c7d01fbcb..b63fd3944 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -221,7 +221,7 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi EXPECT_NE(nullptr, scene); // Export ExportProperties props; - props.SetPropertyBool(, true); + props.SetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS, true); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props)); // And re-import From 5d841ec9a5889f910fe0ed906056616babefe6cf Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 16 Apr 2023 18:20:14 +0200 Subject: [PATCH 026/162] Refactoring: Cleanup post-processing steps. --- code/AssetLib/3DS/3DSHelper.h | 4 -- code/AssetLib/X3D/X3DExporter.hpp | 2 - code/Geometry/GeometryUtils.cpp | 13 ++++ code/Geometry/GeometryUtils.h | 2 + code/PostProcessing/ArmaturePopulate.cpp | 27 +++------ code/PostProcessing/ArmaturePopulate.h | 8 +-- .../ComputeUVMappingProcess.cpp | 37 ++++-------- code/PostProcessing/ConvertToLHProcess.cpp | 9 --- code/PostProcessing/DeboneProcess.cpp | 12 ++-- code/PostProcessing/FindDegenerates.cpp | 3 +- code/PostProcessing/RemoveVCProcess.cpp | 59 ------------------- code/PostProcessing/ScaleProcess.cpp | 8 +-- code/PostProcessing/SortByPTypeProcess.cpp | 21 +++---- .../SplitByBoneCountProcess.cpp | 18 +++--- code/PostProcessing/SplitByBoneCountProcess.h | 13 +++- include/assimp/Vertex.h | 2 +- 16 files changed, 75 insertions(+), 163 deletions(-) diff --git a/code/AssetLib/3DS/3DSHelper.h b/code/AssetLib/3DS/3DSHelper.h index 06c36bfeb..2279d105c 100644 --- a/code/AssetLib/3DS/3DSHelper.h +++ b/code/AssetLib/3DS/3DSHelper.h @@ -397,10 +397,6 @@ struct Material { Material(const Material &other) = default; - Material(Material &&other) AI_NO_EXCEPT = default; - - Material &operator=(Material &&other) AI_NO_EXCEPT = default; - virtual ~Material() = default; //! Name of the material diff --git a/code/AssetLib/X3D/X3DExporter.hpp b/code/AssetLib/X3D/X3DExporter.hpp index e77aa6877..babf552dd 100644 --- a/code/AssetLib/X3D/X3DExporter.hpp +++ b/code/AssetLib/X3D/X3DExporter.hpp @@ -58,8 +58,6 @@ class X3DExporter { Value(value) { // empty } - - SAttribute(SAttribute &&rhs) AI_NO_EXCEPT = default; }; /***********************************************/ diff --git a/code/Geometry/GeometryUtils.cpp b/code/Geometry/GeometryUtils.cpp index ab735aa6e..92a3aa853 100644 --- a/code/Geometry/GeometryUtils.cpp +++ b/code/Geometry/GeometryUtils.cpp @@ -76,4 +76,17 @@ ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh return area; } +// ------------------------------------------------------------------------------------------------ +// Check whether a ray intersects a plane and find the intersection point +bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, + const aiVector3D& planeNormal, aiVector3D& pos) { + const ai_real b = planeNormal * (planePos - ray.pos); + ai_real h = ray.dir * planeNormal; + if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0) + return false; + + pos = ray.pos + (ray.dir * h); + return true; +} + } // namespace Assimp diff --git a/code/Geometry/GeometryUtils.h b/code/Geometry/GeometryUtils.h index ab49380de..bd2038f78 100644 --- a/code/Geometry/GeometryUtils.h +++ b/code/Geometry/GeometryUtils.h @@ -62,6 +62,8 @@ public: /// @param mesh The mesh containing the face /// @return The area. static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ); + + static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos); }; } // namespace Assimp diff --git a/code/PostProcessing/ArmaturePopulate.cpp b/code/PostProcessing/ArmaturePopulate.cpp index a05cd91e9..a29735205 100644 --- a/code/PostProcessing/ArmaturePopulate.cpp +++ b/code/PostProcessing/ArmaturePopulate.cpp @@ -47,11 +47,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -/// The default class constructor. -ArmaturePopulate::ArmaturePopulate() = default; +static bool IsBoneNode(const aiString &bone_name, std::vector &bones) { + for (aiBone *bone : bones) { + if (bone->mName == bone_name) { + return true; + } + } -/// The class destructor. -ArmaturePopulate::~ArmaturePopulate() = default; + return false; +} bool ArmaturePopulate::IsActive(unsigned int pFlags) const { return (pFlags & aiProcess_PopulateArmatureData) != 0; @@ -78,9 +82,8 @@ void ArmaturePopulate::Execute(aiScene *out) { aiBone *bone = kvp.first; aiNode *bone_node = kvp.second; ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str()); + // lcl transform grab - done in generate_nodes :) - - // bone->mOffsetMatrix = bone_node->mTransformation; aiNode *armature = GetArmatureRoot(bone_node, bones); ai_assert(armature); @@ -212,18 +215,6 @@ aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, return nullptr; } -// Simple IsBoneNode check if this could be a bone -bool ArmaturePopulate::IsBoneNode(const aiString &bone_name, - std::vector &bones) { - for (aiBone *bone : bones) { - if (bone->mName == bone_name) { - return true; - } - } - - return false; -} - // Pop this node by name from the stack if found // Used in multiple armature situations with duplicate node / bone names // Known flaw: cannot have nodes with bone names, will be fixed in later release diff --git a/code/PostProcessing/ArmaturePopulate.h b/code/PostProcessing/ArmaturePopulate.h index 530932f48..83cbf8cf7 100644 --- a/code/PostProcessing/ArmaturePopulate.h +++ b/code/PostProcessing/ArmaturePopulate.h @@ -69,10 +69,10 @@ namespace Assimp { class ASSIMP_API ArmaturePopulate : public BaseProcess { public: /// The default class constructor. - ArmaturePopulate(); + ArmaturePopulate() = default; /// The class destructor. - virtual ~ArmaturePopulate(); + virtual ~ArmaturePopulate() = default; /// Overwritten, @see BaseProcess virtual bool IsActive( unsigned int pFlags ) const; @@ -86,9 +86,6 @@ public: static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector &bone_list); - static bool IsBoneNode(const aiString &bone_name, - std::vector &bones); - static aiNode *GetNodeFromStack(const aiString &node_name, std::vector &nodes); @@ -108,5 +105,4 @@ public: } // Namespace Assimp - #endif // SCALE_PROCESS_H_ diff --git a/code/PostProcessing/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp index a5472668b..e81f63d42 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,10 +41,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file GenUVCoords step */ - #include "ComputeUVMappingProcess.h" #include "ProcessHelper.h" #include +#include "Geometry/GeometryUtils.h" using namespace Assimp; @@ -59,31 +58,17 @@ namespace { // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const -{ +bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_GenUVCoords) != 0; } -// ------------------------------------------------------------------------------------------------ -// Check whether a ray intersects a plane and find the intersection point -inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, - const aiVector3D& planeNormal, aiVector3D& pos) -{ - const ai_real b = planeNormal * (planePos - ray.pos); - ai_real h = ray.dir * planeNormal; - if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0) - return false; - - pos = ray.pos + (ray.dir * h); - return true; -} - // ------------------------------------------------------------------------------------------------ // Find the first empty UV channel in a mesh -inline unsigned int FindEmptyUVChannel (aiMesh* mesh) -{ +inline unsigned int FindEmptyUVChannel (aiMesh* mesh) { for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) - if (!mesh->mTextureCoords[m])return m; + if (!mesh->mTextureCoords[m]) { + return m; + } ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found"); return UINT_MAX; @@ -91,8 +76,7 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh) // ------------------------------------------------------------------------------------------------ // Try to remove UV seams -void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) -{ +void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { // TODO: just a very rough algorithm. I think it could be done // much easier, but I don't know how and am currently too tired to // to think about a better solution. @@ -103,10 +87,11 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) const static ai_real LOWER_EPSILON = ai_real( 10e-3 ); const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 ); - for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) - { + for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) { const aiFace& face = mesh->mFaces[fidx]; - if (face.mNumIndices < 3) continue; // triangles and polygons only, please + if (face.mNumIndices < 3) { + continue; // triangles and polygons only, please + } unsigned int smallV = face.mNumIndices, large = smallV; bool zero = false, one = false, round_to_zero = false; diff --git a/code/PostProcessing/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp index 08e3fe48a..e67bf030f 100644 --- a/code/PostProcessing/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -219,13 +217,6 @@ void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) { // rotation keys for (unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) { - /* That's the safe version, but the float errors add up. So we try the short version instead - aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix(); - rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3; - rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2; - aiQuaternion rotquat( rotmat); - pAnim->mRotationKeys[a].mValue = rotquat; - */ pAnim->mRotationKeys[a].mValue.x *= -1.0f; pAnim->mRotationKeys[a].mValue.y *= -1.0f; } diff --git a/code/PostProcessing/DeboneProcess.cpp b/code/PostProcessing/DeboneProcess.cpp index 2a8499dc5..e91196ce2 100644 --- a/code/PostProcessing/DeboneProcess.cpp +++ b/code/PostProcessing/DeboneProcess.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -87,7 +86,7 @@ void DeboneProcess::Execute( aiScene* pScene) { if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) { for(unsigned int a = 0; a < pScene->mNumMeshes; a++) { if(splitList[a]) { - numSplits++; + ++numSplits; } } } @@ -119,8 +118,8 @@ void DeboneProcess::Execute( aiScene* pScene) { aiNode *theNode = find ? pScene->mRootNode->FindNode(*find) : nullptr; std::pair push_pair(static_cast(meshes.size()),theNode); - mSubMeshIndices[a].push_back(push_pair); - meshes.push_back(newMeshes[b].first); + mSubMeshIndices[a].emplace_back(push_pair); + meshes.emplace_back(newMeshes[b].first); out+=newMeshes[b].first->mNumBones; } @@ -360,9 +359,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const { unsigned int m = static_cast(pNode->mNumMeshes), n = static_cast(mSubMeshIndices.size()); // first pass, look for meshes which have not moved - for(unsigned int a=0;amMeshes[a]; const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex]; unsigned int nSubmeshes = static_cast(subMeshes.size()); @@ -376,8 +373,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const { // second pass, collect deboned meshes - for(unsigned int a=0;a > &subMeshes = mSubMeshIndices[a]; unsigned int nSubmeshes = static_cast(subMeshes.size()); diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp index 5874c17d2..87ee75601 100644 --- a/code/PostProcessing/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -236,8 +236,7 @@ evil_jump_outside: face_src.mNumIndices = 0; face_src.mIndices = nullptr; } - } - else { + } else { // Otherwise delete it if we don't need this face delete[] face_src.mIndices; face_src.mIndices = nullptr; diff --git a/code/PostProcessing/RemoveVCProcess.cpp b/code/PostProcessing/RemoveVCProcess.cpp index 35047dc0a..bcad65423 100644 --- a/code/PostProcessing/RemoveVCProcess.cpp +++ b/code/PostProcessing/RemoveVCProcess.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -74,63 +72,6 @@ inline void ArrayDelete(T **&in, unsigned int &num) { num = 0; } -#if 0 -// ------------------------------------------------------------------------------------------------ -// Updates the node graph - removes all nodes which have the "remove" flag set and the -// "don't remove" flag not set. Nodes with meshes are never deleted. -bool UpdateNodeGraph(aiNode* node,std::list& childsOfParent,bool root) -{ - bool b = false; - - std::list mine; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - if(UpdateNodeGraph(node->mChildren[i],mine,false)) - b = true; - } - - // somewhat tricky ... mNumMeshes must be originally 0 and MSB2 may not be set, - // so we can do a simple comparison against MSB here - if (!root && AI_RC_UINT_MSB == node->mNumMeshes ) - { - // this node needs to be removed - if(node->mNumChildren) - { - childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end()); - - // set all children to nullptr to make sure they are not deleted when we delete ourself - for (unsigned int i = 0; i < node->mNumChildren;++i) - node->mChildren[i] = nullptr; - } - b = true; - delete node; - } - else - { - AI_RC_UNMASK(node->mNumMeshes); - childsOfParent.push_back(node); - - if (b) - { - // reallocate the array of our children here - node->mNumChildren = (unsigned int)mine.size(); - aiNode** const children = new aiNode*[mine.size()]; - aiNode** ptr = children; - - for (std::list::iterator it = mine.begin(), end = mine.end(); - it != end; ++it) - { - *ptr++ = *it; - } - delete[] node->mChildren; - node->mChildren = children; - return false; - } - } - return b; -} -#endif - // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void RemoveVCProcess::Execute(aiScene *pScene) { diff --git a/code/PostProcessing/ScaleProcess.cpp b/code/PostProcessing/ScaleProcess.cpp index 665f28a7e..00df07090 100644 --- a/code/PostProcessing/ScaleProcess.cpp +++ b/code/PostProcessing/ScaleProcess.cpp @@ -86,9 +86,9 @@ void ScaleProcess::Execute( aiScene* pScene ) { return; // nothing to scale } - ai_assert( mScale != 0 ); - ai_assert( nullptr != pScene ); - ai_assert( nullptr != pScene->mRootNode ); + ai_assert(mScale != 0 ); + ai_assert(nullptr != pScene ); + ai_assert(nullptr != pScene->mRootNode ); if ( nullptr == pScene ) { return; @@ -140,7 +140,7 @@ void ScaleProcess::Execute( aiScene* pScene ) { aiMatrix4x4 scaling; aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); - aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); + const aiMatrix4x4 RotMatrix = aiMatrix4x4(rotation.GetMatrix()); bone->mOffsetMatrix = translation * RotMatrix * scaling; } diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 1be75fc48..394ef15c8 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -54,10 +52,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -SortByPTypeProcess::SortByPTypeProcess() : - mConfigRemoveMeshes(0) { - // empty -} +SortByPTypeProcess::SortByPTypeProcess() : mConfigRemoveMeshes(0) {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. @@ -155,7 +150,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { if (1 == num) { if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { *meshIdx = static_cast(outMeshes.size()); - outMeshes.push_back(mesh); + outMeshes.emplace_back(mesh); } else { delete mesh; pScene->mMeshes[i] = nullptr; @@ -311,21 +306,23 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { if (vert) { *vert++ = mesh->mVertices[idx]; - //mesh->mVertices[idx].x = get_qnan(); } - if (nor) *nor++ = mesh->mNormals[idx]; + if (nor) + *nor++ = mesh->mNormals[idx]; if (tan) { *tan++ = mesh->mTangents[idx]; *bit++ = mesh->mBitangents[idx]; } for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) { - if (!uv[pp]) break; + if (!uv[pp]) + break; *uv[pp]++ = mesh->mTextureCoords[pp][idx]; } for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) { - if (!cols[pp]) break; + if (!cols[pp]) + break; *cols[pp]++ = mesh->mColors[pp][idx]; } @@ -351,7 +348,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { } } if (pp == mesh->mNumAnimMeshes) - amIdx++; + ++amIdx; in.mIndices[q] = outIdx++; } diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index 5324160d4..e44a55979 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -166,7 +165,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector isBoneUsed( pMesh->mNumBones, false); // indices of the faces which are going to go into this submesh - std::vector subMeshFaces; + IndexArray subMeshFaces; subMeshFaces.reserve( pMesh->mNumFaces); // accumulated vertex count of all the faces in this submesh unsigned int numSubMeshVertices = 0; @@ -202,7 +201,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) { if (!isBoneUsed[*it]) { isBoneUsed[*it] = true; - numBones++; + ++numBones; } } @@ -212,18 +211,17 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormName.length > 0 ) - { + if( pMesh->mName.length > 0 ) { newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size()); } newMesh->mMaterialIndex = pMesh->mMaterialIndex; newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; - poNewMeshes.push_back( newMesh); + poNewMeshes.emplace_back( newMesh); // create all the arrays for this mesh if the old mesh contained them newMesh->mNumVertices = numSubMeshVertices; @@ -251,7 +249,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormFaces = new aiFace[subMeshFaces.size()]; unsigned int nvi = 0; // next vertex index - std::vector previousVertexIndices( numSubMeshVertices, std::numeric_limits::max()); // per new vertex: its index in the source mesh + IndexArray previousVertexIndices( numSubMeshVertices, std::numeric_limits::max()); // per new vertex: its index in the source mesh for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) { const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; aiFace& dstFace = newMesh->mFaces[a]; @@ -399,10 +397,10 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumMeshes == 0 ) { - std::vector newMeshList; + IndexArray newMeshList; for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) { unsigned int srcIndex = pNode->mMeshes[a]; - const std::vector& replaceMeshes = mSubMeshIndices[srcIndex]; + const IndexArray& replaceMeshes = mSubMeshIndices[srcIndex]; newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); } diff --git a/code/PostProcessing/SplitByBoneCountProcess.h b/code/PostProcessing/SplitByBoneCountProcess.h index 625019e0c..efe85824f 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.h +++ b/code/PostProcessing/SplitByBoneCountProcess.h @@ -76,6 +76,10 @@ public: /// basing on the Importer's configuration property list. virtual void SetupProperties(const Importer* pImp) override; + /// @brief Will return the maximal number of bones. + /// @return The maximal number of bones. + size_t getMaxNumberOfBones() const; + protected: /// Executes the post processing step on the given imported data. /// At the moment a process is not supposed to fail. @@ -90,14 +94,19 @@ protected: /// Recursively updates the node's mesh list to account for the changed mesh list void UpdateNode( aiNode* pNode) const; -public: +private: /// Max bone count. Splitting occurs if a mesh has more than that number of bones. size_t mMaxBoneCount; /// Per mesh index: Array of indices of the new submeshes. - std::vector< std::vector > mSubMeshIndices; + using IndexArray = std::vector; + std::vector mSubMeshIndices; }; +inline size_t SplitByBoneCountProcess::getMaxNumberOfBones() const { + return mMaxBoneCount; +} + } // end of namespace Assimp #endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index fd7eb037e..b4aa1dd2d 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -105,7 +105,7 @@ class Vertex { friend Vertex operator * (ai_real, const Vertex&); public: - Vertex() {} + Vertex() = default; // ---------------------------------------------------------------------------- /** Extract a particular vertex from a mesh and interleave all components */ From 71043ec164e641ccc129797064744f15f48c7433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Suhajda=20Tam=C3=A1s?= Date: Fri, 28 Apr 2023 11:44:29 +0200 Subject: [PATCH 027/162] Add missing cast --- code/PostProcessing/ConvertToLHProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/PostProcessing/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp index 0d5f3dc42..5524b31dc 100644 --- a/code/PostProcessing/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -241,7 +241,7 @@ void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) { // Converts a single camera to left handed coordinates. void MakeLeftHandedProcess::ProcessCamera( aiCamera* pCam) { - pCam->mLookAt = 2.0f * pCam->mPosition - pCam->mLookAt; + pCam->mLookAt = ai_real(2.0f) * pCam->mPosition - pCam->mLookAt; } #endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS From a8e7c2360508060234aca824d65b692a3d303624 Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 29 Apr 2023 00:29:33 +0800 Subject: [PATCH 028/162] Fix warning related to unreachable-code. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/AssetLib/FBX/FBXParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index 150921db5..11cd1a934 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -190,7 +190,7 @@ Scope::Scope(Parser& parser,bool topLevel) } auto *element = new_Element(*n, parser); - + // Element() should stop at the next Key token (or right after a Close token) n = parser.CurrentToken(); if (n == nullptr) { @@ -198,8 +198,8 @@ Scope::Scope(Parser& parser,bool topLevel) elements.insert(ElementMap::value_type(str, element)); return; } - ParseError("unexpected end of file",parser.LastToken()); delete element; + ParseError("unexpected end of file",parser.LastToken()); } else { elements.insert(ElementMap::value_type(str, element)); } From cabf3a5d17be1479dd2b1a9d64eff7bc9f557501 Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 29 Apr 2023 00:30:21 +0800 Subject: [PATCH 029/162] Fix warning related to unreachable-code-return. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/AssetLib/X3D/X3DXmlHelper.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/AssetLib/X3D/X3DXmlHelper.cpp b/code/AssetLib/X3D/X3DXmlHelper.cpp index ff24b74b3..7ed2e8237 100644 --- a/code/AssetLib/X3D/X3DXmlHelper.cpp +++ b/code/AssetLib/X3D/X3DXmlHelper.cpp @@ -12,7 +12,6 @@ bool X3DXmlHelper::getColor3DAttribute(XmlNode &node, const char *attributeName, tokenize(val, values, " "); if (values.size() != 3) { Throw_ConvertFail_Str2ArrF(node.name(), attributeName); - return false; } auto it = values.begin(); color.r = stof(*it++); @@ -30,7 +29,6 @@ bool X3DXmlHelper::getVector2DAttribute(XmlNode &node, const char *attributeName tokenize(val, values, " "); if (values.size() != 2) { Throw_ConvertFail_Str2ArrF(node.name(), attributeName); - return false; } auto it = values.begin(); color.x = stof(*it++); @@ -47,7 +45,6 @@ bool X3DXmlHelper::getVector3DAttribute(XmlNode &node, const char *attributeName tokenize(val, values, " "); if (values.size() != 3) { Throw_ConvertFail_Str2ArrF(node.name(), attributeName); - return false; } auto it = values.begin(); color.x = stof(*it++); From cdefc9f7aa5ff59618df60cfa505c6ac180e0115 Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 29 Apr 2023 00:43:40 +0800 Subject: [PATCH 030/162] Remove unused -Wno-deprecated-copy-with-dtor. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index d5500d986..cf86225d9 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1241,7 +1241,6 @@ IF (ASSIMP_WARNINGS_AS_ERRORS) -Wno-undefined-reinterpret-cast -Wno-shift-sign-overflow -Wno-deprecated-copy-with-user-provided-dtor - -Wno-deprecated-copy-with-dtor -Wno-deprecated -Wno-format-nonliteral -Wno-comma From 51494e1b4fec3d9086aa4a45332f46d103aa7ddc Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 29 Apr 2023 00:55:13 +0800 Subject: [PATCH 031/162] Remove unused -Wno-deprecated-copy-with-user-provided-dtor. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index cf86225d9..af260f5e9 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1240,7 +1240,6 @@ IF (ASSIMP_WARNINGS_AS_ERRORS) -Wno-nonportable-system-include-path -Wno-undefined-reinterpret-cast -Wno-shift-sign-overflow - -Wno-deprecated-copy-with-user-provided-dtor -Wno-deprecated -Wno-format-nonliteral -Wno-comma From 92d426de2b6878ee5f8535d8ad5c51f871b632df Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 29 Apr 2023 01:05:25 +0800 Subject: [PATCH 032/162] Remove unused -Wno-missing-noreturn. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index af260f5e9..02ba7a08e 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1234,7 +1234,6 @@ IF (ASSIMP_WARNINGS_AS_ERRORS) -Wno-header-hygiene -Wno-tautological-value-range-compare -Wno-tautological-type-limit-compare - -Wno-missing-noreturn -Wno-missing-variable-declarations -Wno-extra-semi -Wno-nonportable-system-include-path From a923d1f89bec9af09e4978adbd78c7d1aadae5c1 Mon Sep 17 00:00:00 2001 From: ParkBook <974200701@qq.com> Date: Mon, 1 May 2023 00:38:16 +0800 Subject: [PATCH 033/162] fix unreachable code fix unreachable code --- code/AssetLib/FBX/FBXParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index 150921db5..9278d90ab 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -198,8 +198,8 @@ Scope::Scope(Parser& parser,bool topLevel) elements.insert(ElementMap::value_type(str, element)); return; } - ParseError("unexpected end of file",parser.LastToken()); delete element; + ParseError("unexpected end of file",parser.LastToken()); } else { elements.insert(ElementMap::value_type(str, element)); } From f32c21e6b3ff7ba92347fb3c0b9d83d21dd85b22 Mon Sep 17 00:00:00 2001 From: Samuel Kogler Date: Wed, 3 May 2023 16:46:54 +0200 Subject: [PATCH 034/162] Fix PBRT exporter FoV aspect ratio calculation --- code/Pbrt/PbrtExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/Pbrt/PbrtExporter.cpp b/code/Pbrt/PbrtExporter.cpp index a9f8656a4..1378038e4 100644 --- a/code/Pbrt/PbrtExporter.cpp +++ b/code/Pbrt/PbrtExporter.cpp @@ -309,7 +309,7 @@ void PbrtExporter::WriteCamera(int i) { // Get camera fov float hfov = AI_RAD_TO_DEG(camera->mHorizontalFOV); - float fov = (aspect >= 1.0) ? hfov : (hfov * aspect); + float fov = (aspect >= 1.0) ? hfov : (hfov / aspect); if (fov < 5) { std::cerr << fov << ": suspiciously low field of view specified by camera. Setting to 45 degrees.\n"; fov = 45; From 55cb19f924c07da495f8632a092289a56448c8cd Mon Sep 17 00:00:00 2001 From: Samuel Kogler Date: Wed, 3 May 2023 16:49:27 +0200 Subject: [PATCH 035/162] Fix PBRT exporter coordinate system Was just mirroring the x axis. This uses aiProcess_ConvertToLeftHanded and rotates the root node to match PBRT. The problem is apparent when using an environment map texture. --- code/Common/Exporter.cpp | 2 +- code/Pbrt/PbrtExporter.cpp | 25 ++++++++++++++++++++----- code/Pbrt/PbrtExporter.h | 3 +++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index b8dabfff4..0795da65c 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -225,7 +225,7 @@ static void setupExporterArray(std::vector &exporte #endif #ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER - exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_Triangulate | aiProcess_SortByPType); + exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_SortByPType); #endif #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER diff --git a/code/Pbrt/PbrtExporter.cpp b/code/Pbrt/PbrtExporter.cpp index 1378038e4..67937019f 100644 --- a/code/Pbrt/PbrtExporter.cpp +++ b/code/Pbrt/PbrtExporter.cpp @@ -111,7 +111,22 @@ PbrtExporter::PbrtExporter( mScene(pScene), mIOSystem(pIOSystem), mPath(path), - mFile(file) { + mFile(file), + mRootTransform( + // rotates the (already left-handed) CRS -90 degrees around the x axis in order to + // make +Z 'up' and +Y 'towards viewer', as in default in pbrt + 1.f, 0.f, 0.f, 0.f, // + 0.f, 0.f, -1.f, 0.f, // + 0.f, 1.f, 0.f, 0.f, // + 0.f, 0.f, 0.f, 1.f // + ) { + + mRootTransform = aiMatrix4x4( + -1.f, 0, 0.f, 0.f, // + 0.0f, -1.f, 0.f, 0.f, // + 0.f, 0.f, 1.f, 0.f, // + 0.f, 0.f, 0.f, 1.f // + ) * mRootTransform; // Export embedded textures. if (mScene->mNumTextures > 0) if (!mIOSystem->CreateDirectory("textures")) @@ -260,7 +275,7 @@ aiMatrix4x4 PbrtExporter::GetNodeTransform(const aiString &name) const { node = node->mParent; } } - return m; + return mRootTransform * m; } std::string PbrtExporter::TransformAsString(const aiMatrix4x4 &m) { @@ -327,7 +342,7 @@ void PbrtExporter::WriteCamera(int i) { if (!cameraActive) mOutput << "# "; - mOutput << "Scale -1 1 1\n"; // right handed -> left handed + mOutput << "Scale 1 1 1\n"; if (!cameraActive) mOutput << "# "; mOutput << "LookAt " @@ -383,8 +398,8 @@ void PbrtExporter::WriteWorldDefinition() { } mOutput << "# Geometry\n\n"; - aiMatrix4x4 worldFromObject; - WriteGeometricObjects(mScene->mRootNode, worldFromObject, meshUses); + + WriteGeometricObjects(mScene->mRootNode, mRootTransform, meshUses); } void PbrtExporter::WriteTextures() { diff --git a/code/Pbrt/PbrtExporter.h b/code/Pbrt/PbrtExporter.h index 4f4e1625d..c7e8180e2 100644 --- a/code/Pbrt/PbrtExporter.h +++ b/code/Pbrt/PbrtExporter.h @@ -100,6 +100,9 @@ private: // A private set to keep track of which textures have been declared std::set mTextureSet; + // Transform to apply to the root node and all root objects such as cameras, lights, etc. + aiMatrix4x4 mRootTransform; + aiMatrix4x4 GetNodeTransform(const aiString& name) const; static std::string TransformAsString(const aiMatrix4x4& m); From fbf8799cb52100dcffff604c1b4ec7870b1e26ee Mon Sep 17 00:00:00 2001 From: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> Date: Sat, 1 Apr 2023 10:19:52 +0800 Subject: [PATCH 036/162] Fix warning related to unused-function. Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com> --- code/CMakeLists.txt | 1 - code/Common/StbCommon.h | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 02ba7a08e..eec2eb40f 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1198,7 +1198,6 @@ IF (ASSIMP_WARNINGS_AS_ERRORS) IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror - -Wno-unused-function -Wno-microsoft-enum-value -Wno-switch-enum -Wno-covered-switch-default diff --git a/code/Common/StbCommon.h b/code/Common/StbCommon.h index 573c98ac7..5de2e176d 100644 --- a/code/Common/StbCommon.h +++ b/code/Common/StbCommon.h @@ -48,6 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma GCC diagnostic ignored "-Wunused-function" #endif +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + #ifndef STB_USE_HUNTER /* Use prefixed names for the symbols from stb_image as it is a very commonly embedded library. Including vanilla stb_image symbols causes duplicate symbol problems if assimp is linked @@ -114,3 +119,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma GCC diagnostic pop #endif +#if defined(__clang__) +#pragma clang diagnostic pop +#endif From d58201a579759305cec8330cdcc908d954d2b970 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 4 May 2023 00:00:52 +0200 Subject: [PATCH 037/162] Refactoring: Reuse code from GeometryUtils --- code/Geometry/GeometryUtils.cpp | 8 + code/Geometry/GeometryUtils.h | 14 +- .../ComputeUVMappingProcess.cpp | 289 ++++++++--------- .../PostProcessing/DropFaceNormalsProcess.cpp | 25 +- code/PostProcessing/FindDegenerates.cpp | 80 +++-- code/PostProcessing/PretransformVertices.cpp | 293 +++++++++--------- code/PostProcessing/PretransformVertices.h | 18 +- code/PostProcessing/ProcessHelper.cpp | 7 +- .../RemoveRedundantMaterials.cpp | 33 +- code/PostProcessing/ScaleProcess.cpp | 1 - code/PostProcessing/SortByPTypeProcess.cpp | 3 +- .../SplitByBoneCountProcess.cpp | 4 +- code/PostProcessing/SplitLargeMeshes.cpp | 36 +-- code/PostProcessing/TextureTransform.cpp | 6 +- code/PostProcessing/TriangulateProcess.cpp | 45 +-- code/PostProcessing/ValidateDataStructure.cpp | 83 +++-- include/assimp/StreamWriter.h | 5 +- include/assimp/Vertex.h | 25 +- test/CMakeLists.txt | 18 +- test/unit/Geometry/utGeometryUtils.cpp | 68 ++++ 20 files changed, 526 insertions(+), 535 deletions(-) create mode 100644 test/unit/Geometry/utGeometryUtils.cpp diff --git a/code/Geometry/GeometryUtils.cpp b/code/Geometry/GeometryUtils.cpp index 92a3aa853..ad99f2224 100644 --- a/code/Geometry/GeometryUtils.cpp +++ b/code/Geometry/GeometryUtils.cpp @@ -89,4 +89,12 @@ bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, return true; } +// ------------------------------------------------------------------------------------------------ +void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, + size_t numVectors) { + for (size_t i=0; i -#include "Geometry/GeometryUtils.h" using namespace Assimp; namespace { - const static aiVector3D base_axis_y(0.0,1.0,0.0); - const static aiVector3D base_axis_x(1.0,0.0,0.0); - const static aiVector3D base_axis_z(0.0,0.0,1.0); - const static ai_real angle_epsilon = ai_real( 0.95 ); -} +const static aiVector3D base_axis_y(0.0, 1.0, 0.0); +const static aiVector3D base_axis_x(1.0, 0.0, 0.0); +const static aiVector3D base_axis_z(0.0, 0.0, 1.0); +const static ai_real angle_epsilon = ai_real(0.95); +} // namespace // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_GenUVCoords) != 0; +bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const { + return (pFlags & aiProcess_GenUVCoords) != 0; } // ------------------------------------------------------------------------------------------------ // Find the first empty UV channel in a mesh -inline unsigned int FindEmptyUVChannel (aiMesh* mesh) { - for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) +inline unsigned int FindEmptyUVChannel(aiMesh *mesh) { + for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++m) if (!mesh->mTextureCoords[m]) { return m; } @@ -76,19 +76,19 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh) { // ------------------------------------------------------------------------------------------------ // Try to remove UV seams -void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { +void RemoveUVSeams(aiMesh *mesh, aiVector3D *out) { // TODO: just a very rough algorithm. I think it could be done // much easier, but I don't know how and am currently too tired to // to think about a better solution. - const static ai_real LOWER_LIMIT = ai_real( 0.1 ); - const static ai_real UPPER_LIMIT = ai_real( 0.9 ); + const static ai_real LOWER_LIMIT = ai_real(0.1); + const static ai_real UPPER_LIMIT = ai_real(0.9); - const static ai_real LOWER_EPSILON = ai_real( 10e-3 ); - const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 ); + const static ai_real LOWER_EPSILON = ai_real(10e-3); + const static ai_real UPPER_EPSILON = ai_real(1.0 - 10e-3); - for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) { - const aiFace& face = mesh->mFaces[fidx]; + for (unsigned int fidx = 0; fidx < mesh->mNumFaces; ++fidx) { + const aiFace &face = mesh->mFaces[fidx]; if (face.mNumIndices < 3) { continue; // triangles and polygons only, please } @@ -100,20 +100,18 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { // but the assumption that a face with at least one very small // on the one side and one very large U coord on the other side // lies on a UV seam should work for most cases. - for (unsigned int n = 0; n < face.mNumIndices;++n) - { - if (out[face.mIndices[n]].x < LOWER_LIMIT) - { + for (unsigned int n = 0; n < face.mNumIndices; ++n) { + if (out[face.mIndices[n]].x < LOWER_LIMIT) { smallV = n; // If we have a U value very close to 0 we can't // round the others to 0, too. if (out[face.mIndices[n]].x <= LOWER_EPSILON) zero = true; - else round_to_zero = true; + else + round_to_zero = true; } - if (out[face.mIndices[n]].x > UPPER_LIMIT) - { + if (out[face.mIndices[n]].x > UPPER_LIMIT) { large = n; // If we have a U value very close to 1 we can't @@ -122,10 +120,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { one = true; } } - if (smallV != face.mNumIndices && large != face.mNumIndices) - { - for (unsigned int n = 0; n < face.mNumIndices;++n) - { + if (smallV != face.mNumIndices && large != face.mNumIndices) { + for (unsigned int n = 0; n < face.mNumIndices; ++n) { // If the u value is over the upper limit and no other u // value of that face is 0, round it to 0 if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) @@ -141,9 +137,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { // Due to numerical inaccuracies one U coord becomes 0, the // other 1. But we do still have a third UV coord to determine // to which side we must round to. - else if (one && zero) - { - if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) + else if (one && zero) { + if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) out[face.mIndices[n]].x = 0.0; else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) out[face.mIndices[n]].x = 1.0; @@ -154,8 +149,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { } // ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ +void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) { aiVector3D center, min, max; FindMeshCenter(mesh, center, min, max); @@ -163,7 +157,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D // currently the mapping axis will always be one of x,y,z, except if the // PretransformVertices step is used (it transforms the meshes into worldspace, // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { + if (axis * base_axis_x >= angle_epsilon) { // For each point get a normalized projection vector in the sphere, // get its longitude and latitude and map them to their respective @@ -177,58 +171,54 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D // Thus we can derive: // lat = arcsin (z) // lon = arctan (y/x) - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize(); + out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F, + (std::asin(diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); } - } - else if (axis * base_axis_y >= angle_epsilon) { + } else if (axis * base_axis_y >= angle_epsilon) { // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize(); + out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F, + (std::asin(diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); } - } - else if (axis * base_axis_z >= angle_epsilon) { + } else if (axis * base_axis_z >= angle_epsilon) { // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize(); + out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F, + (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); } } // slower code path in case the mapping axis is not one of the coordinate system axes - else { + else { aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); + aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo); // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D diff = ((mTrafo * mesh->mVertices[pnt]) - center).Normalize(); + out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F, + (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); } } - // Now find and remove UV seams. A seam occurs if a face has a tcoord // close to zero on the one side, and a tcoord close to one on the // other side. - RemoveUVSeams(mesh,out); + RemoveUVSeams(mesh, out); } // ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ +void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) { aiVector3D center, min, max; // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // currently the mapping axis will always be one of x,y,z, except if the // PretransformVertices step is used (it transforms the meshes into worldspace, // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { + if (axis * base_axis_x >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); const ai_real diff = max.x - min.x; @@ -236,116 +226,110 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector // directly to the texture V axis. The other axis is derived from // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where // 'c' is the center point of the mesh. - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + aiVector3D &uv = out[pnt]; uv.y = (pos.x - min.x) / diff; - uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; + uv.x = (std::atan2(pos.z - center.z, pos.y - center.y) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI; } - } - else if (axis * base_axis_y >= angle_epsilon) { + } else if (axis * base_axis_y >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); const ai_real diff = max.y - min.y; // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + aiVector3D &uv = out[pnt]; uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; + uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI; } - } - else if (axis * base_axis_z >= angle_epsilon) { + } else if (axis * base_axis_z >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); const ai_real diff = max.z - min.z; // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + aiVector3D &uv = out[pnt]; uv.y = (pos.z - min.z) / diff; - uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; + uv.x = (std::atan2(pos.y - center.y, pos.x - center.x) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI; } } // slower code path in case the mapping axis is not one of the coordinate system axes else { aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); + aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo); + FindMeshCenterTransformed(mesh, center, min, max, mTrafo); const ai_real diff = max.y - min.y; // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ - const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; + aiVector3D &uv = out[pnt]; uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; + uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI; } } // Now find and remove UV seams. A seam occurs if a face has a tcoord // close to zero on the one side, and a tcoord close to one on the // other side. - RemoveUVSeams(mesh,out); + RemoveUVSeams(mesh, out); } // ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - ai_real diffu,diffv; +void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) { + ai_real diffu, diffv; aiVector3D center, min, max; // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // currently the mapping axis will always be one of x,y,z, except if the // PretransformVertices step is used (it transforms the meshes into worldspace, // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { + if (axis * base_axis_x >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); diffu = max.z - min.z; diffv = max.y - min.y; - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + out[pnt].Set((pos.z - min.z) / diffu, (pos.y - min.y) / diffv, 0.0); } - } - else if (axis * base_axis_y >= angle_epsilon) { + } else if (axis * base_axis_y >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); diffu = max.x - min.x; diffv = max.z - min.z; - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0); } - } - else if (axis * base_axis_z >= angle_epsilon) { + } else if (axis * base_axis_z >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); diffu = max.x - min.x; diffv = max.y - min.y; - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0); + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { + const aiVector3D &pos = mesh->mVertices[pnt]; + out[pnt].Set((pos.x - min.x) / diffu, (pos.y - min.y) / diffv, 0.0); } } // slower code path in case the mapping axis is not one of the coordinate system axes - else - { + else { aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); + aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo); + FindMeshCenterTransformed(mesh, center, min, max, mTrafo); diffu = max.x - min.x; diffv = max.z - min.z; // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { + for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); + out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0); } } @@ -353,14 +337,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& } // ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) -{ +void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh *, aiVector3D *) { ASSIMP_LOG_ERROR("Mapping type currently not implemented"); } // ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::Execute( aiScene* pScene) -{ +void ComputeUVMappingProcess::Execute(aiScene *pScene) { ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); char buffer[1024]; @@ -371,23 +353,18 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene) /* Iterate through all materials and search for non-UV mapped textures */ - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { + for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { mappingStack.clear(); - aiMaterial* mat = pScene->mMaterials[i]; - for (unsigned int a = 0; a < mat->mNumProperties;++a) - { - aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.mapping")) - { - aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); - if (aiTextureMapping_UV != mapping) - { - if (!DefaultLogger::isNullLogger()) - { + aiMaterial *mat = pScene->mMaterials[i]; + for (unsigned int a = 0; a < mat->mNumProperties; ++a) { + aiMaterialProperty *prop = mat->mProperties[a]; + if (!::strcmp(prop->mKey.data, "$tex.mapping")) { + aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData); + if (aiTextureMapping_UV != mapping) { + if (!DefaultLogger::isNullLogger()) { ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", - aiTextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, - MappingTypeToString(mapping)); + aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex, + MappingTypeToString(mapping)); ASSIMP_LOG_INFO(buffer); } @@ -395,70 +372,62 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene) if (aiTextureMapping_OTHER == mapping) continue; - MappingInfo info (mapping); + MappingInfo info(mapping); // Get further properties - currently only the major axis - for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) - { - aiMaterialProperty* prop2 = mat->mProperties[a2]; + for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) { + aiMaterialProperty *prop2 = mat->mProperties[a2]; if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) continue; - if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { - info.axis = *((aiVector3D*)prop2->mData); + if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) { + info.axis = *((aiVector3D *)prop2->mData); break; } } - unsigned int idx( 99999999 ); + unsigned int idx(99999999); // Check whether we have this mapping mode already - std::list::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); - if (mappingStack.end() != it) - { + std::list::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info); + if (mappingStack.end() != it) { idx = (*it).uv; - } - else - { + } else { /* We have found a non-UV mapped texture. Now - * we need to find all meshes using this material - * that we can compute UV channels for them. - */ - for (unsigned int m = 0; m < pScene->mNumMeshes;++m) - { - aiMesh* mesh = pScene->mMeshes[m]; + * we need to find all meshes using this material + * that we can compute UV channels for them. + */ + for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) { + aiMesh *mesh = pScene->mMeshes[m]; unsigned int outIdx = 0; - if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || - !mesh->mNumVertices) - { + if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX || + !mesh->mNumVertices) { continue; } // Allocate output storage - aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; + aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; - switch (mapping) - { + switch (mapping) { case aiTextureMapping_SPHERE: - ComputeSphereMapping(mesh,info.axis,p); + ComputeSphereMapping(mesh, info.axis, p); break; case aiTextureMapping_CYLINDER: - ComputeCylinderMapping(mesh,info.axis,p); + ComputeCylinderMapping(mesh, info.axis, p); break; case aiTextureMapping_PLANE: - ComputePlaneMapping(mesh,info.axis,p); + ComputePlaneMapping(mesh, info.axis, p); break; case aiTextureMapping_BOX: - ComputeBoxMapping(mesh,p); + ComputeBoxMapping(mesh, p); break; default: ai_assert(false); } - if (m && idx != outIdx) - { + if (m && idx != outIdx) { ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to " - "this material have equal numbers of UV channels. The UV index stored in " - "the material structure does therefore not apply for all meshes. "); + "this material have equal numbers of UV channels. The UV index stored in " + "the material structure does therefore not apply for all meshes. "); } idx = outIdx; } @@ -468,7 +437,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene) // Update the material property list mapping = aiTextureMapping_UV; - ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); + ((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex)); } } } diff --git a/code/PostProcessing/DropFaceNormalsProcess.cpp b/code/PostProcessing/DropFaceNormalsProcess.cpp index 223482374..c5f6333e0 100644 --- a/code/PostProcessing/DropFaceNormalsProcess.cpp +++ b/code/PostProcessing/DropFaceNormalsProcess.cpp @@ -42,27 +42,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Implementation of the post processing step to drop face -* normals for all imported faces. -*/ - + * normals for all imported faces. + */ #include "DropFaceNormalsProcess.h" +#include #include #include #include -#include using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_DropNormals) != 0; +bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const { + return (pFlags & aiProcess_DropNormals) != 0; } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void DropFaceNormalsProcess::Execute( aiScene* pScene) { +void DropFaceNormalsProcess::Execute(aiScene *pScene) { ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin"); if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { @@ -70,21 +69,21 @@ void DropFaceNormalsProcess::Execute( aiScene* pScene) { } bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]); + for (unsigned int a = 0; a < pScene->mNumMeshes; a++) { + bHas |= this->DropMeshFaceNormals(pScene->mMeshes[a]); } - if (bHas) { + if (bHas) { ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. " - "Face normals have been removed"); + "Face normals have been removed"); } else { ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. " - "No normals were present"); + "No normals were present"); } } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* mesh) { +bool DropFaceNormalsProcess::DropMeshFaceNormals(aiMesh *mesh) { ai_assert(nullptr != mesh); if (nullptr == mesh->mNormals) { diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp index 87ee75601..d9c14425c 100644 --- a/code/PostProcessing/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -41,11 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file FindDegenerates.cpp * @brief Implementation of the FindDegenerates post-process step. -*/ + */ -#include "ProcessHelper.h" #include "FindDegenerates.h" #include "Geometry/GeometryUtils.h" +#include "ProcessHelper.h" #include @@ -54,35 +54,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; // Correct node indices to meshes and remove references to deleted mesh -static void updateSceneGraph(aiNode* pNode, const std::unordered_map& meshMap); +static void updateSceneGraph(aiNode *pNode, const std::unordered_map &meshMap); // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer FindDegeneratesProcess::FindDegeneratesProcess() : - mConfigRemoveDegenerates( false ), - mConfigCheckAreaOfTriangle( false ){ + mConfigRemoveDegenerates(false), + mConfigCheckAreaOfTriangle(false) { // empty } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { +bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const { return 0 != (pFlags & aiProcess_FindDegenerates); } // ------------------------------------------------------------------------------------------------ // Setup import configuration -void FindDegeneratesProcess::SetupProperties(const Importer* pImp) { +void FindDegeneratesProcess::SetupProperties(const Importer *pImp) { // Get the current value of AI_CONFIG_PP_FD_REMOVE - mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); - mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) ); + mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0)); + mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA)); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void FindDegeneratesProcess::Execute( aiScene* pScene) { +void FindDegeneratesProcess::Execute(aiScene *pScene) { ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin"); - if ( nullptr == pScene) { + if (nullptr == pScene) { return; } @@ -112,7 +112,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished"); } -static void updateSceneGraph(aiNode* pNode, const std::unordered_map& meshMap) { +static void updateSceneGraph(aiNode *pNode, const std::unordered_map &meshMap) { unsigned int targetIndex = 0; for (unsigned i = 0; i < pNode->mNumMeshes; ++i) { const unsigned int sourceMeshIndex = pNode->mMeshes[i]; @@ -123,7 +123,7 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_mapmNumMeshes = targetIndex; - //recurse to all children + // recurse to all children for (unsigned i = 0; i < pNode->mNumChildren; ++i) { updateSceneGraph(pNode->mChildren[i], meshMap); } @@ -131,17 +131,17 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_mapmPrimitiveTypes = 0; std::vector remove_me; if (mConfigRemoveDegenerates) { - remove_me.resize( mesh->mNumFaces, false ); + remove_me.resize(mesh->mNumFaces, false); } unsigned int deg = 0, limit; - for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) { - aiFace& face = mesh->mFaces[a]; + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { + aiFace &face = mesh->mFaces[a]; bool first = true; // check whether the face contains degenerated entries @@ -151,43 +151,43 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { // double points may not come directly after another. limit = face.mNumIndices; if (face.mNumIndices > 4) { - limit = std::min( limit, i+2 ); + limit = std::min(limit, i + 2); } - for (unsigned int t = i+1; t < limit; ++t) { - if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) { + for (unsigned int t = i + 1; t < limit; ++t) { + if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) { // we have found a matching vertex position // remove the corresponding index from the array --face.mNumIndices; --limit; for (unsigned int m = t; m < face.mNumIndices; ++m) { - face.mIndices[ m ] = face.mIndices[ m+1 ]; + face.mIndices[m] = face.mIndices[m + 1]; } --t; // NOTE: we set the removed vertex index to an unique value // to make sure the developer gets notified when his // application attempts to access this data. - face.mIndices[ face.mNumIndices ] = 0xdeadbeef; + face.mIndices[face.mNumIndices] = 0xdeadbeef; - if(first) { + if (first) { ++deg; first = false; } - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; + if (mConfigRemoveDegenerates) { + remove_me[a] = true; goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! } } } - if ( mConfigCheckAreaOfTriangle ) { - if ( face.mNumIndices == 3 ) { - ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh ); + if (mConfigCheckAreaOfTriangle) { + if (face.mNumIndices == 3) { + ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh); if (area < ai_epsilon) { - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; + if (mConfigRemoveDegenerates) { + remove_me[a] = true; ++deg; goto evil_jump_outside; } @@ -199,8 +199,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { } // We need to update the primitive flags array of the mesh. - switch (face.mNumIndices) - { + switch (face.mNumIndices) { case 1u: mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; break; @@ -214,22 +213,21 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; break; }; -evil_jump_outside: + evil_jump_outside: continue; } // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import if (mConfigRemoveDegenerates && deg) { unsigned int n = 0; - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) - { - aiFace& face_src = mesh->mFaces[a]; + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { + aiFace &face_src = mesh->mFaces[a]; if (!remove_me[a]) { - aiFace& face_dest = mesh->mFaces[n++]; + aiFace &face_dest = mesh->mFaces[n++]; // Do a manual copy, keep the index array face_dest.mNumIndices = face_src.mNumIndices; - face_dest.mIndices = face_src.mIndices; + face_dest.mIndices = face_src.mIndices; if (&face_src != &face_dest) { // clear source @@ -246,15 +244,15 @@ evil_jump_outside: // Just leave the rest of the array unreferenced, we don't care for now mesh->mNumFaces = n; if (!mesh->mNumFaces) { - //The whole mesh consists of degenerated faces - //signal upward, that this mesh should be deleted. + // The whole mesh consists of degenerated faces + // signal upward, that this mesh should be deleted. ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives"); return true; } } if (deg && !DefaultLogger::isNullLogger()) { - ASSIMP_LOG_WARN( "Found ", deg, " degenerated primitives"); + ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives"); } return false; } diff --git a/code/PostProcessing/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp index b6bb6155e..ff066a1d3 100644 --- a/code/PostProcessing/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -41,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file PretransformVertices.cpp - * @brief Implementation of the "PretransformVertices" post processing step -*/ +/// @file PretransformVertices.cpp +/// @brief Implementation of the "PretransformVertices" post processing step #include "PretransformVertices.h" #include "ConvertToLHProcess.h" @@ -57,16 +54,44 @@ using namespace Assimp; #define AI_PTVS_VERTEX 0x0 #define AI_PTVS_FACE 0x1 +namespace { + +// Get a bitwise combination identifying the vertex format of a mesh +static unsigned int GetMeshVFormat(aiMesh *pcMesh) { + // the vertex format is stored in aiMesh::mBones for later retrieval. + // there isn't a good reason to compute it a few hundred times + // from scratch. The pointer is unused as animations are lost + // during PretransformVertices. + if (pcMesh->mBones) + return (unsigned int)(uint64_t)pcMesh->mBones; + + const unsigned int iRet = GetMeshVFormatUnique(pcMesh); + + // store the value for later use + pcMesh->mBones = (aiBone **)(uint64_t)iRet; + return iRet; +} + +// Get a list of all vertex formats that occur for a given material index +// The output list contains duplicate elements +static void GetVFormatList(const aiScene *pcScene, unsigned int iMat, std::list &aiOut) { + for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) { + aiMesh *pcMesh = pcScene->mMeshes[i]; + if (iMat == pcMesh->mMaterialIndex) { + aiOut.push_back(GetMeshVFormat(pcMesh)); + } + } +} + +} // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer PretransformVertices::PretransformVertices() : - configKeepHierarchy(false), - configNormalize(false), - configTransform(false), - configTransformation(), - mConfigPointCloud(false) { - // empty -} + mConfigKeepHierarchy(false), + mConfigNormalize(false), + mConfigTransform(false), + mConfigTransformation(), + mConfigPointCloud(false) {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. @@ -79,11 +104,11 @@ bool PretransformVertices::IsActive(unsigned int pFlags) const { void PretransformVertices::SetupProperties(const Importer *pImp) { // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION - configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0)); - configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0)); - configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0)); + mConfigKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0)); + mConfigNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0)); + mConfigTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0)); - configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); + mConfigTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); } @@ -99,25 +124,7 @@ unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const { } // ------------------------------------------------------------------------------------------------ -// Get a bitwise combination identifying the vertex format of a mesh -unsigned int PretransformVertices::GetMeshVFormat(aiMesh *pcMesh) const { - // the vertex format is stored in aiMesh::mBones for later retrieval. - // there isn't a good reason to compute it a few hundred times - // from scratch. The pointer is unused as animations are lost - // during PretransformVertices. - if (pcMesh->mBones) - return (unsigned int)(uint64_t)pcMesh->mBones; - - const unsigned int iRet = GetMeshVFormatUnique(pcMesh); - - // store the value for later use - pcMesh->mBones = (aiBone **)(uint64_t)iRet; - return iRet; -} - -// ------------------------------------------------------------------------------------------------ -// Count the number of vertices in the whole scene and a given -// material index +// Count the number of vertices in the whole scene and a given material index void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat, unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const { for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) { @@ -128,8 +135,7 @@ void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const a } } for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { - CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, - iVFormat, piFaces, piVertices); + CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, iVFormat, piFaces, piVertices); } } @@ -272,19 +278,6 @@ void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcN } } -// ------------------------------------------------------------------------------------------------ -// Get a list of all vertex formats that occur for a given material index -// The output list contains duplicate elements -void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat, - std::list &aiOut) const { - for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) { - aiMesh *pcMesh = pcScene->mMeshes[i]; - if (iMat == pcMesh->mMaterialIndex) { - aiOut.push_back(GetMeshVFormat(pcMesh)); - } - } -} - // ------------------------------------------------------------------------------------------------ // Compute the absolute transformation matrices of each node void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) { @@ -297,39 +290,44 @@ void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) { } } +static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) { + for (size_t i=0; iHasFaces() && mat.Determinant() < 0) { - // Reverse the mesh face winding order - FlipWindingOrderProcess::ProcessMesh(mesh); + // Check for odd negative scale (mirror) + if (mesh->HasFaces() && mat.Determinant() < 0) { + // Reverse the mesh face winding order + FlipWindingOrderProcess::ProcessMesh(mesh); + } + + // Update positions + if (mesh->HasPositions()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mVertices[i] = mat * mesh->mVertices[i]; } + } - // Update positions - if (mesh->HasPositions()) { + // Update normals and tangents + if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { + const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose(); + + if (mesh->HasNormals()) { + normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices); + } + if (mesh->HasTangentsAndBitangents()) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - - // Update normals and tangents - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose(); - - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } + mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); + mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); } } } @@ -352,40 +350,41 @@ void PretransformVertices::BuildWCSMeshes(std::vector &out, aiMesh **i // yes, we can. mesh->mBones = reinterpret_cast(&node->mTransformation); mesh->mNumBones = UINT_MAX; - } else { + continue; + } - // try to find us in the list of newly created meshes - for (unsigned int n = 0; n < out.size(); ++n) { - aiMesh *ctz = out[n]; - if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { + // try to find us in the list of newly created meshes + for (unsigned int n = 0; n < out.size(); ++n) { + aiMesh *ctz = out[n]; + if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { - // ok, use this one. Update node mesh index - node->mMeshes[i] = numIn + n; - } + // ok, use this one. Update node mesh index + node->mMeshes[i] = numIn + n; } - if (node->mMeshes[i] < numIn) { - // Worst case. Need to operate on a full copy of the mesh - ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); - aiMesh *ntz; + } + if (node->mMeshes[i] < numIn) { + // Worst case. Need to operate on a full copy of the mesh + ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); + aiMesh *ntz; - const unsigned int tmp = mesh->mNumBones; // - mesh->mNumBones = 0; - SceneCombiner::Copy(&ntz, mesh); - mesh->mNumBones = tmp; + const unsigned int cacheNumBones = mesh->mNumBones; // + mesh->mNumBones = 0; + SceneCombiner::Copy(&ntz, mesh); + mesh->mNumBones = cacheNumBones; - ntz->mNumBones = node->mMeshes[i]; - ntz->mBones = reinterpret_cast(&node->mTransformation); + ntz->mNumBones = node->mMeshes[i]; + ntz->mBones = reinterpret_cast(&node->mTransformation); - out.push_back(ntz); + out.push_back(ntz); - node->mMeshes[i] = static_cast(numIn + out.size() - 1); - } + node->mMeshes[i] = static_cast(numIn + out.size() - 1); } } // call children - for (unsigned int i = 0; i < node->mNumChildren; ++i) + for (unsigned int i = 0; i < node->mNumChildren; ++i) { BuildWCSMeshes(out, in, numIn, node->mChildren[i]); + } } // ------------------------------------------------------------------------------------------------ @@ -394,8 +393,9 @@ void PretransformVertices::MakeIdentityTransform(aiNode *nd) const { nd->mTransformation = aiMatrix4x4(); // call children - for (unsigned int i = 0; i < nd->mNumChildren; ++i) + for (unsigned int i = 0; i < nd->mNumChildren; ++i) { MakeIdentityTransform(nd->mChildren[i]); + } } // ------------------------------------------------------------------------------------------------ @@ -405,8 +405,27 @@ void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int refs[nd->mMeshes[i]]++; // call children - for (unsigned int i = 0; i < nd->mNumChildren; ++i) + for (unsigned int i = 0; i < nd->mNumChildren; ++i) { BuildMeshRefCountArray(nd->mChildren[i], refs); + } +} + +// ------------------------------------------------------------------------------------------------ +static void appendNewMeshesToScene(aiScene *pScene, std::vector &apcOutMeshes) { + ai_assert(pScene != nullptr); + + if (apcOutMeshes.empty()) { + return; + } + + aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()]; + + ::memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes); + ::memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size()); + + pScene->mNumMeshes += static_cast(apcOutMeshes.size()); + delete[] pScene->mMeshes; + pScene->mMeshes = npp; } // ------------------------------------------------------------------------------------------------ @@ -418,12 +437,12 @@ void PretransformVertices::Execute(aiScene *pScene) { if (!pScene->mNumMeshes) return; - const unsigned int iOldMeshes = pScene->mNumMeshes; - const unsigned int iOldAnimationChannels = pScene->mNumAnimations; - const unsigned int iOldNodes = CountNodes(pScene->mRootNode); + const unsigned int oldMeshes = pScene->mNumMeshes; + const unsigned int oldAnimationChannels = pScene->mNumAnimations; + const unsigned int oldNodes = CountNodes(pScene->mRootNode); - if (configTransform) { - pScene->mRootNode->mTransformation = configTransformation * pScene->mRootNode->mTransformation; + if (mConfigTransform) { + pScene->mRootNode->mTransformation = mConfigTransformation * pScene->mRootNode->mTransformation; } // first compute absolute transformation matrices for all nodes @@ -449,22 +468,13 @@ void PretransformVertices::Execute(aiScene *pScene) { // we go on and transform all meshes, if one is referenced by nodes // with different absolute transformations a depth copy of the mesh // is required. - if (configKeepHierarchy) { + if (mConfigKeepHierarchy) { // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode); // ... if new meshes have been generated, append them to the end of the scene - if (apcOutMeshes.size() > 0) { - aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()]; - - memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes); - memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size()); - - pScene->mNumMeshes += static_cast(apcOutMeshes.size()); - delete[] pScene->mMeshes; - pScene->mMeshes = npp; - } + appendNewMeshesToScene(pScene, apcOutMeshes); // now iterate through all meshes and transform them to world-space for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { @@ -488,34 +498,35 @@ void PretransformVertices::Execute(aiScene *pScene) { aiVFormats.sort(); aiVFormats.unique(); for (std::list::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) { - unsigned int iVertices = 0; - unsigned int iFaces = 0; - CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices); - if (0 != iFaces && 0 != iVertices) { + unsigned int numVertices = 0u; + unsigned int numFaces = 0u; + CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &numFaces, &numVertices); + if (0 != numFaces && 0 != numVertices) { apcOutMeshes.push_back(new aiMesh()); aiMesh *pcMesh = apcOutMeshes.back(); - pcMesh->mNumFaces = iFaces; - pcMesh->mNumVertices = iVertices; - pcMesh->mFaces = new aiFace[iFaces]; - pcMesh->mVertices = new aiVector3D[iVertices]; + pcMesh->mNumFaces = numFaces; + pcMesh->mNumVertices = numVertices; + pcMesh->mFaces = new aiFace[numFaces]; + pcMesh->mVertices = new aiVector3D[numVertices]; pcMesh->mMaterialIndex = i; - if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices]; + if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[numVertices]; if ((*j) & 0x4) { - pcMesh->mTangents = new aiVector3D[iVertices]; - pcMesh->mBitangents = new aiVector3D[iVertices]; + pcMesh->mTangents = new aiVector3D[numVertices]; + pcMesh->mBitangents = new aiVector3D[numVertices]; } - iFaces = 0; - while ((*j) & (0x100 << iFaces)) { - pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; - if ((*j) & (0x10000 << iFaces)) - pcMesh->mNumUVComponents[iFaces] = 3; - else - pcMesh->mNumUVComponents[iFaces] = 2; - iFaces++; + numFaces = 0; + while ((*j) & (0x100 << numFaces)) { + pcMesh->mTextureCoords[numFaces] = new aiVector3D[numVertices]; + if ((*j) & (0x10000 << numFaces)) { + pcMesh->mNumUVComponents[numFaces] = 3; + } else { + pcMesh->mNumUVComponents[numFaces] = 2; + } + ++numFaces; } - iFaces = 0; - while ((*j) & (0x1000000 << iFaces)) - pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; + numFaces = 0; + while ((*j) & (0x1000000 << numFaces)) + pcMesh->mColors[numFaces++] = new aiColor4D[numVertices]; // fill the mesh ... unsigned int aiTemp[2] = { 0, 0 }; @@ -593,7 +604,7 @@ void PretransformVertices::Execute(aiScene *pScene) { l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp; } - if (!configKeepHierarchy) { + if (!mConfigKeepHierarchy) { // now delete all nodes in the scene and build a new // flat node graph with a root node and some level 1 children @@ -644,7 +655,7 @@ void PretransformVertices::Execute(aiScene *pScene) { MakeIdentityTransform(pScene->mRootNode); } - if (configNormalize) { + if (mConfigNormalize) { // compute the boundary of all meshes aiVector3D min, max; MinMaxChooser()(min, max); @@ -674,9 +685,9 @@ void PretransformVertices::Execute(aiScene *pScene) { if (!DefaultLogger::isNullLogger()) { ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); - ASSIMP_LOG_INFO("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", + ASSIMP_LOG_INFO("Removed ", oldNodes, " nodes and ", oldAnimationChannels, " animation channels (", CountNodes(pScene->mRootNode), " output nodes)"); ASSIMP_LOG_INFO("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras."); - ASSIMP_LOG_INFO("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); + ASSIMP_LOG_INFO("Moved ", oldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); } } diff --git a/code/PostProcessing/PretransformVertices.h b/code/PostProcessing/PretransformVertices.h index 7c2b5e99e..69d3d8400 100644 --- a/code/PostProcessing/PretransformVertices.h +++ b/code/PostProcessing/PretransformVertices.h @@ -90,7 +90,7 @@ public: * @param keep true for keep configuration. */ void KeepHierarchy(bool keep) { - configKeepHierarchy = keep; + mConfigKeepHierarchy = keep; } // ------------------------------------------------------------------- @@ -98,7 +98,7 @@ public: * @return ... */ bool IsHierarchyKept() const { - return configKeepHierarchy; + return mConfigKeepHierarchy; } private: @@ -108,7 +108,7 @@ private: // ------------------------------------------------------------------- // Get a bitwise combination identifying the vertex format of a mesh - unsigned int GetMeshVFormat(aiMesh *pcMesh) const; + //unsigned int GetMeshVFormat(aiMesh *pcMesh) const; // ------------------------------------------------------------------- // Count the number of vertices in the whole scene and a given @@ -131,8 +131,8 @@ private: // ------------------------------------------------------------------- // Get a list of all vertex formats that occur for a given material // The output list contains duplicate elements - void GetVFormatList(const aiScene *pcScene, unsigned int iMat, - std::list &aiOut) const; + /*void GetVFormatList(const aiScene *pcScene, unsigned int iMat, + std::list &aiOut) const;*/ // ------------------------------------------------------------------- // Compute the absolute transformation matrices of each node @@ -156,10 +156,10 @@ private: void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const; //! Configuration option: keep scene hierarchy as long as possible - bool configKeepHierarchy; - bool configNormalize; - bool configTransform; - aiMatrix4x4 configTransformation; + bool mConfigKeepHierarchy; + bool mConfigNormalize; + bool mConfigTransform; + aiMatrix4x4 mConfigTransformation; bool mConfigPointCloud; }; diff --git a/code/PostProcessing/ProcessHelper.cpp b/code/PostProcessing/ProcessHelper.cpp index 15f01676c..e55c17648 100644 --- a/code/PostProcessing/ProcessHelper.cpp +++ b/code/PostProcessing/ProcessHelper.cpp @@ -175,10 +175,9 @@ unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) { // tangents and bitangents if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4; -#ifdef BOOST_STATIC_ASSERT - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); -#endif + + static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); + static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); // texture coordinates unsigned int p = 0; diff --git a/code/PostProcessing/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp index dbc3c8822..ea8d154dc 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // internal headers - #include "RemoveRedundantMaterials.h" #include #include "ProcessHelper.h" @@ -57,35 +54,28 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() -: mConfigFixedMaterials() { - // nothing to do here -} +RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const -{ +bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; } // ------------------------------------------------------------------------------------------------ // Setup import properties -void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) -{ +void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) { // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void RemoveRedundantMatsProcess::Execute( aiScene* pScene) -{ +void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); unsigned int redundantRemoved = 0, unreferencedRemoved = 0; - if (pScene->mNumMaterials) - { + if (pScene->mNumMaterials) { // Find out which materials are referenced by meshes std::vector abReferenced(pScene->mNumMaterials,false); for (unsigned int i = 0;i < pScene->mNumMeshes;++i) @@ -134,8 +124,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) // we do already have a specific hash. This allows us to // determine which materials are identical. uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { // No mesh is referencing this material, remove it. if (!abReferenced[i]) { ++unreferencedRemoved; @@ -147,8 +136,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) // Check all previously mapped materials for a matching hash. // On a match we can delete this material and just make it ref to the same index. uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); - for (unsigned int a = 0; a < i;++a) - { + for (unsigned int a = 0; a < i;++a) { if (abReferenced[a] && me == aiHashes[a]) { ++redundantRemoved; me = 0; @@ -205,12 +193,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) delete[] aiHashes; delete[] aiMappingTable; } - if (redundantRemoved == 0 && unreferencedRemoved == 0) - { + if (redundantRemoved == 0 && unreferencedRemoved == 0) { ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); - } - else - { + } else { ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ", unreferencedRemoved, " unused materials."); } diff --git a/code/PostProcessing/ScaleProcess.cpp b/code/PostProcessing/ScaleProcess.cpp index 00df07090..1bb9196f1 100644 --- a/code/PostProcessing/ScaleProcess.cpp +++ b/code/PostProcessing/ScaleProcess.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 394ef15c8..47633dce5 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -99,8 +99,9 @@ void UpdateNodes(const std::vector &replaceMeshIndex, aiNode *node } // call all subnodes recursively - for (unsigned int m = 0; m < node->mNumChildren; ++m) + for (unsigned int m = 0; m < node->mNumChildren; ++m) { UpdateNodes(replaceMeshIndex, node->mChildren[m]); + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index e44a55979..969146fee 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -57,9 +57,7 @@ using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ // Constructor -SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) { - // empty -} +SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag. diff --git a/code/PostProcessing/SplitLargeMeshes.cpp b/code/PostProcessing/SplitLargeMeshes.cpp index 73e0cc5d8..b6e5b772a 100644 --- a/code/PostProcessing/SplitLargeMeshes.cpp +++ b/code/PostProcessing/SplitLargeMeshes.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -40,9 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** - * @file Implementation of the SplitLargeMeshes postprocessing step - */ + /// @file Implementation of the SplitLargeMeshes postprocessing step // internal headers of the post-processing framework #include "SplitLargeMeshes.h" @@ -75,22 +72,22 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) { this->SplitMesh(a, pScene->mMeshes[a],avList); } - if (avList.size() != pScene->mNumMeshes) { - // it seems something has been split. rebuild the mesh list - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)avList.size(); - pScene->mMeshes = new aiMesh*[avList.size()]; - - for (unsigned int i = 0; i < avList.size();++i) { - pScene->mMeshes[i] = avList[i].first; - } - - // now we need to update all nodes - this->UpdateNode(pScene->mRootNode,avList); - ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); - } else { + if (avList.size() == pScene->mNumMeshes) { ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); } + + // it seems something has been split. rebuild the mesh list + delete[] pScene->mMeshes; + pScene->mNumMeshes = (unsigned int)avList.size(); + pScene->mMeshes = new aiMesh*[avList.size()]; + + for (unsigned int i = 0; i < avList.size();++i) { + pScene->mMeshes[i] = avList[i].first; + } + + // now we need to update all nodes + this->UpdateNode(pScene->mRootNode,avList); + ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); } // ------------------------------------------------------------------------------------------------ @@ -102,8 +99,7 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) { // ------------------------------------------------------------------------------------------------ // Update a node after some meshes have been split -void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, - const std::vector >& avList) { +void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector >& avList) { // for every index in out list build a new entry std::vector aiEntries; aiEntries.reserve(pcNode->mNumMeshes + 1); diff --git a/code/PostProcessing/TextureTransform.cpp b/code/PostProcessing/TextureTransform.cpp index 2ed17f390..3de357c17 100644 --- a/code/PostProcessing/TextureTransform.cpp +++ b/code/PostProcessing/TextureTransform.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,8 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file A helper class that processes texture transformations */ - - #include #include #include @@ -494,8 +491,9 @@ void TextureTransformStep::Execute( aiScene* pScene) { ai_assert(nullptr != src); // Copy the data to the destination array - if (dest != src) + if (dest != src) { ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); + } end = dest + mesh->mNumVertices; diff --git a/code/PostProcessing/TriangulateProcess.cpp b/code/PostProcessing/TriangulateProcess.cpp index 52cfa66bf..b4c66b41e 100644 --- a/code/PostProcessing/TriangulateProcess.cpp +++ b/code/PostProcessing/TriangulateProcess.cpp @@ -158,15 +158,13 @@ namespace { // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool TriangulateProcess::IsActive( unsigned int pFlags) const -{ +bool TriangulateProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_Triangulate) != 0; } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void TriangulateProcess::Execute( aiScene* pScene) -{ +void TriangulateProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("TriangulateProcess begin"); bool bHas = false; @@ -187,8 +185,7 @@ void TriangulateProcess::Execute( aiScene* pScene) // ------------------------------------------------------------------------------------------------ // Triangulates the given mesh. -bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) -{ +bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases if (!pMesh->mPrimitiveTypes) { bool bNeed = false; @@ -218,8 +215,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) if( face.mNumIndices <= 3) { numOut++; - } - else { + } else { numOut += face.mNumIndices-2; max_out = std::max(max_out,face.mNumIndices); } @@ -511,22 +507,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) #endif num = 0; break; - - /*curOut -= (max-num); // undo all previous work - for (tmp = 0; tmp < max-2; ++tmp) { - aiFace& nface = *curOut++; - - nface.mNumIndices = 3; - if (!nface.mIndices) - nface.mIndices = new unsigned int[3]; - - nface.mIndices[0] = 0; - nface.mIndices[1] = tmp+1; - nface.mIndices[2] = tmp+2; - - } - num = 0; - break;*/ } aiFace& nface = *curOut++; @@ -580,23 +560,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) for(aiFace* f = last_face; f != curOut; ) { unsigned int* i = f->mIndices; - // drop dumb 0-area triangles - deactivated for now: - //FindDegenerates post processing step can do the same thing - //if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) { - // ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0"); - // --curOut; - - // delete[] f->mIndices; - // f->mIndices = nullptr; - - // for(aiFace* ff = f; ff != curOut; ++ff) { - // ff->mNumIndices = (ff+1)->mNumIndices; - // ff->mIndices = (ff+1)->mIndices; - // (ff+1)->mIndices = nullptr; - // } - // continue; - //} - i[0] = idx[i[0]]; i[1] = idx[i[1]]; i[2] = idx[i[2]]; diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index cae35b895..af4ff788e 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -110,18 +108,21 @@ inline int HasNameMatch(const aiString &in, aiNode *node) { template inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) { // validate all entries - if (size) { - if (!parray) { - ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", - firstName, secondName, size); - } - for (unsigned int i = 0; i < size; ++i) { - if (!parray[i]) { - ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)", - firstName, i, secondName, size); - } - Validate(parray[i]); + if (size == 0) { + return; + } + + if (!parray) { + ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", + firstName, secondName, size); + } + + for (unsigned int i = 0; i < size; ++i) { + if (!parray[i]) { + ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)", + firstName, i, secondName, size); } + Validate(parray[i]); } } @@ -130,25 +131,27 @@ template inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size, const char *firstName, const char *secondName) { // validate all entries - if (size) { - if (!parray) { - ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", - firstName, secondName, size); + if (size == 0) { + return; + } + + if (!parray) { + ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", + firstName, secondName, size); + } + for (unsigned int i = 0; i < size; ++i) { + if (!parray[i]) { + ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)", + firstName, i, secondName, size); } - for (unsigned int i = 0; i < size; ++i) { - if (!parray[i]) { - ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)", - firstName, i, secondName, size); - } - Validate(parray[i]); + Validate(parray[i]); - // check whether there are duplicate names - for (unsigned int a = i + 1; a < size; ++a) { - if (parray[i]->mName == parray[a]->mName) { - ReportError("aiScene::%s[%u] has the same name as " - "aiScene::%s[%u]", - firstName, i, secondName, a); - } + // check whether there are duplicate names + for (unsigned int a = i + 1; a < size; ++a) { + if (parray[i]->mName == parray[a]->mName) { + ReportError("aiScene::%s[%u] has the same name as " + "aiScene::%s[%u]", + firstName, i, secondName, a); } } } @@ -229,12 +232,6 @@ void ValidateDSProcess::Execute(aiScene *pScene) { if (pScene->mNumMaterials) { DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials"); } -#if 0 - // NOTE: ScenePreprocessor generates a default material if none is there - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { - ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); - } -#endif else if (pScene->mMaterials) { ReportError("aiScene::mMaterials is non-null although there are no materials"); } @@ -267,8 +264,7 @@ void ValidateDSProcess::Validate(const aiCamera *pCamera) { if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear) ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); - // FIX: there are many 3ds files with invalid FOVs. No reason to - // reject them at all ... a warning is appropriate. + // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate. if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV); } @@ -362,15 +358,6 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh) { if (face.mIndices[a] >= pMesh->mNumVertices) { ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a); } - // the MSB flag is temporarily used by the extra verbose - // mode to tell us that the JoinVerticesProcess might have - // been executed already. - /*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) && - abRefList[face.mIndices[a]]) - { - ReportError("aiMesh::mVertices[%i] is referenced twice - second " - "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a); - }*/ abRefList[face.mIndices[a]] = true; } } @@ -466,7 +453,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float this->Validate(&pBone->mName); if (!pBone->mNumWeights) { - //ReportError("aiBone::mNumWeights is zero"); + ReportWarning("aiBone::mNumWeights is zero"); } // check whether all vertices affected by this bone are valid diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index 1bdfcc650..50e28447c 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -68,8 +66,7 @@ namespace Assimp { */ // -------------------------------------------------------------------------------------------- template -class StreamWriter -{ +class StreamWriter { enum { INITIAL_CAPACITY = 1024 }; diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index b4aa1dd2d..3fc974504 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -97,14 +97,20 @@ namespace Assimp { * to *all* vertex components equally. This is useful for stuff like interpolation * or subdivision, but won't work if special handling is required for some vertex components. */ // ------------------------------------------------------------------------------------------------ -class Vertex { +struct Vertex { friend Vertex operator + (const Vertex&,const Vertex&); friend Vertex operator - (const Vertex&,const Vertex&); friend Vertex operator * (const Vertex&,ai_real); friend Vertex operator / (const Vertex&,ai_real); friend Vertex operator * (ai_real, const Vertex&); -public: + aiVector3D position; + aiVector3D normal; + aiVector3D tangent, bitangent; + + aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS]; + Vertex() = default; // ---------------------------------------------------------------------------- @@ -178,7 +184,7 @@ public: } // ---------------------------------------------------------------------------- - /** Convert back to non-interleaved storage */ + /// Convert back to non-interleaved storage void SortBack(aiMesh* out, unsigned int idx) const { ai_assert(idxmNumVertices); out->mVertices[idx] = position; @@ -204,7 +210,7 @@ public: private: // ---------------------------------------------------------------------------- - /** Construct from two operands and a binary operation to combine them */ + /// Construct from two operands and a binary operation to combine them template