Compare commits

..

13 Commits

Author SHA1 Message Date
Pichas f4c7606faf
fix no_valid_proc (#5774)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-16 09:17:22 +02:00
Kim Kulling 66187a77cf
Update dll_symbol.h (#5781)
- fix compile switch
- closes https://github.com/assimp/assimp/issues/5777
2024-09-15 20:44:32 +02:00
PatrickD 5c7acc968b
Fix naming in aiMaterial comment (#5780) 2024-09-13 14:24:09 +02:00
Lux f81ea6986c
Restored absolute transform calculation due to https://github.com/assimp/assimp/pull/5349 which requires this now. (#5751) 2024-09-11 10:11:15 +02:00
dataisland ab12e8d8ba
Fix stack overflow (#5764)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-10 23:15:31 +02:00
dataisland 3bd98611d7
Fix buffer overflow in MD3Loader (#5763)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-10 22:10:36 +02:00
dataisland d468e633b1
Fix invalid access (#5765)
* Fix invalid access

* Update SortByPTypeProcess.cpp

Some smaller refactorings.

* Update SortByPTypeProcess.cpp

Small refactorings.

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-10 09:12:01 +02:00
Kim Kulling 4024726eca
Fix leak (#5762)
* Fix leak

* Update utLogger.cpp
2024-09-07 21:02:34 +02:00
Kim Kulling cd0ef869e3
Kimkulling/mark blender versions as not supported (#5370)
* Cleanup defs + add deprecated macro

* Remove empty line

* Remove dead code

---------

Co-authored-by: Kim Kulling <kim.kulling@draeger.com>
2024-09-05 23:40:19 +02:00
RichardTea ed3fccd5db
Add option to ignore FBX custom axes (#5754)
AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION
Default false

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-05 21:03:26 +02:00
Matthias Möller ff2dc2fb2e
Prevents PLY from parsing duplicate properties (#5743)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2024-09-04 11:54:24 +02:00
Tobias Rittig, Ph.D. f69e55058d
Allow usage of pugixml from a superproject (#5752)
When using CMake subprojects with an existing build of pugixml
this prevents Assimp from using its own copy.
2024-09-03 21:45:30 +02:00
RichardTea c1ffbfec06
Zero-length mChildren arrays should be nullptr (#5749)
- Children: Don't allocate a zero-length array
- aiNode::mChildren should be left nullptr instead.
2024-09-03 10:26:27 +02:00
25 changed files with 413 additions and 145 deletions

View File

@ -643,11 +643,17 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
}
// Allocate storage for children
pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
pcOut->mNumChildren = size;
if (size == 0) {
return;
}
pcOut->mChildren = new aiNode *[pcIn->mChildren.size()];
// Recursively process all children
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
for (unsigned int i = 0; i < size; ++i) {
pcOut->mChildren[i] = new aiNode();
pcOut->mChildren[i]->mParent = pcOut;

View File

@ -372,9 +372,11 @@ aiNode *COBImporter::BuildNodes(const Node &root, const Scene &scin, aiScene *fi
}
// add children recursively
nd->mChildren = new aiNode *[root.temp_children.size()]();
for (const Node *n : root.temp_children) {
(nd->mChildren[nd->mNumChildren++] = BuildNodes(*n, scin, fill))->mParent = nd;
if (!root.temp_children.empty()) {
nd->mChildren = new aiNode *[root.temp_children.size()]();
for (const Node *n : root.temp_children) {
(nd->mChildren[nd->mNumChildren++] = BuildNodes(*n, scin, fill))->mParent = nd;
}
}
return nd;

View File

@ -181,7 +181,9 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
if (out->mNumMeshes == 0) {
out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} else {
correctRootTransform(mSceneOut);
// Apply the FBX axis metadata unless requested not to
if (!doc.Settings().ignoreUpDirection)
correctRootTransform(mSceneOut);
}
}
@ -310,6 +312,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
child->mParent = last_parent;
last_parent = child.mNode;
new_abs_transform *= child->mTransformation;
}
// attach geometry
@ -332,6 +336,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
postnode->mParent = last_parent;
last_parent = postnode.mNode;
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
@ -357,12 +363,12 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
if (nodes.empty()) {
parent->mNumChildren = 0;
parent->mChildren = nullptr;
}
parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
for (unsigned int i = 0; i < nodes.size(); ++i) {
parent->mChildren[i] = nodes[i].mOwnership.release();
} else {
parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
for (unsigned int i = 0; i < nodes.size(); ++i) {
parent->mChildren[i] = nodes[i].mOwnership.release();
}
}
}

View File

@ -156,6 +156,9 @@ struct ImportSettings {
/** Set to true to perform a conversion from cm to meter after the import
*/
bool convertToMeters;
// Set to true to ignore the axis configuration in the file
bool ignoreUpDirection = false;
};
} // namespace FBX

View File

@ -117,6 +117,7 @@ void FBXImporter::SetupProperties(const Importer *pImp) {
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.ignoreUpDirection = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION, false);
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
}

View File

@ -78,7 +78,15 @@ static constexpr aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Recursive parsing of LWS files
void LWS::Element::Parse(const char *&buffer, const char *end) {
namespace {
constexpr int MAX_DEPTH = 1000; // Define the maximum depth allowed
}
void LWS::Element::Parse(const char *&buffer, const char *end, int depth) {
if (depth > MAX_DEPTH) {
throw std::runtime_error("Maximum recursion depth exceeded in LWS::Element::Parse");
}
for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
// begin of a new element with children
@ -121,7 +129,7 @@ void LWS::Element::Parse(const char *&buffer, const char *end) {
// parse more elements recursively
if (sub) {
children.back().Parse(buffer, end);
children.back().Parse(buffer, end, depth + 1);
}
}
}

View File

@ -76,7 +76,7 @@ public:
std::list<Element> children;
//! Recursive parsing function
void Parse(const char *&buffer, const char *end);
void Parse(const char *&buffer, const char *end, int depth = 0);
};
#define AI_LWS_MASK (0xffffffff >> 4u)

View File

@ -724,6 +724,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
std::vector<unsigned char> mBuffer2(fileSize);
file->Read(&mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0];
const unsigned char* bufferEnd = mBuffer + fileSize;
pcHeader = (BE_NCONST MD3::Header *)mBuffer;
@ -749,9 +750,15 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Navigate to the list of surfaces
BE_NCONST MD3::Surface *pcSurfaces = (BE_NCONST MD3::Surface *)(mBuffer + pcHeader->OFS_SURFACES);
if ((const unsigned char*)pcSurfaces + sizeof(MD3::Surface) * pcHeader->NUM_SURFACES > bufferEnd) {
throw DeadlyImportError("MD3 surface headers are outside the file");
}
// Navigate to the list of tags
BE_NCONST MD3::Tag *pcTags = (BE_NCONST MD3::Tag *)(mBuffer + pcHeader->OFS_TAGS);
if ((const unsigned char*)pcTags + sizeof(MD3::Tag) * pcHeader->NUM_TAGS > bufferEnd) {
throw DeadlyImportError("MD3 tags are outside the file");
}
// Allocate output storage
pScene->mNumMeshes = pcHeader->NUM_SURFACES;
@ -1026,6 +1033,10 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
for (unsigned int i = 0; i < pcHeader->NUM_TAGS; ++i, ++pcTags) {
aiNode *nd = pScene->mRootNode->mChildren[i] = new aiNode();
if ((const unsigned char*)pcTags + sizeof(MD3::Tag) > bufferEnd) {
throw DeadlyImportError("MD3 tag is outside the file");
}
nd->mName.Set((const char *)pcTags->NAME);
nd->mParent = pScene->mRootNode;

View File

@ -48,10 +48,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ByteSwapper.h>
#include <assimp/fast_atof.h>
#include <assimp/DefaultLogger.hpp>
#include <unordered_set>
#include <utility>
namespace Assimp {
std::string to_string(EElementSemantic e) {
switch (e) {
case EEST_Vertex:
return std::string{ "vertex" };
case EEST_TriStrip:
return std::string{ "tristrips" };
case EEST_Edge:
return std::string{ "edge" };
case EEST_Material:
return std::string{ "material" };
case EEST_TextureFile:
return std::string{ "TextureFile" };
default:
return std::string{ "invalid" };
}
}
// ------------------------------------------------------------------------------------------------
PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
ai_assert(!buffer.empty());
@ -281,6 +300,8 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
// if the exact semantic can't be determined, just store
// the original string identifier
pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
auto pos = pOut->szName.find_last_of(' ');
pOut->szName.erase(pos, pOut->szName.size());
}
if (!PLY::DOM::SkipSpaces(buffer))
@ -413,6 +434,7 @@ bool PLY::DOM::SkipComments(std::vector<char> buffer) {
bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool isBinary) {
ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseHeader() begin");
std::unordered_set<std::string> definedAlElements;
// parse all elements
while (!buffer.empty()) {
// skip all comments
@ -421,6 +443,13 @@ bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char>
PLY::Element out;
if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) {
// add the element to the list of elements
const auto propertyName = (out.szName.empty()) ? to_string(out.eSemantic) : out.szName;
auto alreadyDefined = definedAlElements.find(propertyName);
if (alreadyDefined != definedAlElements.end()) {
throw DeadlyImportError("Property '" + propertyName + "' in header already defined ");
}
definedAlElements.insert(propertyName);
alElements.push_back(out);
} else if (TokenMatch(buffer, "end_header", 10)) {
// we have reached the end of the header

View File

@ -400,8 +400,12 @@ void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent) {
}
}
// nothing to do
if (pcNode->mNumChildren == 0)
return;
// now allocate the output array
pcNode->mChildren = new aiNode*[pcNode->mNumChildren];
pcNode->mChildren = new aiNode *[pcNode->mNumChildren];
// and fill all subnodes
unsigned int qq( 0 );

View File

@ -1053,7 +1053,7 @@ ENDIF() # IF (ASSIMP_BUILD_USD_IMPORTER)
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(pugixml)
find_package(pugixml CONFIG REQUIRED)
ELSE()
ELSEIF(NOT TARGET pugixml::pugixml)
SET( Pugixml_SRCS
../contrib/pugixml/src/pugiconfig.hpp
../contrib/pugixml/src/pugixml.hpp
@ -1396,6 +1396,7 @@ IF (ASSIMP_WARNINGS_AS_ERRORS)
-Wno-unused-template
-Wno-undefined-func-template
-Wno-declaration-after-statement
-Wno-deprecated-declarations
)
ELSE()
TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX)
@ -1417,9 +1418,7 @@ TARGET_INCLUDE_DIRECTORIES ( assimp PUBLIC
IF(ASSIMP_HUNTER_ENABLED)
TARGET_LINK_LIBRARIES(assimp
PUBLIC
#polyclipping::polyclipping
openddlparser::openddl_parser
#poly2tri::poly2tri
minizip::minizip
ZLIB::zlib
RapidJSON::rapidjson
@ -1439,6 +1438,9 @@ ELSE()
if (ASSIMP_BUILD_DRACO)
target_link_libraries(assimp ${draco_LIBRARIES})
endif()
if(TARGET pugixml::pugixml)
target_link_libraries(assimp pugixml::pugixml)
endif()
ENDIF()
if(ASSIMP_ANDROID_JNIIOSYSTEM)

View File

@ -359,20 +359,25 @@ void CallbackToLogRedirector(const char *msg, char *dt) {
s->write(msg);
}
static LogStream *DefaultStream = nullptr;
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream, const char *file) {
aiLogStream sout;
ASSIMP_BEGIN_EXCEPTION_REGION();
LogStream *stream = LogStream::createDefaultStream(pStream, file);
if (!stream) {
if (DefaultStream == nullptr) {
DefaultStream = LogStream::createDefaultStream(pStream, file);
}
if (!DefaultStream) {
sout.callback = nullptr;
sout.user = nullptr;
} else {
sout.callback = &CallbackToLogRedirector;
sout.user = (char *)stream;
sout.user = (char *)DefaultStream;
}
gPredefinedStreams.push_back(stream);
gPredefinedStreams.push_back(DefaultStream);
ASSIMP_END_EXCEPTION_REGION(aiLogStream);
return sout;
}

View File

@ -848,11 +848,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
break;
}
#ifdef ASSIMP_BUILD_DEBUG
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
continue;
#endif // no validation
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
if (pimpl->bExtraVerbose) {
ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
@ -864,6 +860,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
break;
}
}
#endif // no validation
#endif // ! DEBUG
}
pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
@ -939,6 +936,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
profiler->EndRegion( "postprocess" );
}
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
if ( pimpl->bExtraVerbose || requestValidation ) {
ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" );
@ -949,6 +947,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" );
}
}
#endif // no validation
// clear any data allocated by post-process steps
pimpl->mPPShared->Clean();

View File

@ -65,37 +65,47 @@ void SortByPTypeProcess::SetupProperties(const Importer *pImp) {
mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0);
}
// ------------------------------------------------------------------------------------------------
static void clearMeshesInNode(aiNode *node) {
delete[] node->mMeshes;
node->mNumMeshes = 0;
node->mMeshes = nullptr;
}
// ------------------------------------------------------------------------------------------------
// Update changed meshes in all nodes
void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node) {
ai_assert(node != nullptr);
if (node->mNumMeshes) {
unsigned int newSize = 0;
for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
unsigned int add = node->mMeshes[m] << 2;
for (unsigned int i = 0; i < 4; ++i) {
if (UINT_MAX != replaceMeshIndex[add + i]) ++newSize;
}
}
if (!newSize) {
delete[] node->mMeshes;
node->mNumMeshes = 0;
node->mMeshes = nullptr;
} else {
// Try to reuse the old array if possible
unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
unsigned int add = node->mMeshes[m] << 2;
for (unsigned int i = 0; i < 4; ++i) {
if (UINT_MAX != replaceMeshIndex[add + i])
*newMeshes++ = replaceMeshIndex[add + i];
if (UINT_MAX != replaceMeshIndex[add + i]) {
++newSize;
}
}
if (newSize > node->mNumMeshes)
delete[] node->mMeshes;
node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
}
if (newSize == 0) {
clearMeshesInNode(node);
return;
}
// Try to reuse the old array if possible
unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
unsigned int add = node->mMeshes[m] << 2;
for (unsigned int i = 0; i < 4; ++i) {
if (UINT_MAX != replaceMeshIndex[add + i]) {
*newMeshes++ = replaceMeshIndex[add + i];
}
}
}
if (newSize > node->mNumMeshes) {
clearMeshesInNode(node);
}
node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
}
// call all subnodes recursively
@ -167,6 +177,10 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
// with the largest number of primitives
unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 };
aiFace *pFirstFace = mesh->mFaces;
if (pFirstFace == nullptr) {
continue;
}
aiFace *const pLastFace = pFirstFace + mesh->mNumFaces;
unsigned int numPolyVerts = 0;

View File

@ -891,6 +891,9 @@ void ValidateDSProcess::Validate(const aiNode *pNode) {
ReportError("aiNode \"%s\" child %i \"%s\" parent is someone else: \"%s\"", pNode->mName.C_Str(), i, pChild->mName.C_Str(), parentName);
}
}
} else if (pNode->mChildren) {
ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
nodeName, pNode->mNumChildren);
}
}

View File

@ -31,7 +31,7 @@
#pragma once
#if defined(_WIN32)
#if defined(_MSC_VER)
# pragma warning( disable: 4273)
# define P2T_COMPILER_DLLEXPORT __declspec(dllexport)
# define P2T_COMPILER_DLLIMPORT __declspec(dllimport)

View File

@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, nullptr);
aiAttachLogStream(&stream);
Importer importer;

View File

@ -676,6 +676,19 @@ enum aiComponent
#define AI_CONFIG_FBX_CONVERT_TO_M \
"AI_CONFIG_FBX_CONVERT_TO_M"
// ---------------------------------------------------------------------------
/** @brief Set whether the FBX importer shall ignore the provided axis configuration
*
* If this property is set to true, the axis directions provided in the FBX file
* will be ignored and the file will be loaded as is.
*
* Set to true for Assimp 5.3.x and earlier behavior
* Equivalent to AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION
* Property type: Bool. Default value: false.
*/
#define AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION \
"AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION"
// ---------------------------------------------------------------------------
/** @brief Will enable the skeleton struct to store bone data.
*

View File

@ -49,14 +49,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_DEFINES_H_INC
#ifdef __GNUC__
#pragma GCC system_header
# pragma GCC system_header
#endif
#include <assimp/config.h>
//////////////////////////////////////////////////////////////////////////
/* Define ASSIMP_BUILD_NO_XX_IMPORTER to disable a specific
* file format loader. The loader is be excluded from the
/**
* @brief Define ASSIMP_BUILD_NO_XX_IMPORTER to disable a specific file format loader.
*
* The loader is be excluded from the
* build in this case. 'XX' stands for the most common file
* extension of the file format. E.g.:
* ASSIMP_BUILD_NO_X_IMPORTER disables the X loader.
@ -76,34 +78,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////
#ifndef ASSIMP_BUILD_NO_COMPRESSED_X
#define ASSIMP_BUILD_NEED_Z_INFLATE
# define ASSIMP_BUILD_NEED_Z_INFLATE
#endif
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
#define ASSIMP_BUILD_NEED_Z_INFLATE
# define ASSIMP_BUILD_NEED_Z_INFLATE
#endif
#ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC
#define ASSIMP_BUILD_NEED_Z_INFLATE
#define ASSIMP_BUILD_NEED_UNZIP
# define ASSIMP_BUILD_NEED_Z_INFLATE
# define ASSIMP_BUILD_NEED_UNZIP
#endif
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
#define ASSIMP_BUILD_NEED_Z_INFLATE
#define ASSIMP_BUILD_NEED_UNZIP
# define ASSIMP_BUILD_NEED_Z_INFLATE
# define ASSIMP_BUILD_NEED_UNZIP
#endif
// We need those constants, workaround for any platforms where nobody defined them yet
/**
* @brief We need those constants, workaround for any platforms where nobody defined them yet.
*/
#if (!defined SIZE_MAX)
#define SIZE_MAX (~((size_t)0))
# define SIZE_MAX (~((size_t)0))
#endif
/*#if (!defined UINT_MAX)
#define UINT_MAX (~((unsigned int)0))
#endif*/
//////////////////////////////////////////////////////////////////////////
/* Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific
/** @brief Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific
*
* post processing step. This is the current list of process names ('XX'):
* CALCTANGENTS
* JOINVERTICES
@ -134,46 +135,50 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* OPTIMIZEGRAPH
* GENENTITYMESHES
* FIXTEXTUREPATHS
* GENBOUNDINGBOXES */
//////////////////////////////////////////////////////////////////////////
* GENBOUNDINGBOXES
*/
//////////////////////////////////////////////////////////////////////////
/** @brief Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library
*
* Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in
* an external DLL under Windows. Default is static linkage.
*/
//////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#undef ASSIMP_API
//////////////////////////////////////////////////////////////////////////
/* Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library */
//////////////////////////////////////////////////////////////////////////
#ifdef ASSIMP_BUILD_DLL_EXPORT
#define ASSIMP_API __declspec(dllexport)
#define ASSIMP_API_WINONLY __declspec(dllexport)
//////////////////////////////////////////////////////////////////////////
/* Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in
* an external DLL under Windows. Default is static linkage. */
//////////////////////////////////////////////////////////////////////////
#elif (defined ASSIMP_DLL)
#define ASSIMP_API __declspec(dllimport)
#define ASSIMP_API_WINONLY __declspec(dllimport)
# undef ASSIMP_API
# ifdef ASSIMP_BUILD_DLL_EXPORT
# define ASSIMP_API __declspec(dllexport)
# define ASSIMP_API_WINONLY __declspec(dllexport)
# elif (defined ASSIMP_DLL)
# define ASSIMP_API __declspec(dllimport)
# define ASSIMP_API_WINONLY __declspec(dllimport)
# else
# define ASSIMP_API
# define ASSIMP_API_WINONLY
# endif
#else
#define ASSIMP_API
#define ASSIMP_API_WINONLY
#endif
#elif defined(SWIG)
/* Do nothing, the relevant defines are all in AssimpSwigPort.i */
#else
#define ASSIMP_API __attribute__((visibility("default")))
#define ASSIMP_API_WINONLY
# define ASSIMP_API __attribute__((visibility("default")))
# define ASSIMP_API_WINONLY
#endif // _WIN32
/**
* @brief Helper macros
*
* @def AI_FORCE_INLINE
* @brief Force the compiler to inline a function, if possible
*
* @def AI_WONT_RETURN
* @brief Tells the compiler that a function never returns.
*
* Used in code analysis to skip dead paths (e.g. after an assertion evaluated to false).
*/
#ifdef _MSC_VER
#pragma warning(disable : 4521 4512 4714 4127 4351 4510)
#ifdef ASSIMP_BUILD_DLL_EXPORT
#pragma warning(disable : 4251)
#endif
/* Force the compiler to inline a function, if possible */
#define AI_FORCE_INLINE inline
/* Tells the compiler that a function never returns. Used in code analysis
* to skip dead paths (e.g. after an assertion evaluated to false). */
#define AI_WONT_RETURN __declspec(noreturn)
#elif defined(SWIG)
/* Do nothing, the relevant defines are all in AssimpSwigPort.i */
@ -223,29 +228,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* to typedef all structs/enums. */
//////////////////////////////////////////////////////////////////////////
#if (defined ASSIMP_DOXYGEN_BUILD)
#define C_STRUCT
#define C_ENUM
# define C_STRUCT
# define C_ENUM
#else
#define C_STRUCT struct
#define C_ENUM enum
# define C_STRUCT struct
# define C_ENUM enum
#endif
#endif
#if (defined(__BORLANDC__) || defined(__BCPLUSPLUS__))
#error Currently, Borland is unsupported. Feel free to port Assimp.
# error Currently, Borland is unsupported. Feel free to port Assimp.
#endif
//////////////////////////////////////////////////////////////////////////
/* Define ASSIMP_BUILD_SINGLETHREADED to compile assimp
* without threading support. The library doesn't utilize
* threads then and is itself not threadsafe. */
/**
* Define ASSIMP_BUILD_SINGLETHREADED to compile assimp
* without threading support. The library doesn't utilize
* threads then and is itself not threadsafe.
*/
//////////////////////////////////////////////////////////////////////////
#ifndef ASSIMP_BUILD_SINGLETHREADED
#define ASSIMP_BUILD_SINGLETHREADED
# define ASSIMP_BUILD_SINGLETHREADED
#endif
#if defined(_DEBUG) || !defined(NDEBUG)
#define ASSIMP_BUILD_DEBUG
# define ASSIMP_BUILD_DEBUG
#endif
//////////////////////////////////////////////////////////////////////////
@ -291,55 +298,74 @@ typedef unsigned int ai_uint;
#ifdef __cplusplus
constexpr ai_real ai_epsilon = (ai_real) 1e-6;
#else
#define ai_epsilon ((ai_real)1e-6)
#endif
/* Support for big-endian builds */
#if defined(__BYTE_ORDER__)
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#if !defined(__BIG_ENDIAN__)
#define __BIG_ENDIAN__
#endif
#else /* little endian */
#if defined(__BIG_ENDIAN__)
#undef __BIG_ENDIAN__
#endif
#endif
#endif
#if defined(__BIG_ENDIAN__)
#define AI_BUILD_BIG_ENDIAN
# define ai_epsilon ((ai_real)1e-6)
#endif
/**
* To avoid running out of memory
* @brief Support for big-endian builds
*
* This will check which byte ordering is used on the target architecture.
*/
#if defined(__BYTE_ORDER__)
# if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# if !defined(__BIG_ENDIAN__)
# define __BIG_ENDIAN__
# endif
# else /* little endian */
# if defined(__BIG_ENDIAN__)
# undef __BIG_ENDIAN__
# endif
# endif
#endif
#if defined(__BIG_ENDIAN__)
# define AI_BUILD_BIG_ENDIAN
#endif
/**
* @brief To avoid running out of memory
*
* This can be adjusted for specific use cases
* It's NOT a total limit, just a limit for individual allocations
*/
#define AI_MAX_ALLOC(type) ((256U * 1024 * 1024) / sizeof(type))
#ifndef _MSC_VER
#if __cplusplus >= 201103L // C++11
#define AI_NO_EXCEPT noexcept
# if __cplusplus >= 201103L // C++11
# define AI_NO_EXCEPT noexcept
# else
# define AI_NO_EXCEPT
# endif
#else
#define AI_NO_EXCEPT
#endif
#else
#if (_MSC_VER >= 1915)
#define AI_NO_EXCEPT noexcept
#else
#define AI_NO_EXCEPT
#endif
# if (_MSC_VER >= 1915)
# define AI_NO_EXCEPT noexcept
# else
# define AI_NO_EXCEPT
# endif
#endif // _MSC_VER
/**
* Helper macro to set a pointer to NULL in debug builds
* @brief Helper macro to set a pointer to NULL in debug builds
*/
#if (defined ASSIMP_BUILD_DEBUG)
#define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
#else
#define AI_DEBUG_INVALIDATE_PTR(x)
# define AI_DEBUG_INVALIDATE_PTR(x)
#endif
#define AI_COUNT_OF(X) (sizeof(X) / sizeof((X)[0]))
/**
* @brief Will mark functions or classes as deprecated.
*
* Deprecation means that we will remove this function, class or methods in the next m
*/
#if defined(__GNUC__) || defined(__clang__)
# define AI_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
# define AI_DEPRECATED __declspec(deprecated)
#else
# pragma message("WARNING: You need to implement DEPRECATED for this compiler")
# define AI_DEPRECATED
#endif
#endif // !! AI_DEFINES_H_INC

View File

@ -701,7 +701,7 @@ struct aiMaterialProperty {
* Material data is stored using a key-value structure. A single key-value
* pair is called a 'material property'. C++ users should use the provided
* member functions of aiMaterial to process material properties, C users
* have to stick with the aiMaterialGetXXX family of unbound functions.
* have to stick with the aiGetMaterialXXX family of unbound functions.
* The library defines a set of standard keys (AI_MATKEY_XXX).
*/
#ifdef __cplusplus

View File

@ -100,6 +100,7 @@ SET( COMMON
unit/Common/utBase64.cpp
unit/Common/utHash.cpp
unit/Common/utBaseProcess.cpp
unit/Common/utLogger.cpp
)
SET(Geometry

View File

@ -0,0 +1,52 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2024, 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/Importer.hpp>
using namespace Assimp;
class utLogger : public ::testing::Test {};
TEST_F(utLogger, aiGetPredefinedLogStream_leak_test) {
aiLogStream stream1 = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, nullptr);
aiLogStream stream2 = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, nullptr);
ASSERT_EQ(stream1.callback, stream2.callback);
}

View File

@ -311,6 +311,37 @@ TEST_F(utFBXImporterExporter, sceneMetadata) {
}
}
TEST_F(utFBXImporterExporter, importCustomAxes) {
// see https://github.com/assimp/assimp/issues/5494
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure);
EXPECT_NE(nullptr, scene);
// The ASCII box has customised the Up and Forward axes, verify that the RootNode transform has applied it
ASSERT_FALSE(scene->mRootNode->mTransformation.IsIdentity()) << "Did not apply the custom axis transform";
aiVector3D upVec{ 0, 0, 1 }; // Up is +Z
aiVector3D forwardVec{ 0, -1, 0 }; // Forward is -Y
aiVector3D rightVec{ 1, 0, 0 }; // Right is +X
aiMatrix4x4 mat(rightVec.x, rightVec.y, rightVec.z, 0.0f,
upVec.x, upVec.y, upVec.z, 0.0f,
forwardVec.x, forwardVec.y, forwardVec.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
EXPECT_EQ(mat, scene->mRootNode->mTransformation);
}
TEST_F(utFBXImporterExporter, importIgnoreCustomAxes) {
// see https://github.com/assimp/assimp/issues/5494
Assimp::Importer importer;
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION, true);
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure);
EXPECT_NE(nullptr, scene);
// Verify that the RootNode transform has NOT applied the custom axes
EXPECT_TRUE(scene->mRootNode->mTransformation.IsIdentity());
}
TEST_F(utFBXImporterExporter, importCubesWithOutOfRangeFloat) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_outofrange_float.fbx", aiProcess_ValidateDataStructure);

View File

@ -89,7 +89,7 @@ TEST_F(utPLYImportExport, exportTest_Success) {
#endif // ASSIMP_BUILD_NO_EXPORT
//Test issue 1623, crash when loading two PLY files in a row
// Test issue 1623, crash when loading two PLY files in a row
TEST_F(utPLYImportExport, importerMultipleTest) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure);
@ -109,7 +109,7 @@ TEST_F(utPLYImportExport, importPLYwithUV) {
EXPECT_NE(nullptr, scene);
EXPECT_NE(nullptr, scene->mMeshes[0]);
//This test model is using n-gons, so 6 faces instead of 12 tris
// This test model is using n-gons, so 6 faces instead of 12 tris
EXPECT_EQ(6u, scene->mMeshes[0]->mNumFaces);
EXPECT_EQ(aiPrimitiveType_POLYGON, scene->mMeshes[0]->mPrimitiveTypes);
EXPECT_EQ(true, scene->mMeshes[0]->HasTextureCoords(0));
@ -121,7 +121,7 @@ TEST_F(utPLYImportExport, importBinaryPLY) {
EXPECT_NE(nullptr, scene);
EXPECT_NE(nullptr, scene->mMeshes[0]);
//This test model is double sided, so 12 faces instead of 6
// This test model is double sided, so 12 faces instead of 6
EXPECT_EQ(12u, scene->mMeshes[0]->mNumFaces);
}
@ -160,7 +160,7 @@ TEST_F(utPLYImportExport, vertexColorTest) {
TEST_F(utPLYImportExport, pointcloudTest) {
Assimp::Importer importer;
//Could not use aiProcess_ValidateDataStructure since it's missing faces.
// Could not use aiProcess_ValidateDataStructure since it's missing faces.
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/issue623.ply", 0);
EXPECT_NE(nullptr, scene);
@ -192,7 +192,7 @@ static const char *test_file =
TEST_F(utPLYImportExport, parseErrorTest) {
Assimp::Importer importer;
//Could not use aiProcess_ValidateDataStructure since it's missing faces.
// Could not use aiProcess_ValidateDataStructure since it's missing faces.
const aiScene *scene = importer.ReadFileFromMemory(test_file, strlen(test_file), 0);
EXPECT_NE(nullptr, scene);
}
@ -207,5 +207,57 @@ TEST_F(utPLYImportExport, parseInvalid) {
TEST_F(utPLYImportExport, payload_JVN42386607) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/payload_JVN42386607", 0);
EXPECT_EQ(nullptr, scene);
EXPECT_EQ(nullptr, scene);
}
// Tests Issue #5729. Test, if properties defined multiple times. Unclear what to do, better to abort than to crash entirely
TEST_F(utPLYImportExport, parseInvalidDoubleProperty) {
const char data[] = "ply\n"
"format ascii 1.0\n"
"element vertex 4\n"
"property float x\n"
"property float y\n"
"property float z\n"
"element vertex 8\n"
"property float x\n"
"property float y\n"
"property float z\n"
"end_header\n"
"0.0 0.0 0.0 0.0 0.0 0.0\n"
"0.0 0.0 1.0 0.0 0.0 1.0\n"
"0.0 1.0 0.0 0.0 1.0 0.0\n"
"0.0 0.0 1.0\n"
"0.0 1.0 0.0 0.0 0.0 1.0\n"
"0.0 1.0 1.0 0.0 1.0 1.0\n";
Assimp::Importer importer;
const aiScene *scene = importer.ReadFileFromMemory(data, sizeof(data), 0);
EXPECT_EQ(nullptr, scene);
}
// Tests Issue #5729. Test, if properties defined multiple times. Unclear what to do, better to abort than to crash entirely
TEST_F(utPLYImportExport, parseInvalidDoubleCustomProperty) {
const char data[] = "ply\n"
"format ascii 1.0\n"
"element vertex 4\n"
"property float x\n"
"property float y\n"
"property float z\n"
"element name 8\n"
"property float x\n"
"element name 5\n"
"property float x\n"
"end_header\n"
"0.0 0.0 0.0 100.0 10.0\n"
"0.0 0.0 1.0 200.0 20.0\n"
"0.0 1.0 0.0 300.0 30.0\n"
"0.0 1.0 1.0 400.0 40.0\n"
"0.0 0.0 0.0 500.0 50.0\n"
"0.0 0.0 1.0 600.0 60.0\n"
"0.0 1.0 0.0 700.0 70.0\n"
"0.0 1.0 1.0 800.0 80.0\n";
Assimp::Importer importer;
const aiScene *scene = importer.ReadFileFromMemory(data, sizeof(data), 0);
EXPECT_EQ(nullptr, scene);
}