Merge branch 'master' into msvc-clang-unused-function

pull/5083/head
Kim Kulling 2023-05-24 23:23:40 +02:00 committed by GitHub
commit f43cfa1fba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 1133 additions and 844 deletions

View File

@ -397,10 +397,6 @@ struct Material {
Material(const Material &other) = default; Material(const Material &other) = default;
Material(Material &&other) AI_NO_EXCEPT = default;
Material &operator=(Material &&other) AI_NO_EXCEPT = default;
virtual ~Material() = default; virtual ~Material() = default;
//! Name of the material //! Name of the material

View File

@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers // internal headers
@ -322,21 +321,6 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nd->mNodeName.Set(me->mName + ".Target"); nd->mNodeName.Set(me->mName + ".Target");
// If there is no input position channel we will need
// to supply the default position from the node's
// local transformation matrix.
/*TargetAnimationHelper helper;
if (me->mAnim.akeyPositions.empty())
{
aiMatrix4x4& mat = (*i)->mTransform;
helper.SetFixedMainAnimationChannel(aiVector3D(
mat.a4, mat.b4, mat.c4));
}
else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
helper.Process(&me->mTargetAnim.akeyPositions);*/
// Allocate the key array and fill it // Allocate the key array and fill it
nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size(); nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];

View File

@ -342,8 +342,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 // 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); const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@ -409,7 +408,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// XXX this is vulnerable to stack overflowing .. // XXX this is vulnerable to stack overflowing ..
while(Offset(input, cursor) < end_offset - sentinel_block_length) { 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) )); output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
@ -432,8 +431,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 // 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); ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file"); ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
@ -466,7 +464,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
try try
{ {
while (cursor < end ) { while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
break; break;
} }
} }

View File

@ -243,7 +243,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Document::Document(const Parser& parser, const ImportSettings& settings) : Document::Document(Parser& parser, const ImportSettings& settings) :
settings(settings), parser(parser) { settings(settings), parser(parser) {
ASSIMP_LOG_DEBUG("Creating FBX Document"); ASSIMP_LOG_DEBUG("Creating FBX Document");
@ -265,13 +265,17 @@ Document::Document(const 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) { for (ObjectMap::value_type &v : objects) {
delete v.second; delete_LazyObject(v.second);
} }
for (ConnectionMap::value_type &v : src_connections) { for (ConnectionMap::value_type &v : src_connections) {
delete v.second; delete_Connection(v.second);
} }
// |dest_connections| contain the same Connection objects as the |src_connections| // |dest_connections| contain the same Connection objects as the |src_connections|
} }
@ -356,9 +360,11 @@ void Document::ReadObjects() {
DOMError("no Objects dictionary found"); DOMError("no Objects dictionary found");
} }
StackAllocator &allocator = parser.GetAllocator();
// add a dummy entry to represent the Model::RootNode object (id 0), // add a dummy entry to represent the Model::RootNode object (id 0),
// which is only indirectly defined in the input file // which is only indirectly defined in the input file
objects[0] = new LazyObject(0L, *eobjects, *this); objects[0] = new_LazyObject(0L, *eobjects, *this);
const Scope& sobjects = *eobjects->Compound(); const Scope& sobjects = *eobjects->Compound();
for(const ElementMap::value_type& el : sobjects.Elements()) { for(const ElementMap::value_type& el : sobjects.Elements()) {
@ -387,7 +393,7 @@ void Document::ReadObjects() {
delete foundObject->second; delete foundObject->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 // grab all animation stacks upfront since there is no listing of them
if(!strcmp(el.first.c_str(),"AnimationStack")) { if(!strcmp(el.first.c_str(),"AnimationStack")) {
@ -454,7 +460,9 @@ void Document::ReadPropertyTemplates() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Document::ReadConnections() { void Document::ReadConnections()
{
StackAllocator &allocator = parser.GetAllocator();
const Scope &sc = parser.GetRootScope(); const Scope &sc = parser.GetRootScope();
// read property templates from "Definitions" section // read property templates from "Definitions" section
const Element* const econns = sc["Connections"]; const Element* const econns = sc["Connections"];
@ -494,7 +502,7 @@ void Document::ReadConnections() {
} }
// add new connection // 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)); src_connections.insert(ConnectionMap::value_type(src,c));
dest_connections.insert(ConnectionMap::value_type(dest,c)); dest_connections.insert(ConnectionMap::value_type(dest,c));
} }

View File

@ -81,6 +81,10 @@ class BlendShape;
class Skin; class Skin;
class Cluster; 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 /** Represents a delay-parsed FBX objects. Many objects in the scene
* are not needed by assimp, so it makes no sense to parse them * are not needed by assimp, so it makes no sense to parse them
@ -1073,7 +1077,7 @@ private:
/** DOM root for a FBX file */ /** DOM root for a FBX file */
class Document { class Document {
public: public:
Document(const Parser& parser, const ImportSettings& settings); Document(Parser& parser, const ImportSettings& settings);
~Document(); ~Document();
@ -1157,7 +1161,7 @@ private:
const ImportSettings& settings; const ImportSettings& settings;
ObjectMap objects; ObjectMap objects;
const Parser& parser; Parser& parser;
PropertyTemplateMap templates; PropertyTemplateMap templates;
ConnectionMap src_connections; ConnectionMap src_connections;

View File

@ -152,19 +152,19 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// broad-phase tokenized pass in which we identify the core // broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens; TokenList tokens;
Assimp::StackAllocator tempAllocator;
try { try {
bool is_binary = false; bool is_binary = false;
if (!strncmp(begin, "Kaydara FBX Binary", 18)) { if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
is_binary = true; is_binary = true;
TokenizeBinary(tokens, begin, contents.size()); TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
} else { } else {
Tokenize(tokens, begin); Tokenize(tokens, begin, tempAllocator);
} }
// use this information to construct a very rudimentary // use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure // 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 // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, mSettings); Document doc(parser, mSettings);
@ -183,9 +183,11 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// assimp universal format (M) // assimp universal format (M)
SetFileScale(size_relative_to_cm * 0.01f); SetFileScale(size_relative_to_cm * 0.01f);
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); // 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<Token>());
} catch (std::exception &) { } catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
throw; throw;
} }
} }

View File

@ -116,8 +116,11 @@ namespace Assimp {
namespace FBX { 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; TokenPtr n = nullptr;
StackAllocator &allocator = parser.GetAllocator();
do { do {
n = parser.AdvanceToNextToken(); n = parser.AdvanceToNextToken();
if(!n) { if(!n) {
@ -146,7 +149,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
} }
if (n->Type() == TokenType_OPEN_BRACKET) { if (n->Type() == TokenType_OPEN_BRACKET) {
compound.reset(new Scope(parser)); compound = new_Scope(parser);
// current token should be a TOK_CLOSE_BRACKET // current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken(); n = parser.CurrentToken();
@ -164,6 +167,15 @@ 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
}
Scope::Scope(Parser& parser,bool topLevel) Scope::Scope(Parser& parser,bool topLevel)
{ {
if(!topLevel) { if(!topLevel) {
@ -173,6 +185,7 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
} }
StackAllocator &allocator = parser.GetAllocator();
TokenPtr n = parser.AdvanceToNextToken(); TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) { if (n == nullptr) {
ParseError("unexpected end of file"); ParseError("unexpected end of file");
@ -207,22 +220,27 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::~Scope() { 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) { for (ElementMap::value_type &v : elements) {
delete v.second; delete_Element(v.second);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Parser::Parser (const TokenList& tokens, bool is_binary) Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
: tokens(tokens) tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
, last()
, current()
, cursor(tokens.begin())
, is_binary(is_binary)
{ {
ASSIMP_LOG_DEBUG("Parsing FBX tokens"); ASSIMP_LOG_DEBUG("Parsing FBX tokens");
root.reset(new Scope(*this,true)); root = new_Scope(*this, true);
}
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
delete_Scope(root);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/LogAux.h> #include <assimp/LogAux.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include "Common/StackAllocator.h"
#include "FBXCompileConfig.h" #include "FBXCompileConfig.h"
#include "FBXTokenizer.h" #include "FBXTokenizer.h"
@ -63,14 +64,14 @@ class Parser;
class Element; class Element;
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03 // XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef std::vector< Scope* > ScopeList; using ScopeList = std::vector<Scope*>;
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> 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
#define delete_Scope(_p) (_p)->~Scope()
#define delete_Element(_p) (_p)->~Element()
/** FBX data entity that consists of a key:value tuple. /** FBX data entity that consists of a key:value tuple.
* *
@ -82,15 +83,16 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
* @endverbatim * @endverbatim
* *
* As can be seen in this sample, elements can contain nested #Scope * As can be seen in this sample, elements can contain nested #Scope
* as their trailing member. **/ * as their trailing member.
**/
class Element class Element
{ {
public: public:
Element(const Token& key_token, Parser& parser); Element(const Token& key_token, Parser& parser);
~Element() = default; ~Element();
const Scope* Compound() const { const Scope* Compound() const {
return compound.get(); return compound;
} }
const Token& KeyToken() const { const Token& KeyToken() const {
@ -104,7 +106,7 @@ public:
private: private:
const Token& key_token; const Token& key_token;
TokenList tokens; TokenList tokens;
std::unique_ptr<Scope> compound; Scope* compound;
}; };
/** FBX data entity that consists of a 'scope', a collection /** FBX data entity that consists of a 'scope', a collection
@ -159,8 +161,8 @@ class Parser
public: public:
/** Parse given a token list. Does not take ownership of the tokens - /** Parse given a token list. Does not take ownership of the tokens -
* the objects must persist during the entire parser lifetime */ * 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() = default; ~Parser();
const Scope& GetRootScope() const { const Scope& GetRootScope() const {
return *root; return *root;
@ -170,6 +172,10 @@ public:
return is_binary; return is_binary;
} }
StackAllocator &GetAllocator() {
return allocator;
}
private: private:
friend class Scope; friend class Scope;
friend class Element; friend class Element;
@ -180,10 +186,10 @@ private:
private: private:
const TokenList& tokens; const TokenList& tokens;
StackAllocator &allocator;
TokenPtr last, current; TokenPtr last, current;
TokenList::const_iterator cursor; TokenList::const_iterator cursor;
std::unique_ptr<Scope> root; Scope *root;
const bool is_binary; const bool is_binary;
}; };

View File

@ -94,7 +94,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'. // 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 line,
unsigned int column, unsigned int column,
TokenType type = TokenType_DATA, TokenType type = TokenType_DATA,
@ -131,8 +132,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); ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file"); ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
@ -164,7 +164,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
in_double_quotes = false; in_double_quotes = false;
token_end = cur; 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; pending_data_token = false;
} }
continue; continue;
@ -181,30 +181,30 @@ void Tokenize(TokenList& output_tokens, const char* input)
continue; continue;
case ';': case ';':
ProcessDataToken(output_tokens,token_begin,token_end,line,column); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
comment = true; comment = true;
continue; continue;
case '{': 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)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
continue; continue;
case '}': 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)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
continue; continue;
case ',': case ',':
if (pending_data_token) { 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)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
continue; continue;
case ':': case ':':
if (pending_data_token) { 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 { else {
TokenizeError("unexpected colon", line, column); TokenizeError("unexpected colon", line, column);
@ -226,7 +226,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; pending_data_token = false;

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_TOKENIZER_H #define INCLUDED_AI_FBX_TOKENIZER_H
#include "FBXCompileConfig.h" #include "FBXCompileConfig.h"
#include "Common/StackAllocator.h"
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/defs.h> #include <assimp/defs.h>
#include <vector> #include <vector>
@ -157,7 +158,8 @@ private:
typedef const Token* TokenPtr; typedef const Token* TokenPtr;
typedef std::vector< TokenPtr > TokenList; typedef std::vector< TokenPtr > TokenList;
#define new_Token new Token #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. /** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
@ -167,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList;
* @param output_tokens Receives a list of all tokens in the input data. * @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated. * @param input_buffer Textual input buffer to be processed, 0-terminated.
* @throw DeadlyImportError if something goes wrong */ * @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. /** Tokenizer function for binary FBX files.
@ -178,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
* @param input_buffer Binary input buffer to be processed. * @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal. * @param length Length of input buffer, in bytes. There is no 0-terminal.
* @throw DeadlyImportError if something goes wrong */ * @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 } // ! FBX

View File

@ -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 <typename T>
struct destructor_fun {
void operator()(const volatile T* del) {
if (del) {
del->~T();
}
}
};
/** Get a string representation for a #TokenType. */ /** Get a string representation for a #TokenType. */
const char* TokenTypeString(TokenType t); const char* TokenTypeString(TokenType t);

View File

@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetLib/IFC/IFCUtil.h" #include "AssetLib/IFC/IFCUtil.h"
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "Geometry/GeometryUtils.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
namespace Assimp { namespace Assimp {
@ -235,7 +236,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
struct CompareVector { struct CompareVector {
bool operator () (const IfcVector3& a, const IfcVector3& b) const { bool operator () (const IfcVector3& a, const IfcVector3& b) const {
IfcVector3 d = a - b; IfcVector3 d = a - b;
IfcFloat eps = ai_epsilon; constexpr IfcFloat eps = ai_epsilon;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps); return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
} }
}; };

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -51,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetLib/LWO/LWOLoader.h" #include "AssetLib/LWO/LWOLoader.h"
#include "PostProcessing/ConvertToLHProcess.h" #include "PostProcessing/ConvertToLHProcess.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
#include "Geometry/GeometryUtils.h"
#include <assimp/ByteSwapper.h> #include <assimp/ByteSwapper.h>
#include <assimp/SGSpatialSort.h> #include <assimp/SGSpatialSort.h>
@ -528,7 +527,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
continue; continue;
vNormals += v; vNormals += v;
} }
mesh->mNormals[idx] = vNormals.Normalize();
} }
} }
} }
@ -549,7 +547,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
const aiVector3D &v = faceNormals[*a]; const aiVector3D &v = faceNormals[*a];
vNormals += v; vNormals += v;
} }
vNormals.Normalize();
for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) { for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
mesh->mNormals[*a] = vNormals; mesh->mNormals[*a] = vNormals;
vertexDone[*a] = true; vertexDone[*a] = true;
@ -557,6 +554,7 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
} }
} }
} }
GeometryUtils::normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -578,7 +578,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
aiString name; aiString name;
pScene->mMaterials[b]->Get( AI_MATKEY_NAME, name); pScene->mMaterials[b]->Get( AI_MATKEY_NAME, name);
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) { if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
oldMat.sceneIndex = a; oldMat.sceneIndex = b;
break; break;
} }
} }

View File

@ -58,8 +58,6 @@ class X3DExporter {
Value(value) { Value(value) {
// empty // empty
} }
SAttribute(SAttribute &&rhs) AI_NO_EXCEPT = default;
}; };
/***********************************************/ /***********************************************/

View File

@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* glTF Extensions Support: * glTF Extensions Support:
* KHR_materials_pbrSpecularGlossiness full * KHR_materials_pbrSpecularGlossiness full
* KHR_materials_specular full
* KHR_materials_unlit full * KHR_materials_unlit full
* KHR_lights_punctual full * KHR_lights_punctual full
* KHR_materials_sheen full * KHR_materials_sheen full
@ -710,6 +711,7 @@ const vec4 defaultBaseColor = { 1, 1, 1, 1 };
const vec3 defaultEmissiveFactor = { 0, 0, 0 }; const vec3 defaultEmissiveFactor = { 0, 0, 0 };
const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 }; const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 };
const vec3 defaultSpecularFactor = { 1, 1, 1 }; const vec3 defaultSpecularFactor = { 1, 1, 1 };
const vec3 defaultSpecularColorFactor = { 0, 0, 0 };
const vec3 defaultSheenFactor = { 0, 0, 0 }; const vec3 defaultSheenFactor = { 0, 0, 0 };
const vec3 defaultAttenuationColor = { 1, 1, 1 }; const vec3 defaultAttenuationColor = { 1, 1, 1 };
@ -753,6 +755,16 @@ struct PbrSpecularGlossiness {
void SetDefaults(); void SetDefaults();
}; };
struct MaterialSpecular {
float specularFactor;
vec3 specularColorFactor;
TextureInfo specularTexture;
TextureInfo specularColorTexture;
MaterialSpecular() { SetDefaults(); }
void SetDefaults();
};
struct MaterialSheen { struct MaterialSheen {
vec3 sheenColorFactor; vec3 sheenColorFactor;
float sheenRoughnessFactor; float sheenRoughnessFactor;
@ -817,6 +829,9 @@ struct Material : public Object {
//extension: KHR_materials_pbrSpecularGlossiness //extension: KHR_materials_pbrSpecularGlossiness
Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness; Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
//extension: KHR_materials_specular
Nullable<MaterialSpecular> materialSpecular;
//extension: KHR_materials_sheen //extension: KHR_materials_sheen
Nullable<MaterialSheen> materialSheen; Nullable<MaterialSheen> materialSheen;
@ -1099,6 +1114,7 @@ public:
//! Keeps info about the enabled extensions //! Keeps info about the enabled extensions
struct Extensions { struct Extensions {
bool KHR_materials_pbrSpecularGlossiness; bool KHR_materials_pbrSpecularGlossiness;
bool KHR_materials_specular;
bool KHR_materials_unlit; bool KHR_materials_unlit;
bool KHR_lights_punctual; bool KHR_lights_punctual;
bool KHR_texture_transform; bool KHR_texture_transform;
@ -1114,6 +1130,7 @@ public:
Extensions() : Extensions() :
KHR_materials_pbrSpecularGlossiness(false), KHR_materials_pbrSpecularGlossiness(false),
KHR_materials_specular(false),
KHR_materials_unlit(false), KHR_materials_unlit(false),
KHR_lights_punctual(false), KHR_lights_punctual(false),
KHR_texture_transform(false), KHR_texture_transform(false),

View File

@ -1264,6 +1264,19 @@ inline void Material::Read(Value &material, Asset &r) {
} }
} }
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<MaterialSpecular>(specular);
}
}
// Extension KHR_texture_transform is handled in ReadTextureProperty // Extension KHR_texture_transform is handled in ReadTextureProperty
if (r.extensionsUsed.KHR_materials_sheen) { if (r.extensionsUsed.KHR_materials_sheen) {
@ -1361,6 +1374,12 @@ inline void PbrSpecularGlossiness::SetDefaults() {
glossinessFactor = 1.0f; glossinessFactor = 1.0f;
} }
inline void MaterialSpecular::SetDefaults() {
//KHR_materials_specular properties
SetVector(specularColorFactor, defaultSpecularColorFactor);
specularFactor = 0.f;
}
inline void MaterialSheen::SetDefaults() { inline void MaterialSheen::SetDefaults() {
//KHR_materials_sheen properties //KHR_materials_sheen properties
SetVector(sheenColorFactor, defaultSheenFactor); SetVector(sheenColorFactor, defaultSheenFactor);
@ -2047,6 +2066,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
} }
CHECK_EXT(KHR_materials_pbrSpecularGlossiness); CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_specular);
CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_materials_unlit);
CHECK_EXT(KHR_lights_punctual); CHECK_EXT(KHR_lights_punctual);
CHECK_EXT(KHR_texture_transform); CHECK_EXT(KHR_texture_transform);

View File

@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* glTF Extensions Support: * glTF Extensions Support:
* KHR_materials_pbrSpecularGlossiness: full * KHR_materials_pbrSpecularGlossiness: full
* KHR_materials_specular: full
* KHR_materials_unlit: full * KHR_materials_unlit: full
* KHR_materials_sheen: full * KHR_materials_sheen: full
* KHR_materials_clearcoat: full * KHR_materials_clearcoat: full

View File

@ -418,6 +418,26 @@ namespace glTF2 {
exts.AddMember("KHR_materials_unlit", unlit, w.mAl); 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.0f) {
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) { if (m.materialSheen.isPresent) {
Value materialSheen(rapidjson::Type::kObjectType); Value materialSheen(rapidjson::Type::kObjectType);
@ -929,6 +949,10 @@ namespace glTF2 {
exts.PushBack(StringRef("KHR_materials_unlit"), mAl); 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) { if (this->mAsset.extensionsUsed.KHR_materials_sheen) {
exts.PushBack(StringRef("KHR_materials_sheen"), mAl); exts.PushBack(StringRef("KHR_materials_sheen"), mAl);
} }

View File

@ -640,11 +640,10 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial &mat, vec3 &prop, const cha
return result; 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 glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) {
bool result = false; bool result = false;
// If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension // 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
if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) {
result = true; result = true;
} else { } else {
@ -674,6 +673,25 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
return result; return result;
} }
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
// Specular requires either/or, default factors of zero disables specular, so do not export
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
return false;
}
// 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) { bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
// Return true if got any valid Sheen properties or textures // Return true if got any valid Sheen properties or textures
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) { if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
@ -818,9 +836,9 @@ void glTF2Exporter::ExportMaterials() {
m->alphaMode = alphaMode.C_Str(); 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 (mProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) {
// KHR_materials_pbrSpecularGlossiness extension // KHR_materials_pbrSpecularGlossiness extension
// NOTE: This extension is being considered for deprecation (Dec 2020)
PbrSpecularGlossiness pbrSG; PbrSpecularGlossiness pbrSG;
if (GetMatSpecGloss(mat, pbrSG)) { if (GetMatSpecGloss(mat, pbrSG)) {
mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
@ -837,7 +855,12 @@ void glTF2Exporter::ExportMaterials() {
} else { } else {
// These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness // These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness
if (!m->pbrSpecularGlossiness.isPresent) { if (!m->pbrSpecularGlossiness.isPresent) {
// Sheen MaterialSpecular specular;
if (GetMatSpecular(mat, specular)) {
mAsset->extensionsUsed.KHR_materials_specular = true;
m->materialSpecular = Nullable<MaterialSpecular>(specular);
}
MaterialSheen sheen; MaterialSheen sheen;
if (GetMatSheen(mat, sheen)) { if (GetMatSheen(mat, sheen)) {
mAsset->extensionsUsed.KHR_materials_sheen = true; mAsset->extensionsUsed.KHR_materials_sheen = true;

View File

@ -76,6 +76,7 @@ struct OcclusionTextureInfo;
struct Node; struct Node;
struct Texture; struct Texture;
struct PbrSpecularGlossiness; struct PbrSpecularGlossiness;
struct MaterialSpecular;
struct MaterialSheen; struct MaterialSheen;
struct MaterialClearcoat; struct MaterialClearcoat;
struct MaterialTransmission; struct MaterialTransmission;
@ -117,6 +118,7 @@ protected:
aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec4 &prop, const char *propName, int type, int idx) const; 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; 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 GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG);
bool GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular);
bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen); bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen);
bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat); bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat);
bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission); bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission);

View File

@ -278,8 +278,19 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); 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 // pbrSpecularGlossiness
if (mat.pbrSpecularGlossiness.isPresent) { else if (mat.pbrSpecularGlossiness.isPresent) {
PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);

View File

@ -194,6 +194,8 @@ SET( Common_SRCS
Common/ScenePreprocessor.cpp Common/ScenePreprocessor.cpp
Common/ScenePreprocessor.h Common/ScenePreprocessor.h
Common/SkeletonMeshBuilder.cpp Common/SkeletonMeshBuilder.cpp
Common/StackAllocator.h
Common/StackAllocator.inl
Common/StandardShapes.cpp Common/StandardShapes.cpp
Common/TargetAnimation.cpp Common/TargetAnimation.cpp
Common/TargetAnimation.h Common/TargetAnimation.h
@ -1387,7 +1389,7 @@ ENDIF()
# Add RT-extension library for glTF importer with Open3DGC-compression. # Add RT-extension library for glTF importer with Open3DGC-compression.
IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) TARGET_LINK_LIBRARIES(assimp rt)
ENDIF () ENDIF ()

View File

@ -225,7 +225,7 @@ static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporte
#endif #endif
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER #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 #endif
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER

View File

@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) {
case AI_AIVECTOR3D: case AI_AIVECTOR3D:
out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData)); out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData));
break; break;
case AI_AIMETADATA:
out.mData = new aiMetadata(*static_cast<aiMetadata *>(in.mData));
break;
default: default:
ai_assert(false); ai_assert(false);
break; break;

View File

@ -0,0 +1,92 @@
/*
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 <vector>
#include <stdint.h>
#include <stddef.h>
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:
/// @brief Constructs the allocator
inline StackAllocator();
/// @brief Destructs the allocator and frees all memory
inline ~StackAllocator();
// non copyable
StackAllocator(const StackAllocator &) = delete;
StackAllocator &operator=(const StackAllocator &) = delete;
/// @brief Returns a pointer to byteSize bytes of heap memory that persists
/// for the lifetime of the allocator (or until FreeAll is called).
inline void *Allocate(size_t byteSize);
/// @brief Releases all the memory owned by this allocator.
// Memory provided through function Allocate is not valid anymore after this function has been called.
inline 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::vector<uint8_t *> m_storageBlocks; // A list of blocks
};
} // namespace Assimp
#include "StackAllocator.inl"
#endif // include guard

View File

@ -0,0 +1,82 @@
/*
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 <assimp/ai_assert.h>
using namespace Assimp;
inline StackAllocator::StackAllocator() {
}
inline StackAllocator::~StackAllocator() {
FreeAll();
}
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.
// 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 = new uint8_t[m_blockAllocationSize];
m_storageBlocks.emplace_back(data);
m_subIndex = byteSize;
return data;
}
uint8_t *data = m_storageBlocks.back();
data += m_subIndex;
m_subIndex += byteSize;
return data;
}
inline void StackAllocator::FreeAll() {
for (size_t i = 0; i < m_storageBlocks.size(); i++) {
delete [] m_storageBlocks[i];
}
std::vector<uint8_t *> empty;
m_storageBlocks.swap(empty);
// start over:
m_blockAllocationSize = g_startBytesPerBlock;
m_subIndex = g_maxBytesPerBlock;
}

View File

@ -45,35 +45,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
// ------------------------------------------------------------------------------------------------
ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) { ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) {
ai_real s = (a + b + c) / 2; const ai_real s = (a + b + c) / 2;
ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 ); const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
return area; return area;
} }
ai_real GeometryUtils::distance3D( const aiVector3D &vA, aiVector3D &vB ) { // ------------------------------------------------------------------------------------------------
ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB ) {
const ai_real lx = ( vB.x - vA.x ); const ai_real lx = ( vB.x - vA.x );
const ai_real ly = ( vB.y - vA.y ); const ai_real ly = ( vB.y - vA.y );
const ai_real lz = ( vB.z - vA.z ); const ai_real lz = ( vB.z - vA.z );
ai_real a = lx*lx + ly*ly + lz*lz; const ai_real a = lx*lx + ly*ly + lz*lz;
ai_real d = pow( a, (ai_real)0.5 ); const ai_real d = pow( a, (ai_real)0.5 );
return d; return d;
} }
// ------------------------------------------------------------------------------------------------
ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) { ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
ai_real area = 0; ai_real area = 0;
aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] ); const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] ); const aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
ai_real a( distance3D( vA, vB ) ); const ai_real a = distance3D( vA, vB );
ai_real b( distance3D( vB, vC ) ); const ai_real b = distance3D( vB, vC );
ai_real c( distance3D( vC, vA ) ); const ai_real c = distance3D( vC, vA );
area = heron( a, b, c ); area = heron( a, b, c );
return area; 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;
}
// ------------------------------------------------------------------------------------------------
void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut,
size_t numVectors) {
for (size_t i=0; i<numVectors; ++i) {
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
}
} // namespace Assimp } // namespace Assimp

View File

@ -47,7 +47,7 @@ namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// @brief This helper class supports some basic geometry algorithms. /// @brief This helper class supports some basic geometry algorithms.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
class GeometryUtils { class ASSIMP_API GeometryUtils {
public: public:
static ai_real heron( ai_real a, ai_real b, ai_real c ); static ai_real heron( ai_real a, ai_real b, ai_real c );
@ -55,13 +55,27 @@ public:
/// @param vA Vector a. /// @param vA Vector a.
/// @param vB Vector b. /// @param vB Vector b.
/// @return The distance. /// @return The distance.
static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ); static ai_real distance3D( const aiVector3D &vA, const aiVector3D &vB );
/// @brief Will calculate the area of a triangle described by a aiFace. /// @brief Will calculate the area of a triangle described by a aiFace.
/// @param face The face /// @param face The face
/// @param mesh The mesh containing the face /// @param mesh The mesh containing the face
/// @return The area. /// @return The area.
static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ); static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh );
/// @brief Will calculate the intersection between a ray and a plane
/// @param ray The ray to test for
/// @param planePos A point on the plane
/// @param planeNormal The plane normal to describe its orientation
/// @param pos The position of the intersection.
/// @return true is an intersection was detected, false if not.
static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos);
/// @brief Will normalize an array of vectors.
/// @param vectorArrayIn The incoming arra of vectors.
/// @param vectorArrayOut The normalized vectors.
/// @param numVectors The array size.
static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors);
}; };
} // namespace Assimp } // namespace Assimp

View File

@ -111,7 +111,22 @@ PbrtExporter::PbrtExporter(
mScene(pScene), mScene(pScene),
mIOSystem(pIOSystem), mIOSystem(pIOSystem),
mPath(path), 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. // Export embedded textures.
if (mScene->mNumTextures > 0) if (mScene->mNumTextures > 0)
if (!mIOSystem->CreateDirectory("textures")) if (!mIOSystem->CreateDirectory("textures"))
@ -260,7 +275,7 @@ aiMatrix4x4 PbrtExporter::GetNodeTransform(const aiString &name) const {
node = node->mParent; node = node->mParent;
} }
} }
return m; return mRootTransform * m;
} }
std::string PbrtExporter::TransformAsString(const aiMatrix4x4 &m) { std::string PbrtExporter::TransformAsString(const aiMatrix4x4 &m) {
@ -309,7 +324,7 @@ void PbrtExporter::WriteCamera(int i) {
// Get camera fov // Get camera fov
float hfov = AI_RAD_TO_DEG(camera->mHorizontalFOV); 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) { if (fov < 5) {
std::cerr << fov << ": suspiciously low field of view specified by camera. Setting to 45 degrees.\n"; std::cerr << fov << ": suspiciously low field of view specified by camera. Setting to 45 degrees.\n";
fov = 45; fov = 45;
@ -327,7 +342,7 @@ void PbrtExporter::WriteCamera(int i) {
if (!cameraActive) if (!cameraActive)
mOutput << "# "; mOutput << "# ";
mOutput << "Scale -1 1 1\n"; // right handed -> left handed mOutput << "Scale 1 1 1\n";
if (!cameraActive) if (!cameraActive)
mOutput << "# "; mOutput << "# ";
mOutput << "LookAt " mOutput << "LookAt "
@ -383,8 +398,8 @@ void PbrtExporter::WriteWorldDefinition() {
} }
mOutput << "# Geometry\n\n"; mOutput << "# Geometry\n\n";
aiMatrix4x4 worldFromObject;
WriteGeometricObjects(mScene->mRootNode, worldFromObject, meshUses); WriteGeometricObjects(mScene->mRootNode, mRootTransform, meshUses);
} }
void PbrtExporter::WriteTextures() { void PbrtExporter::WriteTextures() {

View File

@ -100,6 +100,9 @@ private:
// A private set to keep track of which textures have been declared // A private set to keep track of which textures have been declared
std::set<std::string> mTextureSet; std::set<std::string> 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; aiMatrix4x4 GetNodeTransform(const aiString& name) const;
static std::string TransformAsString(const aiMatrix4x4& m); static std::string TransformAsString(const aiMatrix4x4& m);

View File

@ -43,15 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <iostream>
namespace Assimp { namespace Assimp {
/// The default class constructor. static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones) {
ArmaturePopulate::ArmaturePopulate() = default; for (aiBone *bone : bones) {
if (bone->mName == bone_name) {
return true;
}
}
/// The class destructor. return false;
ArmaturePopulate::~ArmaturePopulate() = default; }
bool ArmaturePopulate::IsActive(unsigned int pFlags) const { bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_PopulateArmatureData) != 0; return (pFlags & aiProcess_PopulateArmatureData) != 0;
@ -70,7 +73,7 @@ void ArmaturePopulate::Execute(aiScene *out) {
BuildBoneList(out->mRootNode, out->mRootNode, out, bones); BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
BuildNodeList(out->mRootNode, nodes); BuildNodeList(out->mRootNode, nodes);
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes); BuildBoneStack(out->mRootNode, out, bones, bone_stack, nodes);
ASSIMP_LOG_DEBUG("Bone stack size: ", bone_stack.size()); ASSIMP_LOG_DEBUG("Bone stack size: ", bone_stack.size());
@ -78,9 +81,8 @@ void ArmaturePopulate::Execute(aiScene *out) {
aiBone *bone = kvp.first; aiBone *bone = kvp.first;
aiNode *bone_node = kvp.second; aiNode *bone_node = kvp.second;
ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str()); ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str());
// lcl transform grab - done in generate_nodes :)
// bone->mOffsetMatrix = bone_node->mTransformation; // lcl transform grab - done in generate_nodes :)
aiNode *armature = GetArmatureRoot(bone_node, bones); aiNode *armature = GetArmatureRoot(bone_node, bones);
ai_assert(armature); ai_assert(armature);
@ -159,8 +161,7 @@ void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
// A bone stack allows us to have multiple armatures, with the same bone names // A bone stack allows us to have multiple armatures, with the same bone names
// A bone stack allows us also to retrieve bones true transform even with // A bone stack allows us also to retrieve bones true transform even with
// duplicate names :) // duplicate names :)
void ArmaturePopulate::BuildBoneStack(aiNode *, void ArmaturePopulate::BuildBoneStack(const aiNode *root_node,
const aiNode *root_node,
const aiScene*, const aiScene*,
const std::vector<aiBone *> &bones, const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack, std::map<aiBone *, aiNode *> &bone_stack,
@ -196,8 +197,7 @@ void ArmaturePopulate::BuildBoneStack(aiNode *,
// This is required to be detected for a bone initially, it will recurse up // This is required to be detected for a bone initially, it will recurse up
// until it cannot find another bone and return the node No known failure // until it cannot find another bone and return the node No known failure
// points. (yet) // points. (yet)
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, std::vector<aiBone *> &bone_list) {
std::vector<aiBone *> &bone_list) {
while (nullptr != bone_node) { while (nullptr != bone_node) {
if (!IsBoneNode(bone_node->mName, bone_list)) { if (!IsBoneNode(bone_node->mName, bone_list)) {
ASSIMP_LOG_VERBOSE_DEBUG("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str()); ASSIMP_LOG_VERBOSE_DEBUG("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
@ -212,18 +212,6 @@ aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
return nullptr; return nullptr;
} }
// Simple IsBoneNode check if this could be a bone
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
std::vector<aiBone *> &bones) {
for (aiBone *bone : bones) {
if (bone->mName == bone_name) {
return true;
}
}
return false;
}
// Pop this node by name from the stack if found // Pop this node by name from the stack if found
// Used in multiple armature situations with duplicate node / bone names // Used in multiple armature situations with duplicate node / bone names
// Known flaw: cannot have nodes with bone names, will be fixed in later release // Known flaw: cannot have nodes with bone names, will be fixed in later release

View File

@ -69,10 +69,10 @@ namespace Assimp {
class ASSIMP_API ArmaturePopulate : public BaseProcess { class ASSIMP_API ArmaturePopulate : public BaseProcess {
public: public:
/// The default class constructor. /// The default class constructor.
ArmaturePopulate(); ArmaturePopulate() = default;
/// The class destructor. /// The class destructor.
virtual ~ArmaturePopulate(); virtual ~ArmaturePopulate() = default;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual bool IsActive( unsigned int pFlags ) const; virtual bool IsActive( unsigned int pFlags ) const;
@ -86,9 +86,6 @@ public:
static aiNode *GetArmatureRoot(aiNode *bone_node, static aiNode *GetArmatureRoot(aiNode *bone_node,
std::vector<aiBone *> &bone_list); std::vector<aiBone *> &bone_list);
static bool IsBoneNode(const aiString &bone_name,
std::vector<aiBone *> &bones);
static aiNode *GetNodeFromStack(const aiString &node_name, static aiNode *GetNodeFromStack(const aiString &node_name,
std::vector<aiNode *> &nodes); std::vector<aiNode *> &nodes);
@ -99,7 +96,7 @@ public:
const aiScene *scene, const aiScene *scene,
std::vector<aiBone *> &bones); std::vector<aiBone *> &bones);
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node, static void BuildBoneStack(const aiNode *root_node,
const aiScene *scene, const aiScene *scene,
const std::vector<aiBone *> &bones, const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack, std::map<aiBone *, aiNode *> &bone_stack,
@ -108,5 +105,4 @@ public:
} // Namespace Assimp } // Namespace Assimp
#endif // SCALE_PROCESS_H_ #endif // SCALE_PROCESS_H_

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -42,8 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file GenUVCoords step */ /** @file GenUVCoords step */
#include "ComputeUVMappingProcess.h" #include "ComputeUVMappingProcess.h"
#include "Geometry/GeometryUtils.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -55,35 +54,21 @@ namespace {
const static aiVector3D base_axis_x(1.0, 0.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 aiVector3D base_axis_z(0.0, 0.0, 1.0);
const static ai_real angle_epsilon = ai_real(0.95); const static ai_real angle_epsilon = ai_real(0.95);
} } // namespace
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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; 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 // 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) 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"); ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found");
return UINT_MAX; return UINT_MAX;
@ -91,8 +76,7 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Try to remove UV seams // 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 // 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 // much easier, but I don't know how and am currently too tired to
// to think about a better solution. // 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 LOWER_EPSILON = ai_real(10e-3);
const static ai_real UPPER_EPSILON = ai_real(1.0 - 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]; 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; unsigned int smallV = face.mNumIndices, large = smallV;
bool zero = false, one = false, round_to_zero = false; bool zero = false, one = false, round_to_zero = false;
@ -115,20 +100,18 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
// but the assumption that a face with at least one very small // 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 // on the one side and one very large U coord on the other side
// lies on a UV seam should work for most cases. // lies on a UV seam should work for most cases.
for (unsigned int n = 0; n < face.mNumIndices;++n) for (unsigned int n = 0; n < face.mNumIndices; ++n) {
{ if (out[face.mIndices[n]].x < LOWER_LIMIT) {
if (out[face.mIndices[n]].x < LOWER_LIMIT)
{
smallV = n; smallV = n;
// If we have a U value very close to 0 we can't // If we have a U value very close to 0 we can't
// round the others to 0, too. // round the others to 0, too.
if (out[face.mIndices[n]].x <= LOWER_EPSILON) if (out[face.mIndices[n]].x <= LOWER_EPSILON)
zero = true; 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; large = n;
// If we have a U value very close to 1 we can't // If we have a U value very close to 1 we can't
@ -137,10 +120,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
one = true; one = true;
} }
} }
if (smallV != face.mNumIndices && large != face.mNumIndices) if (smallV != face.mNumIndices && large != face.mNumIndices) {
{ for (unsigned int n = 0; n < face.mNumIndices; ++n) {
for (unsigned int n = 0; n < face.mNumIndices;++n)
{
// If the u value is over the upper limit and no other u // If the u value is over the upper limit and no other u
// value of that face is 0, round it to 0 // value of that face is 0, round it to 0
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
@ -156,8 +137,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
// Due to numerical inaccuracies one U coord becomes 0, the // Due to numerical inaccuracies one U coord becomes 0, the
// other 1. But we do still have a third UV coord to determine // other 1. But we do still have a third UV coord to determine
// to which side we must round to. // to which side we must round to.
else if (one && zero) else if (one && zero) {
{
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
out[face.mIndices[n]].x = 0.0; out[face.mIndices[n]].x = 0.0;
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
@ -169,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; aiVector3D center, min, max;
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
@ -197,16 +176,14 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F, 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); (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 // ... just the same again
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize(); 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, 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); (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 // ... just the same again
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize(); const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
@ -227,7 +204,6 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
} }
} }
// Now find and remove UV seams. A seam occurs if a face has a tcoord // 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 // close to zero on the one side, and a tcoord close to one on the
// other side. // other side.
@ -235,8 +211,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
{
aiVector3D center, min, max; aiVector3D center, min, max;
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
@ -258,8 +233,7 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
uv.y = (pos.x - min.x) / diff; 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); FindMeshCenter(mesh, center, min, max);
const ai_real diff = max.y - min.y; const ai_real diff = max.y - min.y;
@ -271,8 +245,7 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
uv.y = (pos.y - min.y) / diff; 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); FindMeshCenter(mesh, center, min, max);
const ai_real diff = max.z - min.z; const ai_real diff = max.z - min.z;
@ -309,8 +282,7 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
{
ai_real diffu, diffv; ai_real diffu, diffv;
aiVector3D center, min, max; aiVector3D center, min, max;
@ -327,8 +299,7 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
const aiVector3D &pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
out[pnt].Set((pos.z - min.z) / diffu, (pos.y - min.y) / diffv, 0.0); 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); FindMeshCenter(mesh, center, min, max);
diffu = max.x - min.x; diffu = max.x - min.x;
diffv = max.z - min.z; diffv = max.z - min.z;
@ -337,8 +308,7 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
const aiVector3D &pos = mesh->mVertices[pnt]; const aiVector3D &pos = 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);
} }
} } else if (axis * base_axis_z >= angle_epsilon) {
else if (axis * base_axis_z >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
diffu = max.x - min.x; diffu = max.x - min.x;
diffv = max.y - min.y; diffv = max.y - min.y;
@ -349,8 +319,7 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
} }
} }
// slower code path in case the mapping axis is not one of the coordinate system axes // slower code path in case the mapping axis is not one of the coordinate system axes
else else {
{
aiMatrix4x4 mTrafo; aiMatrix4x4 mTrafo;
aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo); aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
FindMeshCenterTransformed(mesh, center, min, max, mTrafo); FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
@ -368,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"); ASSIMP_LOG_ERROR("Mapping type currently not implemented");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::Execute( aiScene* pScene) void ComputeUVMappingProcess::Execute(aiScene *pScene) {
{
ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
char buffer[1024]; char buffer[1024];
@ -386,20 +353,15 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
/* Iterate through all materials and search for non-UV mapped textures /* 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(); mappingStack.clear();
aiMaterial *mat = pScene->mMaterials[i]; aiMaterial *mat = pScene->mMaterials[i];
for (unsigned int a = 0; a < mat->mNumProperties;++a) for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
{
aiMaterialProperty *prop = mat->mProperties[a]; aiMaterialProperty *prop = mat->mProperties[a];
if (!::strcmp( prop->mKey.data, "$tex.mapping")) if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
{
aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData); aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
if (aiTextureMapping_UV != mapping) if (aiTextureMapping_UV != mapping) {
{ if (!DefaultLogger::isNullLogger()) {
if (!DefaultLogger::isNullLogger())
{
ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex, aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
MappingTypeToString(mapping)); MappingTypeToString(mapping));
@ -413,8 +375,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
MappingInfo info(mapping); MappingInfo info(mapping);
// Get further properties - currently only the major axis // Get further properties - currently only the major axis
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
{
aiMaterialProperty *prop2 = mat->mProperties[a2]; aiMaterialProperty *prop2 = mat->mProperties[a2];
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
continue; continue;
@ -429,31 +390,25 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
// Check whether we have this mapping mode already // Check whether we have this mapping mode already
std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info); std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
if (mappingStack.end() != it) if (mappingStack.end() != it) {
{
idx = (*it).uv; idx = (*it).uv;
} } else {
else
{
/* We have found a non-UV mapped texture. Now /* We have found a non-UV mapped texture. Now
* we need to find all meshes using this material * we need to find all meshes using this material
* that we can compute UV channels for them. * that we can compute UV channels for them.
*/ */
for (unsigned int m = 0; m < pScene->mNumMeshes;++m) for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
{
aiMesh *mesh = pScene->mMeshes[m]; aiMesh *mesh = pScene->mMeshes[m];
unsigned int outIdx = 0; unsigned int outIdx = 0;
if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX || if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
!mesh->mNumVertices) !mesh->mNumVertices) {
{
continue; continue;
} }
// Allocate output storage // 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: case aiTextureMapping_SPHERE:
ComputeSphereMapping(mesh, info.axis, p); ComputeSphereMapping(mesh, info.axis, p);
break; break;
@ -469,8 +424,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
default: default:
ai_assert(false); ai_assert(false);
} }
if (m && idx != outIdx) if (m && idx != outIdx) {
{
ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to " ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
"this material have equal numbers of UV channels. The UV index stored in " "this material have equal numbers of UV channels. The UV index stored in "
"the material structure does therefore not apply for all meshes. "); "the material structure does therefore not apply for all meshes. ");

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -225,13 +223,6 @@ void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) {
// rotation keys // rotation keys
for (unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) { 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.x *= -1.0f;
pAnim->mRotationKeys[a].mValue.y *= -1.0f; pAnim->mRotationKeys[a].mValue.y *= -1.0f;
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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)) { if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
for(unsigned int a = 0; a < pScene->mNumMeshes; a++) { for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
if(splitList[a]) { if(splitList[a]) {
numSplits++; ++numSplits;
} }
} }
} }
@ -119,8 +118,8 @@ void DeboneProcess::Execute( aiScene* pScene) {
aiNode *theNode = find ? pScene->mRootNode->FindNode(*find) : nullptr; aiNode *theNode = find ? pScene->mRootNode->FindNode(*find) : nullptr;
std::pair<unsigned int,aiNode*> push_pair(static_cast<unsigned int>(meshes.size()),theNode); std::pair<unsigned int,aiNode*> push_pair(static_cast<unsigned int>(meshes.size()),theNode);
mSubMeshIndices[a].push_back(push_pair); mSubMeshIndices[a].emplace_back(push_pair);
meshes.push_back(newMeshes[b].first); meshes.emplace_back(newMeshes[b].first);
out+=newMeshes[b].first->mNumBones; out+=newMeshes[b].first->mNumBones;
} }
@ -360,9 +359,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const {
unsigned int m = static_cast<unsigned int>(pNode->mNumMeshes), n = static_cast<unsigned int>(mSubMeshIndices.size()); unsigned int m = static_cast<unsigned int>(pNode->mNumMeshes), n = static_cast<unsigned int>(mSubMeshIndices.size());
// first pass, look for meshes which have not moved // first pass, look for meshes which have not moved
for(unsigned int a=0;a<m;a++) { for(unsigned int a=0;a<m;a++) {
unsigned int srcIndex = pNode->mMeshes[a]; unsigned int srcIndex = pNode->mMeshes[a];
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex]; const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size()); unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());
@ -376,8 +373,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const {
// second pass, collect deboned meshes // second pass, collect deboned meshes
for(unsigned int a=0;a<n;a++) for(unsigned int a=0;a<n;a++) {
{
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a]; const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size()); unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());

View File

@ -45,12 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* normals for all imported faces. * normals for all imported faces.
*/ */
#include "DropFaceNormalsProcess.h" #include "DropFaceNormalsProcess.h"
#include <assimp/Exceptional.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Exceptional.h>
using namespace Assimp; using namespace Assimp;

View File

@ -43,9 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the FindDegenerates post-process step. * @brief Implementation of the FindDegenerates post-process step.
*/ */
#include "ProcessHelper.h"
#include "FindDegenerates.h" #include "FindDegenerates.h"
#include "Geometry/GeometryUtils.h" #include "Geometry/GeometryUtils.h"
#include "ProcessHelper.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -199,8 +199,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
} }
// We need to update the primitive flags array of the mesh. // We need to update the primitive flags array of the mesh.
switch (face.mNumIndices) switch (face.mNumIndices) {
{
case 1u: case 1u:
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
break; break;
@ -221,8 +220,7 @@ evil_jump_outside:
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
if (mConfigRemoveDegenerates && deg) { if (mConfigRemoveDegenerates && deg) {
unsigned int n = 0; unsigned int n = 0;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
{
aiFace &face_src = mesh->mFaces[a]; aiFace &face_src = mesh->mFaces[a];
if (!remove_me[a]) { if (!remove_me[a]) {
aiFace &face_dest = mesh->mFaces[n++]; aiFace &face_dest = mesh->mFaces[n++];
@ -236,8 +234,7 @@ evil_jump_outside:
face_src.mNumIndices = 0; face_src.mNumIndices = 0;
face_src.mIndices = nullptr; face_src.mIndices = nullptr;
} }
} } else {
else {
// Otherwise delete it if we don't need this face // Otherwise delete it if we don't need this face
delete[] face_src.mIndices; delete[] face_src.mIndices;
face_src.mIndices = nullptr; face_src.mIndices = nullptr;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 /// @file PretransformVertices.cpp
* @brief Implementation of the "PretransformVertices" post processing step /// @brief Implementation of the "PretransformVertices" post processing step
*/
#include "PretransformVertices.h" #include "PretransformVertices.h"
#include "ConvertToLHProcess.h" #include "ConvertToLHProcess.h"
@ -57,16 +54,44 @@ using namespace Assimp;
#define AI_PTVS_VERTEX 0x0 #define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1 #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<unsigned int> &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 // Constructor to be privately used by Importer
PretransformVertices::PretransformVertices() : PretransformVertices::PretransformVertices() :
configKeepHierarchy(false), mConfigKeepHierarchy(false),
configNormalize(false), mConfigNormalize(false),
configTransform(false), mConfigTransform(false),
configTransformation(), mConfigTransformation(),
mConfigPointCloud(false) { mConfigPointCloud(false) {}
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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) { void PretransformVertices::SetupProperties(const Importer *pImp) {
// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, // 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 // 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)); mConfigKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0)); mConfigNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 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); 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 // Count the number of vertices in the whole scene and a given material index
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
void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat, void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const { unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) { 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) { for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, iVFormat, piFaces, piVertices);
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<unsigned int> &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 // Compute the absolute transformation matrices of each node
void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) { void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
@ -297,11 +290,19 @@ void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
} }
} }
static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) {
for (size_t i=0; i<numVectors; ++i) {
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply the node transformation to a mesh // Apply the node transformation to a mesh
void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const { void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const {
// Check whether we need to transform the coordinates at all // Check whether we need to transform the coordinates at all
if (!mat.IsIdentity()) { if (mat.IsIdentity()) {
return;
}
// Check for odd negative scale (mirror) // Check for odd negative scale (mirror)
if (mesh->HasFaces() && mat.Determinant() < 0) { if (mesh->HasFaces() && mat.Determinant() < 0) {
@ -321,9 +322,7 @@ void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat)
const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose(); const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
if (mesh->HasNormals()) { if (mesh->HasNormals()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
}
} }
if (mesh->HasTangentsAndBitangents()) { if (mesh->HasTangentsAndBitangents()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
@ -333,7 +332,6 @@ void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat)
} }
} }
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Simple routine to build meshes in worldspace, no further optimization // Simple routine to build meshes in worldspace, no further optimization
@ -352,7 +350,8 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **i
// yes, we can. // yes, we can.
mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation); mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
mesh->mNumBones = UINT_MAX; mesh->mNumBones = UINT_MAX;
} else { continue;
}
// try to find us in the list of newly created meshes // try to find us in the list of newly created meshes
for (unsigned int n = 0; n < out.size(); ++n) { for (unsigned int n = 0; n < out.size(); ++n) {
@ -368,10 +367,10 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **i
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
aiMesh *ntz; aiMesh *ntz;
const unsigned int tmp = mesh->mNumBones; // const unsigned int cacheNumBones = mesh->mNumBones; //
mesh->mNumBones = 0; mesh->mNumBones = 0;
SceneCombiner::Copy(&ntz, mesh); SceneCombiner::Copy(&ntz, mesh);
mesh->mNumBones = tmp; mesh->mNumBones = cacheNumBones;
ntz->mNumBones = node->mMeshes[i]; ntz->mNumBones = node->mMeshes[i];
ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation); ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
@ -381,12 +380,12 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **i
node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1); node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1);
} }
} }
}
// call children // 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]); BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reset transformation matrices to identity // Reset transformation matrices to identity
@ -394,9 +393,10 @@ void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
nd->mTransformation = aiMatrix4x4(); nd->mTransformation = aiMatrix4x4();
// call children // call children
for (unsigned int i = 0; i < nd->mNumChildren; ++i) for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
MakeIdentityTransform(nd->mChildren[i]); MakeIdentityTransform(nd->mChildren[i]);
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Build reference counters for all meshes // Build reference counters for all meshes
@ -405,9 +405,28 @@ void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int
refs[nd->mMeshes[i]]++; refs[nd->mMeshes[i]]++;
// call children // 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); BuildMeshRefCountArray(nd->mChildren[i], refs);
} }
}
// ------------------------------------------------------------------------------------------------
static void appendNewMeshesToScene(aiScene *pScene, std::vector<aiMesh*> &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<unsigned int>(apcOutMeshes.size());
delete[] pScene->mMeshes;
pScene->mMeshes = npp;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
@ -418,12 +437,12 @@ void PretransformVertices::Execute(aiScene *pScene) {
if (!pScene->mNumMeshes) if (!pScene->mNumMeshes)
return; return;
const unsigned int iOldMeshes = pScene->mNumMeshes; const unsigned int oldMeshes = pScene->mNumMeshes;
const unsigned int iOldAnimationChannels = pScene->mNumAnimations; const unsigned int oldAnimationChannels = pScene->mNumAnimations;
const unsigned int iOldNodes = CountNodes(pScene->mRootNode); const unsigned int oldNodes = CountNodes(pScene->mRootNode);
if (configTransform) { if (mConfigTransform) {
pScene->mRootNode->mTransformation = configTransformation * pScene->mRootNode->mTransformation; pScene->mRootNode->mTransformation = mConfigTransformation * pScene->mRootNode->mTransformation;
} }
// first compute absolute transformation matrices for all nodes // 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 // we go on and transform all meshes, if one is referenced by nodes
// with different absolute transformations a depth copy of the mesh // with different absolute transformations a depth copy of the mesh
// is required. // is required.
if (configKeepHierarchy) { if (mConfigKeepHierarchy) {
// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode); BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode);
// ... if new meshes have been generated, append them to the end of the scene // ... if new meshes have been generated, append them to the end of the scene
if (apcOutMeshes.size() > 0) { appendNewMeshesToScene(pScene, apcOutMeshes);
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<unsigned int>(apcOutMeshes.size());
delete[] pScene->mMeshes;
pScene->mMeshes = npp;
}
// now iterate through all meshes and transform them to world-space // now iterate through all meshes and transform them to world-space
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
@ -488,34 +498,35 @@ void PretransformVertices::Execute(aiScene *pScene) {
aiVFormats.sort(); aiVFormats.sort();
aiVFormats.unique(); aiVFormats.unique();
for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) { for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) {
unsigned int iVertices = 0; unsigned int numVertices = 0u;
unsigned int iFaces = 0; unsigned int numFaces = 0u;
CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices); CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &numFaces, &numVertices);
if (0 != iFaces && 0 != iVertices) { if (0 != numFaces && 0 != numVertices) {
apcOutMeshes.push_back(new aiMesh()); apcOutMeshes.push_back(new aiMesh());
aiMesh *pcMesh = apcOutMeshes.back(); aiMesh *pcMesh = apcOutMeshes.back();
pcMesh->mNumFaces = iFaces; pcMesh->mNumFaces = numFaces;
pcMesh->mNumVertices = iVertices; pcMesh->mNumVertices = numVertices;
pcMesh->mFaces = new aiFace[iFaces]; pcMesh->mFaces = new aiFace[numFaces];
pcMesh->mVertices = new aiVector3D[iVertices]; pcMesh->mVertices = new aiVector3D[numVertices];
pcMesh->mMaterialIndex = i; pcMesh->mMaterialIndex = i;
if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices]; if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[numVertices];
if ((*j) & 0x4) { if ((*j) & 0x4) {
pcMesh->mTangents = new aiVector3D[iVertices]; pcMesh->mTangents = new aiVector3D[numVertices];
pcMesh->mBitangents = new aiVector3D[iVertices]; pcMesh->mBitangents = new aiVector3D[numVertices];
} }
iFaces = 0; numFaces = 0;
while ((*j) & (0x100 << iFaces)) { while ((*j) & (0x100 << numFaces)) {
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; pcMesh->mTextureCoords[numFaces] = new aiVector3D[numVertices];
if ((*j) & (0x10000 << iFaces)) if ((*j) & (0x10000 << numFaces)) {
pcMesh->mNumUVComponents[iFaces] = 3; pcMesh->mNumUVComponents[numFaces] = 3;
else } else {
pcMesh->mNumUVComponents[iFaces] = 2; pcMesh->mNumUVComponents[numFaces] = 2;
iFaces++;
} }
iFaces = 0; ++numFaces;
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 ... // fill the mesh ...
unsigned int aiTemp[2] = { 0, 0 }; unsigned int aiTemp[2] = { 0, 0 };
@ -593,7 +604,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp; l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
} }
if (!configKeepHierarchy) { if (!mConfigKeepHierarchy) {
// now delete all nodes in the scene and build a new // now delete all nodes in the scene and build a new
// flat node graph with a root node and some level 1 children // flat node graph with a root node and some level 1 children
@ -644,7 +655,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
MakeIdentityTransform(pScene->mRootNode); MakeIdentityTransform(pScene->mRootNode);
} }
if (configNormalize) { if (mConfigNormalize) {
// compute the boundary of all meshes // compute the boundary of all meshes
aiVector3D min, max; aiVector3D min, max;
MinMaxChooser<aiVector3D>()(min, max); MinMaxChooser<aiVector3D>()(min, max);
@ -674,9 +685,9 @@ void PretransformVertices::Execute(aiScene *pScene) {
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); 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)"); CountNodes(pScene->mRootNode), " output nodes)");
ASSIMP_LOG_INFO("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras."); 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, ")");
} }
} }

View File

@ -90,7 +90,7 @@ public:
* @param keep true for keep configuration. * @param keep true for keep configuration.
*/ */
void KeepHierarchy(bool keep) { void KeepHierarchy(bool keep) {
configKeepHierarchy = keep; mConfigKeepHierarchy = keep;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -98,7 +98,7 @@ public:
* @return ... * @return ...
*/ */
bool IsHierarchyKept() const { bool IsHierarchyKept() const {
return configKeepHierarchy; return mConfigKeepHierarchy;
} }
private: private:
@ -108,7 +108,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // 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 // 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 // Get a list of all vertex formats that occur for a given material
// The output list contains duplicate elements // The output list contains duplicate elements
void GetVFormatList(const aiScene *pcScene, unsigned int iMat, /*void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int> &aiOut) const; std::list<unsigned int> &aiOut) const;*/
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
@ -156,10 +156,10 @@ private:
void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const; void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const;
//! Configuration option: keep scene hierarchy as long as possible //! Configuration option: keep scene hierarchy as long as possible
bool configKeepHierarchy; bool mConfigKeepHierarchy;
bool configNormalize; bool mConfigNormalize;
bool configTransform; bool mConfigTransform;
aiMatrix4x4 configTransformation; aiMatrix4x4 mConfigTransformation;
bool mConfigPointCloud; bool mConfigPointCloud;
}; };

View File

@ -175,10 +175,9 @@ unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) {
// tangents and bitangents // tangents and bitangents
if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4; if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4;
#ifdef BOOST_STATIC_ASSERT
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
#endif
// texture coordinates // texture coordinates
unsigned int p = 0; unsigned int p = 0;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 // internal headers
#include "RemoveRedundantMaterials.h" #include "RemoveRedundantMaterials.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include "ProcessHelper.h" #include "ProcessHelper.h"
@ -57,35 +54,28 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
: mConfigFixedMaterials() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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; return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup import properties // Setup import properties
void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) {
{
// Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
mConfigFixedMaterials = pImp->GetPropertyString(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. // 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"); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
unsigned int redundantRemoved = 0, unreferencedRemoved = 0; unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
if (pScene->mNumMaterials) if (pScene->mNumMaterials) {
{
// Find out which materials are referenced by meshes // Find out which materials are referenced by meshes
std::vector<bool> abReferenced(pScene->mNumMaterials,false); std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i) 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 // we do already have a specific hash. This allows us to
// determine which materials are identical. // determine which materials are identical.
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; 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. // No mesh is referencing this material, remove it.
if (!abReferenced[i]) { if (!abReferenced[i]) {
++unreferencedRemoved; ++unreferencedRemoved;
@ -147,8 +136,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
// Check all previously mapped materials for a matching hash. // 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. // 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]); 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]) { if (abReferenced[a] && me == aiHashes[a]) {
++redundantRemoved; ++redundantRemoved;
me = 0; me = 0;
@ -205,12 +193,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
delete[] aiHashes; delete[] aiHashes;
delete[] aiMappingTable; delete[] aiMappingTable;
} }
if (redundantRemoved == 0 && unreferencedRemoved == 0) if (redundantRemoved == 0 && unreferencedRemoved == 0) {
{
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
} } else {
else
{
ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ", ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
unreferencedRemoved, " unused materials."); unreferencedRemoved, " unused materials.");
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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; 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<aiNode*>& childsOfParent,bool root)
{
bool b = false;
std::list<aiNode*> 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<aiNode*>::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. // Executes the post processing step on the given imported data.
void RemoveVCProcess::Execute(aiScene *pScene) { void RemoveVCProcess::Execute(aiScene *pScene) {

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -140,7 +139,7 @@ void ScaleProcess::Execute( aiScene* pScene ) {
aiMatrix4x4 scaling; aiMatrix4x4 scaling;
aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); aiMatrix4x4::Scaling( aiVector3D(scale), scaling );
aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); const aiMatrix4x4 RotMatrix = aiMatrix4x4(rotation.GetMatrix());
bone->mOffsetMatrix = translation * RotMatrix * scaling; bone->mOffsetMatrix = translation * RotMatrix * scaling;
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 // Constructor to be privately used by Importer
SortByPTypeProcess::SortByPTypeProcess() : SortByPTypeProcess::SortByPTypeProcess() : mConfigRemoveMeshes(0) {}
mConfigRemoveMeshes(0) {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
@ -104,9 +99,10 @@ void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node
} }
// call all subnodes recursively // 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]); UpdateNodes(replaceMeshIndex, node->mChildren[m]);
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
@ -155,7 +151,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
if (1 == num) { if (1 == num) {
if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
*meshIdx = static_cast<unsigned int>(outMeshes.size()); *meshIdx = static_cast<unsigned int>(outMeshes.size());
outMeshes.push_back(mesh); outMeshes.emplace_back(mesh);
} else { } else {
delete mesh; delete mesh;
pScene->mMeshes[i] = nullptr; pScene->mMeshes[i] = nullptr;
@ -311,21 +307,23 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
if (vert) { if (vert) {
*vert++ = mesh->mVertices[idx]; *vert++ = mesh->mVertices[idx];
//mesh->mVertices[idx].x = get_qnan();
} }
if (nor) *nor++ = mesh->mNormals[idx]; if (nor)
*nor++ = mesh->mNormals[idx];
if (tan) { if (tan) {
*tan++ = mesh->mTangents[idx]; *tan++ = mesh->mTangents[idx];
*bit++ = mesh->mBitangents[idx]; *bit++ = mesh->mBitangents[idx];
} }
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) { 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]; *uv[pp]++ = mesh->mTextureCoords[pp][idx];
} }
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) { 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]; *cols[pp]++ = mesh->mColors[pp][idx];
} }
@ -351,7 +349,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
} }
} }
if (pp == mesh->mNumAnimMeshes) if (pp == mesh->mNumAnimMeshes)
amIdx++; ++amIdx;
in.mIndices[q] = outIdx++; in.mIndices[q] = outIdx++;
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -58,9 +57,7 @@ using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor // Constructor
SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) { SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {}
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag. // Returns whether the processing step is present in the given flag.
@ -166,7 +163,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
unsigned int numBones = 0; unsigned int numBones = 0;
std::vector<bool> isBoneUsed( pMesh->mNumBones, false); std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
// indices of the faces which are going to go into this submesh // indices of the faces which are going to go into this submesh
std::vector<unsigned int> subMeshFaces; IndexArray subMeshFaces;
subMeshFaces.reserve( pMesh->mNumFaces); subMeshFaces.reserve( pMesh->mNumFaces);
// accumulated vertex count of all the faces in this submesh // accumulated vertex count of all the faces in this submesh
unsigned int numSubMeshVertices = 0; unsigned int numSubMeshVertices = 0;
@ -202,7 +199,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) { for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) {
if (!isBoneUsed[*it]) { if (!isBoneUsed[*it]) {
isBoneUsed[*it] = true; isBoneUsed[*it] = true;
numBones++; ++numBones;
} }
} }
@ -212,18 +209,17 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
// remember that this face is handled // remember that this face is handled
isFaceHandled[a] = true; isFaceHandled[a] = true;
numFacesHandled++; ++numFacesHandled;
} }
// create a new mesh to hold this subset of the source mesh // create a new mesh to hold this subset of the source mesh
aiMesh* newMesh = new aiMesh; aiMesh* newMesh = new aiMesh;
if( pMesh->mName.length > 0 ) if( pMesh->mName.length > 0 ) {
{
newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size()); newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
} }
newMesh->mMaterialIndex = pMesh->mMaterialIndex; newMesh->mMaterialIndex = pMesh->mMaterialIndex;
newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; 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 // create all the arrays for this mesh if the old mesh contained them
newMesh->mNumVertices = numSubMeshVertices; newMesh->mNumVertices = numSubMeshVertices;
@ -251,7 +247,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
// and copy over the data, generating faces with linear indices along the way // and copy over the data, generating faces with linear indices along the way
newMesh->mFaces = new aiFace[subMeshFaces.size()]; newMesh->mFaces = new aiFace[subMeshFaces.size()];
unsigned int nvi = 0; // next vertex index unsigned int nvi = 0; // next vertex index
std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh IndexArray previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh
for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) { for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) {
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
aiFace& dstFace = newMesh->mFaces[a]; aiFace& dstFace = newMesh->mFaces[a];
@ -399,10 +395,10 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const { void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const {
// rebuild the node's mesh index list // rebuild the node's mesh index list
if( pNode->mNumMeshes == 0 ) { if( pNode->mNumMeshes == 0 ) {
std::vector<unsigned int> newMeshList; IndexArray newMeshList;
for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) { for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) {
unsigned int srcIndex = pNode->mMeshes[a]; unsigned int srcIndex = pNode->mMeshes[a];
const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex]; const IndexArray& replaceMeshes = mSubMeshIndices[srcIndex];
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
} }

View File

@ -76,6 +76,10 @@ public:
/// basing on the Importer's configuration property list. /// basing on the Importer's configuration property list.
virtual void SetupProperties(const Importer* pImp) override; 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: protected:
/// Executes the post processing step on the given imported data. /// Executes the post processing step on the given imported data.
/// At the moment a process is not supposed to fail. /// 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 /// Recursively updates the node's mesh list to account for the changed mesh list
void UpdateNode( aiNode* pNode) const; void UpdateNode( aiNode* pNode) const;
public: private:
/// Max bone count. Splitting occurs if a mesh has more than that number of bones. /// Max bone count. Splitting occurs if a mesh has more than that number of bones.
size_t mMaxBoneCount; size_t mMaxBoneCount;
/// Per mesh index: Array of indices of the new submeshes. /// Per mesh index: Array of indices of the new submeshes.
std::vector< std::vector<unsigned int> > mSubMeshIndices; using IndexArray = std::vector<unsigned int>;
std::vector<IndexArray> mSubMeshIndices;
}; };
inline size_t SplitByBoneCountProcess::getMaxNumberOfBones() const {
return mMaxBoneCount;
}
} // end of namespace Assimp } // end of namespace Assimp
#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC #endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 // internal headers of the post-processing framework
#include "SplitLargeMeshes.h" #include "SplitLargeMeshes.h"
@ -75,7 +72,10 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
this->SplitMesh(a, pScene->mMeshes[a],avList); this->SplitMesh(a, pScene->mMeshes[a],avList);
} }
if (avList.size() != pScene->mNumMeshes) { 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 // it seems something has been split. rebuild the mesh list
delete[] pScene->mMeshes; delete[] pScene->mMeshes;
pScene->mNumMeshes = (unsigned int)avList.size(); pScene->mNumMeshes = (unsigned int)avList.size();
@ -88,9 +88,6 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
// now we need to update all nodes // now we need to update all nodes
this->UpdateNode(pScene->mRootNode,avList); this->UpdateNode(pScene->mRootNode,avList);
ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
} else {
ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -102,8 +99,7 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Update a node after some meshes have been split // Update a node after some meshes have been split
void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
// for every index in out list build a new entry // for every index in out list build a new entry
std::vector<unsigned int> aiEntries; std::vector<unsigned int> aiEntries;
aiEntries.reserve(pcNode->mNumMeshes + 1); aiEntries.reserve(pcNode->mNumMeshes + 1);

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 */ /** @file A helper class that processes texture transformations */
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -494,8 +491,9 @@ void TextureTransformStep::Execute( aiScene* pScene) {
ai_assert(nullptr != src); ai_assert(nullptr != src);
// Copy the data to the destination array // Copy the data to the destination array
if (dest != src) if (dest != src) {
::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
}
end = dest + mesh->mNumVertices; end = dest + mesh->mNumVertices;

View File

@ -158,15 +158,13 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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; return (pFlags & aiProcess_Triangulate) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // 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"); ASSIMP_LOG_DEBUG("TriangulateProcess begin");
bool bHas = false; bool bHas = false;
@ -187,8 +185,7 @@ void TriangulateProcess::Execute( aiScene* pScene)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Triangulates the given mesh. // 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 // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
if (!pMesh->mPrimitiveTypes) { if (!pMesh->mPrimitiveTypes) {
bool bNeed = false; bool bNeed = false;
@ -218,8 +215,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
if( face.mNumIndices <= 3) { if( face.mNumIndices <= 3) {
numOut++; numOut++;
} } else {
else {
numOut += face.mNumIndices-2; numOut += face.mNumIndices-2;
max_out = std::max(max_out,face.mNumIndices); max_out = std::max(max_out,face.mNumIndices);
} }
@ -511,22 +507,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#endif #endif
num = 0; num = 0;
break; 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++; aiFace& nface = *curOut++;
@ -580,23 +560,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
for(aiFace* f = last_face; f != curOut; ) { for(aiFace* f = last_face; f != curOut; ) {
unsigned int* i = f->mIndices; 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[0] = idx[i[0]];
i[1] = idx[i[1]]; i[1] = idx[i[1]];
i[2] = idx[i[2]]; i[2] = idx[i[2]];

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -110,11 +108,15 @@ inline int HasNameMatch(const aiString &in, aiNode *node) {
template <typename T> template <typename T>
inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) { inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
// validate all entries // validate all entries
if (size) { if (size == 0) {
return;
}
if (!parray) { if (!parray) {
ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
firstName, secondName, size); firstName, secondName, size);
} }
for (unsigned int i = 0; i < size; ++i) { for (unsigned int i = 0; i < size; ++i) {
if (!parray[i]) { if (!parray[i]) {
ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)", ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
@ -123,14 +125,16 @@ inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const
Validate(parray[i]); Validate(parray[i]);
} }
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size, inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size,
const char *firstName, const char *secondName) { const char *firstName, const char *secondName) {
// validate all entries // validate all entries
if (size) { if (size == 0) {
return;
}
if (!parray) { if (!parray) {
ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
firstName, secondName, size); firstName, secondName, size);
@ -152,7 +156,6 @@ inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size,
} }
} }
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
@ -229,12 +232,6 @@ void ValidateDSProcess::Execute(aiScene *pScene) {
if (pScene->mNumMaterials) { if (pScene->mNumMaterials) {
DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "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) { else if (pScene->mMaterials) {
ReportError("aiScene::mMaterials is non-null although there are no materials"); 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) if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
// FIX: there are many 3ds files with invalid FOVs. No reason to // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate.
// reject them at all ... a warning is appropriate.
if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV); ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
} }
@ -361,15 +357,6 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh) {
if (face.mIndices[a] >= pMesh->mNumVertices) { if (face.mIndices[a] >= pMesh->mNumVertices) {
ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a); 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; abRefList[face.mIndices[a]] = true;
} }
} }
@ -465,7 +452,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float
this->Validate(&pBone->mName); this->Validate(&pBone->mName);
if (!pBone->mNumWeights) { if (!pBone->mNumWeights) {
//ReportError("aiBone::mNumWeights is zero"); ReportWarning("aiBone::mNumWeights is zero");
} }
// check whether all vertices affected by this bone are valid // check whether all vertices affected by this bone are valid

View File

@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <assimp/cimport.h> #include <assimp/cimport.h>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
@ -53,6 +54,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
const aiScene *sc = importer.ReadFileFromMemory(data, dataSize, const aiScene *sc = importer.ReadFileFromMemory(data, dataSize,
aiProcessPreset_TargetRealtime_Quality, nullptr ); aiProcessPreset_TargetRealtime_Quality, nullptr );
if (sc == nullptr) {
return 0;
}
Exporter exporter;
exporter.ExportToBlob(sc, "fbx");
aiDetachLogStream(&stream); aiDetachLogStream(&stream);
return 0; return 0;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -68,8 +66,7 @@ namespace Assimp {
*/ */
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
template <bool SwapEndianess = false, bool RuntimeSwitch = false> template <bool SwapEndianess = false, bool RuntimeSwitch = false>
class StreamWriter class StreamWriter {
{
enum { enum {
INITIAL_CAPACITY = 1024 INITIAL_CAPACITY = 1024
}; };

View File

@ -97,15 +97,21 @@ namespace Assimp {
* to *all* vertex components equally. This is useful for stuff like interpolation * 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. */ * 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&,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 / (const Vertex&,ai_real); friend Vertex operator / (const Vertex&,ai_real);
friend Vertex operator * (ai_real, const Vertex&); friend Vertex operator * (ai_real, const Vertex&);
public: aiVector3D position;
Vertex() {} aiVector3D normal;
aiVector3D tangent, bitangent;
aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
Vertex() = default;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Extract a particular vertex from a mesh and interleave all components */ /** Extract a particular vertex from a mesh and interleave all components */
@ -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 { void SortBack(aiMesh* out, unsigned int idx) const {
ai_assert(idx<out->mNumVertices); ai_assert(idx<out->mNumVertices);
out->mVertices[idx] = position; out->mVertices[idx] = position;
@ -204,7 +210,7 @@ public:
private: private:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Construct from two operands and a binary operation to combine them */ /// Construct from two operands and a binary operation to combine them
template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) { template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) {
// this is a heavy task for the compiler to optimize ... *pray* // this is a heavy task for the compiler to optimize ... *pray*
@ -224,7 +230,7 @@ private:
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** This time binary arithmetic of v0 with a floating-point number */ /// This time binary arithmetic of v0 with a floating-point number
template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, ai_real f) { template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, ai_real f) {
// this is a heavy task for the compiler to optimize ... *pray* // this is a heavy task for the compiler to optimize ... *pray*
@ -262,15 +268,6 @@ private:
} }
return res; return res;
} }
public:
aiVector3D position;
aiVector3D normal;
aiVector3D tangent, bitangent;
aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -1065,6 +1065,17 @@ enum aiComponent
*/ */
#define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS" #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. * @brief Specifies the blob name, assimp uses for exporting.
* *

View File

@ -289,7 +289,11 @@ typedef unsigned int ai_uint;
#define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795) #define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795)
/* Numerical limits */ /* Numerical limits */
static const ai_real ai_epsilon = (ai_real) 1e-6; #ifdef __cplusplus
constexpr ai_real ai_epsilon = (ai_real) 1e-6;
#else
const ai_real ai_epsilon = (ai_real) 1e-6;
#endif
/* Support for big-endian builds */ /* Support for big-endian builds */
#if defined(__BYTE_ORDER__) #if defined(__BYTE_ORDER__)

View File

@ -102,6 +102,10 @@ SET( COMMON
unit/Common/utBaseProcess.cpp unit/Common/utBaseProcess.cpp
) )
SET(Geometry
unit/Geometry/utGeometryUtils.cpp
)
SET( IMPORTERS SET( IMPORTERS
unit/ImportExport/Assxml/utAssxmlImportExport.cpp unit/ImportExport/Assxml/utAssxmlImportExport.cpp
unit/utLWSImportExport.cpp unit/utLWSImportExport.cpp
@ -202,6 +206,7 @@ SET( POST_PROCESSES
SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c ) SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c )
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
SOURCE_GROUP( UnitTests\\GeometryTools FILES ${Geometry} )
SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} ) SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} )
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
@ -213,6 +218,7 @@ add_executable( unit
../code/Common/Version.cpp ../code/Common/Version.cpp
../code/Common/Base64.cpp ../code/Common/Base64.cpp
${COMMON} ${COMMON}
${Geometry}
${IMPORTERS} ${IMPORTERS}
${MATERIAL} ${MATERIAL}
${MATH} ${MATH}

View File

@ -0,0 +1,68 @@
/*
---------------------------------------------------------------------------
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 "UnitTestPCH.h"
#include "Geometry/GeometryUtils.h"
using namespace Assimp;
class utGeometryUtils : public ::testing::Test {
protected:
void SetUp() override {
}
void TearDown() override {
}
};
static constexpr size_t NumVectors = 100;
TEST_F(utGeometryUtils, normalizeVectorArrayTest) {
aiVector3D *inNormals = new aiVector3D[NumVectors];
for (uint32_t i=0; i<NumVectors; ++i){
inNormals[i].x = static_cast<ai_real>(i);
inNormals[i].y = static_cast<ai_real>(i);
inNormals[i].z = static_cast<ai_real>(i);
}
aiVector3D *outNormals = new aiVector3D[NumVectors];
GeometryUtils::normalizeVectorArray(inNormals, outNormals, NumVectors);
delete[] outNormals;
delete[] inNormals;
}

View File

@ -1,38 +1,71 @@
#include "UnitTestPCH.h" /*
---------------------------------------------------------------------------
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 "UnitTestPCH.h"
#include <assimp/cexport.h> #include <assimp/cexport.h>
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_EXPORT
class ExporterTest : public ::testing::Test { class ExporterTest : public ::testing::Test {
public: public:
void SetUp() override {
virtual void SetUp()
{
ex = new Assimp::Exporter(); ex = new Assimp::Exporter();
im = new Assimp::Importer(); im = new Assimp::Importer();
pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/X/test.x", aiProcess_ValidateDataStructure); pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/X/test.x", aiProcess_ValidateDataStructure);
} }
virtual void TearDown() void TearDown() override {
{
delete ex; delete ex;
delete im; delete im;
} }
protected: protected:
const aiScene* pTest; const aiScene* pTest;
Assimp::Exporter* ex; Assimp::Exporter* ex;
Assimp::Importer* im; Assimp::Importer* im;
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TEST_F(ExporterTest, testExportToFile) TEST_F(ExporterTest, testExportToFile) {
{
const char* file = "unittest_output.dae"; const char* file = "unittest_output.dae";
EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file)); EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file));
@ -41,8 +74,7 @@ TEST_F(ExporterTest, testExportToFile)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TEST_F(ExporterTest, testExportToBlob) TEST_F(ExporterTest, testExportToBlob) {
{
const aiExportDataBlob* blob = ex->ExportToBlob(pTest,"collada"); const aiExportDataBlob* blob = ex->ExportToBlob(pTest,"collada");
ASSERT_TRUE(blob); ASSERT_TRUE(blob);
EXPECT_TRUE(blob->data); EXPECT_TRUE(blob->data);
@ -56,8 +88,7 @@ TEST_F(ExporterTest, testExportToBlob)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TEST_F(ExporterTest, testCppExportInterface) TEST_F(ExporterTest, testCppExportInterface) {
{
EXPECT_TRUE(ex->GetExportFormatCount() > 0); EXPECT_TRUE(ex->GetExportFormatCount() > 0);
for(size_t i = 0; i < ex->GetExportFormatCount(); ++i) { for(size_t i = 0; i < ex->GetExportFormatCount(); ++i) {
const aiExportFormatDesc* const desc = ex->GetExportFormatDescription(i); const aiExportFormatDesc* const desc = ex->GetExportFormatDescription(i);
@ -71,14 +102,13 @@ TEST_F(ExporterTest, testCppExportInterface)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TEST_F(ExporterTest, testCExportInterface) TEST_F(ExporterTest, testCExportInterface) {
{
EXPECT_TRUE(aiGetExportFormatCount() > 0); EXPECT_TRUE(aiGetExportFormatCount() > 0);
for(size_t i = 0; i < aiGetExportFormatCount(); ++i) { for(size_t i = 0; i < aiGetExportFormatCount(); ++i) {
const aiExportFormatDesc* const desc = aiGetExportFormatDescription(i); const aiExportFormatDesc* const desc = aiGetExportFormatDescription(i);
EXPECT_TRUE(desc); EXPECT_TRUE(desc);
// rest has already been validated by testCppExportInterface
} }
} }
#endif #endif

View File

@ -219,9 +219,15 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf",
aiProcess_ValidateDataStructure); aiProcess_ValidateDataStructure);
EXPECT_NE(nullptr, scene); EXPECT_NE(nullptr, scene);
// Export
// Export with specular glossiness disabled
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb")); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb"));
// Export with specular glossiness enabled
ExportProperties props;
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 // And re-import
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true)); EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true));
} }