Compare commits

...

16 Commits

Author SHA1 Message Date
Kim Kulling
14307f41d1 Fix warnings 2025-07-18 20:58:56 +02:00
Kim Kulling
c524e66d2d Merge branch 'kimkulling/mikktspace_issue-2363' of https://github.com/assimp/assimp into kimkulling/mikktspace_issue-2363 2025-07-18 20:53:37 +02:00
Kim Kulling
76af4cc396 Fix compiler warnings 2025-07-18 20:53:26 +02:00
Kim Kulling
f56a0b4592 Merge branch 'master' into kimkulling/mikktspace_issue-2363 2025-07-18 19:45:07 +02:00
Kim Kulling
11899f0120 Add MikkTSpace Tangets code as 3rdparty lib 2025-07-17 16:16:38 +02:00
Kim Kulling
5081d263db Integrate MikkTSpace calculation for tangents 2025-07-17 15:46:54 +02:00
Kim Kulling
a79dc358cf Add windows clang to CI (#5537)
- Add windows clang build step
- Closes https://github.com/assimp/assimp/issues/5519


Co-authored-by: Kim Kulling <kim.kulling@draeger.com>
Co-authored-by: Kim Kulling <kullingk@LDED5178.corp.draeger.global>
2025-07-16 16:43:20 +02:00
Kim Kulling
db0bde758e Update Readme.md (#6245) 2025-07-02 14:35:32 +02:00
Kim Kulling
b447485c06 Fix sonarcube findings (#6242)
* Fix sonarcube findings

* Fix review findings
2025-06-28 18:56:28 +02:00
sSsA01
4c61ca3af5 Refix export fbx PolygonVertexIndex (#6240)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-06-27 11:30:04 +02:00
HandsomeXi
4b6cc8c28a bugfix: Fixed the memory leak when texture transforming (#6236) (#6237)
* bugfix: Fixed the memory leak when texture transforming (#6236)

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-06-26 10:53:08 +02:00
Kim Kulling
d99f9bd2f7 Refactoring: Add nupptr-checks (#6241) 2025-06-26 00:09:02 +02:00
Kim Kulling
b2afe717d3 Update Importer.hpp (#6235)
- Add doc for out-of-memory exception
- closes https://github.com/assimp/assimp/issues/5173
2025-06-21 13:33:15 +02:00
NSG
ad6e8e210a Fix: export fbx wrong to_ktime in FBXExporter.cpp (#6105)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-06-17 08:23:21 +02:00
Kim Kulling
a5a9f1ba33 Introduce mikktshape 2023-12-22 11:51:27 +01:00
Kim Kulling
35e0f6d80f Fix the windows build 2023-12-08 13:00:22 +01:00
33 changed files with 2438 additions and 195 deletions

View File

@@ -16,9 +16,13 @@ jobs:
strategy:
fail-fast: false
matrix:
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++]
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, windows-latest-clang.exe, ubuntu-latest-clang++]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include:
- name: windows-latest-clang.exe
os: windows-latest
cxx: clang++.exe
cc: clang.exe
- name: windows-latest-cl.exe
os: windows-latest
cxx: cl.exe
@@ -69,13 +73,13 @@ jobs:
${{ runner.os }}-DX_SDK
- name: Download DXSetup
if: contains(matrix.name, 'windows') && steps.dxcache.outputs.cache-hit != 'true'
if: contains(matrix.name, 'windows-latest-cl.exe') && steps.dxcache.outputs.cache-hit != 'true'
run: |
curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
- name: Set Windows specific CMake arguments
if: contains(matrix.name, 'windows')
if: contains(matrix.name, 'windows-latest-cl.exe')
id: windows_extra_cmake_args
run: echo ":set-output name=args::=-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1" >> $GITHUB_OUTPUT

View File

@@ -309,6 +309,17 @@ IF( UNIX )
ENDIF()
ENDIF()
IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND WIN32)
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
ENDIF()
IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
endif ()
# Grouped compiler settings ########################################
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU)
IF(NOT ASSIMP_HUNTER_ENABLED)
@@ -354,14 +365,13 @@ ELSEIF(MSVC)
if(NOT /utf-8 IN_LIST CMAKE_CXX_FLAGS)
# Source code is encoded in UTF-8
ADD_COMPILE_OPTIONS(/source-charset:utf-8)
endif ()
endif()
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(CMAKE_CXX_FLAGS "-Wno-deprecated-non-prototype -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
SET(CMAKE_C_FLAGS "-Wno-deprecated-non-prototype -fno-strict-aliasing ${CMAKE_C_FLAGS}")
ELSEIF( MINGW )
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.")

View File

@@ -1,9 +1,9 @@
FROM gcc:latest
FROM gcc:1.5.1.0
RUN apt-get update && apt-get install --no-install-recommends -y ninja-build cmake
RUN apt-get update \
apt-get install --no-install-recommends -y ninja-build cmake zlib1g-dev
WORKDIR /app
RUN apt install zlib1g-dev
COPY . .

View File

@@ -20,7 +20,7 @@ Additionally, assimp features various __mesh post-processing tools__: normals an
![Alt](https://repobeats.axiom.co/api/embed/997f84e5f9fcf772da1e687f3a4f3a8afdbf4cf0.svg "Repobeats analytics image")
### Documentation ###
Read [our latest documentation](https://assimp-docs.readthedocs.io/en/latest/).
Read [our latest documentation](https://the-asset-importer-lib-documentation.readthedocs.io/en/latest/).
### Pre-built binaries ###
Download binaries from [our Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).

View File

@@ -1043,6 +1043,10 @@ aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) {
}
inline int64_t to_ktime(double ticks, const aiAnimation* anim) {
if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) {
return static_cast<int64_t>(ticks * FBX::SECOND);
}
// Defensive: handle zero or near-zero mTicksPerSecond
double tps = anim->mTicksPerSecond;
double timeVal;
@@ -1062,7 +1066,7 @@ inline int64_t to_ktime(double ticks, const aiAnimation* anim) {
if (timeVal < kMin) {
return INT64_MIN;
}
return static_cast<int64_t>(timeVal * FBX::SECOND);
return static_cast<int64_t>((ticks / anim->mTicksPerSecond) * FBX::SECOND);
}
inline int64_t to_ktime(double time) {
@@ -1094,6 +1098,7 @@ void FBXExporter::WriteObjects () {
bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
// save vertex_indices as it is needed later
std::vector<std::vector<int32_t>> vVertexIndice(mScene->mNumMeshes);
std::vector<uint32_t> uniq_v_before_mi;
const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false);
@@ -1140,6 +1145,7 @@ void FBXExporter::WriteObjects () {
const aiMesh *m = mScene->mMeshes[mi];
size_t v_offset = vertex_indices.size();
size_t uniq_v_before = flattened_vertices.size() / 3;
// map of vertex value to its index in the data vector
std::map<aiVector3D,size_t> index_by_vertex_value;
@@ -1182,11 +1188,17 @@ void FBXExporter::WriteObjects () {
if (f.mNumIndices == 0) continue;
size_t pvi = 0;
for (; pvi < f.mNumIndices - 1; pvi++) {
polygon_data.push_back(vertex_indices[v_offset + f.mIndices[pvi]]);
polygon_data.push_back(
static_cast<int32_t>(uniq_v_before + vertex_indices[v_offset + f.mIndices[pvi]])
);
}
polygon_data.push_back(-1 - vertex_indices[v_offset+f.mIndices[pvi]]);
polygon_data.push_back(
static_cast<int32_t>(-1 ^ (uniq_v_before + vertex_indices[v_offset+f.mIndices[pvi]]))
);
}
uniq_v_before_mi.push_back(static_cast<uint32_t>(uniq_v_before));
if (m->HasNormals()) {
normal_data.reserve(3 * polygon_data.size());
for (size_t fi = 0; fi < m->mNumFaces; fi++) {
@@ -2058,7 +2070,8 @@ void FBXExporter::WriteObjects () {
ASSIMP_LOG_ERROR("UNREAL: Skipping vertex index to prevent buffer overflow.");
continue;
}
int32_t vi = vVertexIndice[mi][b->mWeights[wi].mVertexId];
int32_t vi = vVertexIndice[mi][b->mWeights[wi].mVertexId]
+ uniq_v_before_mi[mi];
bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
if (vi == last_index || bIsWeightedAlready) {
// only for vertices we exported to fbx

View File

@@ -740,6 +740,8 @@ SET( PostProcessing_SRCS
PostProcessing/GenFaceNormalsProcess.h
PostProcessing/GenVertexNormalsProcess.cpp
PostProcessing/GenVertexNormalsProcess.h
PostProcessing/GenerateMikkTSpaceTangents.cpp
PostProcessing/GenerateMikkTSpaceTangents.h
PostProcessing/PretransformVertices.cpp
PostProcessing/PretransformVertices.h
PostProcessing/ImproveCacheLocality.cpp
@@ -1170,6 +1172,12 @@ ENDIF()
SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS})
#ENDIF()
# mikktspacetangets
SET( MikkTSpaceTangents_SRCS
../contrib/MikkTSpace/mikktspace.c
../contrib/MikkTSpace/mikktspace.h
)
# minizip/unzip
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(minizip)
@@ -1318,11 +1326,6 @@ if(MSVC10)
endif()
endif()
IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
endif ()
IF(NOT ASSIMP_HUNTER_ENABLED)
if (UNZIP_FOUND)
SET (unzip_compile_SRCS "")
@@ -1372,6 +1375,7 @@ SET( assimp_src
${Tinyusdz_DEP_SOURCES}
${Pugixml_SRCS}
${stb_SRCS}
${MikkTSpaceTangents_SRCS}
# Necessary to show the headers in the project when using the VC++ generator:
${PUBLIC_HEADERS}
@@ -1415,7 +1419,6 @@ add_compile_options(
IF (ASSIMP_WARNINGS_AS_ERRORS)
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
IF (MSVC)
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror
-Wno-microsoft-enum-value

View File

@@ -47,8 +47,8 @@ namespace Assimp {
// ------------------------------------------------------------------------------------------------
ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) {
const ai_real s = (a + b + c) / 2;
const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
const ai_real s = (a + b + c) * 0.5;
const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), static_cast<ai_real>(0.5));
return area;
}
@@ -57,8 +57,8 @@ ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB )
const ai_real lx = ( vB.x - vA.x );
const ai_real ly = ( vB.y - vA.y );
const ai_real lz = ( vB.z - vA.z );
const ai_real a = lx*lx + ly*ly + lz*lz;
const ai_real d = pow( a, (ai_real)0.5 );
const ai_real a = lx*lx + ly*ly + lz*lz;
const ai_real d = pow( a, static_cast<ai_real>(0.5));
return d;
}
@@ -66,6 +66,9 @@ ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB )
// ------------------------------------------------------------------------------------------------
ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
ai_real area = 0;
if (mesh == nullptr) {
return area;
}
const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
@@ -81,8 +84,7 @@ ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh
// ------------------------------------------------------------------------------------------------
// 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) {
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)
@@ -93,11 +95,14 @@ bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
}
// ------------------------------------------------------------------------------------------------
void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut,
size_t numVectors) {
void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) {
if (vectorArrayIn == nullptr || vectorArrayOut == nullptr) {
return;
}
for (size_t i=0; i<numVectors; ++i) {
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
}
} // namespace Assimp

View File

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -63,7 +61,11 @@ CalcTangentsProcess::CalcTangentsProcess() :
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_CalcTangentSpace) != 0;
const bool active = ((pFlags & aiProcess_CalcTangentSpace) != 0);
if (mActive) {
return active;
}
return false;
}
// ------------------------------------------------------------------------------------------------
@@ -71,6 +73,8 @@ bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
ai_assert(nullptr != pImp);
mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false);
// get the current value of the property
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);

View File

@@ -102,6 +102,7 @@ private:
/** Configuration option: maximum smoothing angle, in radians*/
float configMaxAngle;
unsigned int configSourceUV;
bool mActive = true;
};
} // end of namespace Assimp

View File

@@ -0,0 +1,99 @@
#include "GenerateMikkTSpaceTangents.h"
#include <assimp/scene.h>
#include <assimp/postprocess.h>
namespace Assimp {
static int get_num_faces(const SMikkTSpaceContext *context);
static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace);
static void get_position(const SMikkTSpaceContext *context, float outpos[], int iFace, int iVert);
static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int iFace, int iVert);
static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int iFace, int iVert);
static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float fSign, int iFace, int iVert);
static int get_num_faces(const SMikkTSpaceContext *context) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const int numFaces = static_cast<int>(currentMesh->mNumFaces);
return numFaces;
}
static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiFace &face = currentMesh->mFaces[iFace];
return face.mNumIndices;
}
static void get_position(const SMikkTSpaceContext *context, float outpos[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiVector3D &v = currentMesh->mVertices[static_cast<size_t>(iVert)];
outpos[0] = v.x;
outpos[1] = v.y;
outpos[2] = v.z;
}
static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiVector3D &n = currentMesh->mNormals[static_cast<size_t>(iVert)];
outnormal[0] = n.x;
outnormal[1] = n.y;
outnormal[2] = n.z;
}
static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
aiVector3D &t = currentMesh->mTextureCoords[static_cast<size_t>(iVert)][0];
if (currentMesh->mNumUVComponents[iVert] == 2) {
outuv[0] = t.x;
outuv[1] = t.y;
} else if (currentMesh->mNumUVComponents[iVert] == 3){
outuv[0] = t.x;
outuv[1] = t.y;
outuv[2] = 0.0;
}
}
static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float /*fSign*/, int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
currentMesh->mTangents[iVert].x = tangentu[0];
currentMesh->mTangents[iVert].y = tangentu[1];
currentMesh->mTangents[iVert].z = tangentu[2];
}
bool GenerateMikkTSpaceTangents::IsActive(unsigned int pFlags) const {
const bool active = (pFlags & aiProcess_CalcTangentSpace) != 0;
if (mActive) {
return active;
}
return false;
}
void GenerateMikkTSpaceTangents::Execute(aiScene* pScene) {
mIface.m_getNumFaces = get_num_faces;
mIface.m_getNumVerticesOfFace = get_num_vertices_of_face;
mIface.m_getNormal = get_normal;
mIface.m_getPosition = get_position;
mIface.m_getTexCoord = get_tex_coords;
mIface.m_setTSpaceBasic = set_tspace_basic;
mContext.m_pInterface = &mIface;
for (size_t i=0; i<pScene->mNumMeshes; ++i) {
aiMesh *mesh = pScene->mMeshes[i];
ExecutePerMesh(mesh);
}
}
void GenerateMikkTSpaceTangents::SetupProperties(const Importer *pImp) {
mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false);
}
void GenerateMikkTSpaceTangents::ExecutePerMesh(aiMesh *mesh) {
if (mesh == nullptr) {
return;
}
mContext.m_pUserData = mesh;
genTangSpaceDefault(&mContext);
}
} // namespace Assimp

View File

@@ -0,0 +1,25 @@
#pragma once
#include "Common/BaseProcess.h"
#include "contrib/MikkTSpace/mikktspace.h"
struct aiMesh;
namespace Assimp {
class GenerateMikkTSpaceTangents final : public BaseProcess {
public:
GenerateMikkTSpaceTangents() = default;
~GenerateMikkTSpaceTangents() override = default;
bool IsActive(unsigned int pFlags) const override;
void Execute(aiScene* pScene) override;
void SetupProperties(const Importer *pImp) override;
void ExecutePerMesh(aiMesh *mesh);
private:
bool mActive = false;
SMikkTSpaceInterface mIface;
SMikkTSpaceContext mContext;
};
} // namespace Assimp

View File

@@ -1,7 +1,6 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2025, assimp team
All rights reserved.
@@ -35,27 +34,20 @@ 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 A helper class that processes texture transformations */
#include "TextureTransform.h"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#include "TextureTransform.h"
#include <assimp/StringUtils.h>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
TextureTransformStep::TextureTransformStep() : configFlags() {
// nothing to do here
}
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
@@ -202,7 +194,6 @@ inline static const char* MappingModeToChar(aiTextureMapMode map) {
void TextureTransformStep::Execute( aiScene* pScene) {
ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin");
/* We build a per-mesh list of texture transformations we'll need
* to apply. To achieve this, we iterate through all materials,
* find all textures and get their transformations and UV indices.
@@ -426,7 +417,6 @@ void TextureTransformStep::Execute( aiScene* pScene) {
// it shouldn't be too worse if we remove them.
unsigned int size = (unsigned int)trafo.size();
if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_ERROR(static_cast<unsigned int>(trafo.size()), " UV channels required but just ",
AI_MAX_NUMBER_OF_TEXTURECOORDS, " available");
@@ -434,7 +424,6 @@ void TextureTransformStep::Execute( aiScene* pScene) {
size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
}
aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
old[n] = mesh->mTextureCoords[n];
@@ -443,14 +432,13 @@ void TextureTransformStep::Execute( aiScene* pScene) {
// that we're not going to need later can be overridden.
it = trafo.begin();
for (unsigned int n = 0; n < trafo.size();++n,++it) {
if (n >= size) {
// Try to use an untransformed channel for all channels we threw over board
UpdateUVIndex((*it).updateList,untransformed);
continue;
}
outChannels++;
++outChannels;
// Write to the log
if (!DefaultLogger::isNullLogger()) {
@@ -470,15 +458,18 @@ void TextureTransformStep::Execute( aiScene* pScene) {
// Check whether we need a new buffer here
if (mesh->mTextureCoords[n]) {
it2 = it;++it2;
it2 = it;
++it2;
for (unsigned int m = n+1; m < size;++m, ++it2) {
if ((*it2).uvIndex == n){
it2 = trafo.begin();
break;
}
}
if (it2 == trafo.begin()){
if (it2 == trafo.begin()) {
{
std::unique_ptr<aiVector3D[]> oldTextureCoords(mesh->mTextureCoords[n]);
}
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
}
}
@@ -536,13 +527,12 @@ void TextureTransformStep::Execute( aiScene* pScene) {
// Print some detailed statistics into the log
if (!DefaultLogger::isNullLogger()) {
if (transformedChannels) {
ASSIMP_LOG_INFO("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")");
} else {
ASSIMP_LOG_DEBUG("TransformUVCoordsProcess finished");
ASSIMP_LOG_INFO("TransformUVCoordsProcess finished");
}
}
}
} // namespace Assimp

View File

@@ -1,7 +1,6 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2025, assimp team
All rights reserved.
@@ -43,9 +42,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED
#define AI_TEXTURE_TRANSFORM_H_INCLUDED
#include <assimp/BaseImporter.h>
#include "Common/BaseProcess.h"
#include <assimp/BaseImporter.h>
#include <assimp/material.h>
#include <list>
@@ -56,129 +55,103 @@ namespace Assimp {
#define AI_TT_UV_IDX_LOCK_TBD 0xffffffff
#define AI_TT_UV_IDX_LOCK_NONE 0xeeeeeeee
#define AI_TT_ROTATION_EPSILON ((float)AI_DEG_TO_RAD(0.5))
// ---------------------------------------------------------------------------
/** Small helper structure representing a shortcut into the material list
* to be able to update some values quickly.
*/
/**
* @brief Small helper structure representing a shortcut into the material list
* to be able to update some values quickly.
*/
struct TTUpdateInfo {
TTUpdateInfo() AI_NO_EXCEPT
: directShortcut(nullptr)
, mat(nullptr)
, semantic(0)
, index(0) {
// empty
}
//! Direct shortcut, if available
unsigned int* directShortcut;
unsigned int* directShortcut = nullptr;
//! Material
aiMaterial *mat;
aiMaterial *mat = nullptr;
//! Texture type and index
unsigned int semantic, index;
//! Texture type
unsigned int semantic = 0;
//! Texture index
unsigned int index = 0;
};
// ---------------------------------------------------------------------------
/** Helper class representing texture coordinate transformations
*/
/**
* @brief Helper class representing texture coordinate transformations
*/
struct STransformVecInfo : public aiUVTransform {
STransformVecInfo() AI_NO_EXCEPT
: uvIndex(0)
, mapU(aiTextureMapMode_Wrap)
, mapV(aiTextureMapMode_Wrap)
, lockedPos(AI_TT_UV_IDX_LOCK_NONE) {
// empty
}
//! Source texture coordinate index
unsigned int uvIndex;
unsigned int uvIndex = 0;
//! Texture mapping mode in the u, v direction
aiTextureMapMode mapU,mapV;
//! Texture mapping mode in the u direction
aiTextureMapMode mapU = aiTextureMapMode_Wrap;
//! Texture mapping mode in the v direction
aiTextureMapMode mapV = aiTextureMapMode_Wrap;
//! Locked destination UV index
//! AI_TT_UV_IDX_LOCK_TBD - to be determined
//! AI_TT_UV_IDX_LOCK_NONE - none (default)
unsigned int lockedPos;
unsigned int lockedPos = AI_TT_UV_IDX_LOCK_NONE;
//! Update info - shortcuts into all materials
//! that are referencing this transform setup
std::list<TTUpdateInfo> updateList;
// -------------------------------------------------------------------
/** Compare two transform setups
*/
inline bool operator== (const STransformVecInfo& other) const
{
inline bool operator== (const STransformVecInfo& other) const {
// We use a small epsilon here
const static float epsilon = 0.05f;
if (std::fabs( mTranslation.x - other.mTranslation.x ) > epsilon ||
std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon)
{
std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon) {
return false;
}
if (std::fabs( mScaling.x - other.mScaling.x ) > epsilon ||
std::fabs( mScaling.y - other.mScaling.y ) > epsilon)
{
std::fabs( mScaling.y - other.mScaling.y ) > epsilon) {
return false;
}
if (std::fabs( mRotation - other.mRotation) > epsilon)
{
if (std::fabs( mRotation - other.mRotation) > epsilon) {
return false;
}
return true;
}
inline bool operator!= (const STransformVecInfo& other) const
{
inline bool operator!= (const STransformVecInfo& other) const {
return !(*this == other);
}
// -------------------------------------------------------------------
/** Returns whether this is an untransformed texture coordinate set
*/
inline bool IsUntransformed() const
{
/**
* @brief Returns whether this is an untransformed texture coordinate set
*/
inline bool IsUntransformed() const {
return (1.0f == mScaling.x && 1.f == mScaling.y &&
!mTranslation.x && !mTranslation.y &&
mRotation < AI_TT_ROTATION_EPSILON);
!mTranslation.x && !mTranslation.y && mRotation < AI_TT_ROTATION_EPSILON);
}
// -------------------------------------------------------------------
/** Build a 3x3 matrix from the transformations
*/
inline void GetMatrix(aiMatrix3x3& mOut)
{
/**
* @brief Build a 3x3 matrix from the transformations
*/
inline void GetMatrix(aiMatrix3x3& mOut) {
mOut = aiMatrix3x3();
if (1.0f != mScaling.x || 1.0f != mScaling.y)
{
if (1.0f != mScaling.x || 1.0f != mScaling.y) {
aiMatrix3x3 mScale;
mScale.a1 = mScaling.x;
mScale.b2 = mScaling.y;
mOut = mScale;
}
if (mRotation)
{
if (mRotation) {
aiMatrix3x3 mRot;
mRot.a1 = mRot.b2 = std::cos(mRotation);
mRot.a2 = mRot.b1 = std::sin(mRotation);
mRot.a2 = -mRot.a2;
mOut *= mRot;
}
if (mTranslation.x || mTranslation.y)
{
if (mTranslation.x || mTranslation.y) {
aiMatrix3x3 mTrans;
mTrans.a3 = mTranslation.x;
mTrans.b3 = mTranslation.y;
@@ -187,16 +160,18 @@ struct STransformVecInfo : public aiUVTransform {
}
};
// ---------------------------------------------------------------------------
/** Helper step to compute final UV coordinate sets if there are scalings
/**
* @brief Helper step to compute final UV coordinate sets if there are scalings
* or rotations in the original data read from the file.
*/
class TextureTransformStep : public BaseProcess {
*/
class TextureTransformStep final : public BaseProcess {
public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
TextureTransformStep();
/// The default class constructor. /
TextureTransformStep() = default;
/// The default class destructor.
~TextureTransformStep() override = default;
// -------------------------------------------------------------------
@@ -210,10 +185,11 @@ public:
protected:
// -------------------------------------------------------------------
/** Preprocess a specific UV transformation setup
/**
* @brief Preprocess a specific UV transformation setup
*
* @param info Transformation setup to be preprocessed.
*/
*/
void PreProcessUVTransform(STransformVecInfo& info);
private:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,145 @@
/** \file mikktspace/mikktspace.h
* \ingroup mikktspace
*/
/**
* Copyright (C) 2011 by Morten S. Mikkelsen
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef __MIKKTSPACE_H__
#define __MIKKTSPACE_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Author: Morten S. Mikkelsen
* Version: 1.0
*
* The files mikktspace.h and mikktspace.c are designed to be
* stand-alone files and it is important that they are kept this way.
* Not having dependencies on structures/classes/libraries specific
* to the program, in which they are used, allows them to be copied
* and used as is into any tool, program or plugin.
* The code is designed to consistently generate the same
* tangent spaces, for a given mesh, in any tool in which it is used.
* This is done by performing an internal welding step and subsequently an order-independent evaluation
* of tangent space for meshes consisting of triangles and quads.
* This means faces can be received in any order and the same is true for
* the order of vertices of each face. The generated result will not be affected
* by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
* primitives are present or not will not affect the generated results either.
* Once tangent space calculation is done the vertices of degenerate primitives will simply
* inherit tangent space from neighboring non degenerate primitives.
* The analysis behind this implementation can be found in my master's thesis
* which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
* Note that though the tangent spaces at the vertices are generated in an order-independent way,
* by this implementation, the interpolated tangent space is still affected by which diagonal is
* chosen to split each quad. A sensible solution is to have your tools pipeline always
* split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
* If these have the same length then compare the diagonals defined by the texture coordinates.
* XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
* and also quad triangulator plugin.
*/
typedef int tbool;
typedef struct SMikkTSpaceContext SMikkTSpaceContext;
typedef struct {
// Returns the number of faces (triangles/quads) on the mesh to be processed.
int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
// Returns the number of vertices on face number iFace
// iFace is a number in the range {0, 1, ..., getNumFaces()-1}
int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace);
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
// either (or both) of the two setTSpace callbacks can be set.
// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
// This function is used to return the tangent and fSign to the application.
// fvTangent is a unit length vector.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
// This function is used to return tangent space results to the application.
// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
// true magnitudes which can be used for relief mapping effects.
// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
// However, both are perpendicular to the vertex normal.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
} SMikkTSpaceInterface;
struct SMikkTSpaceContext
{
SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
};
// these are both thread safe!
tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold);
// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
// normal map sampler must use the exact inverse of the pixel shader transformation.
// The most efficient transformation we can possibly do in the pixel shader is
// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
// pixel shader (fast transform out)
// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
// where vNt is the tangent space normal. The normal map sampler must likewise use the
// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
// sampler does (exact inverse of pixel shader):
// float3 row0 = cross(vB, vN);
// float3 row1 = cross(vN, vT);
// float3 row2 = cross(vT, vB);
// float fSign = dot(vT, row0)<0 ? -1 : 1;
// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
// where vNout is the sampled normal in some chosen 3D space.
//
// Should you choose to reconstruct the bitangent in the pixel shader instead
// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
// However, this must be used both by the sampler and your tools/rendering pipeline.
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -12,6 +12,15 @@
# endif
#endif
#ifdef _WIN32
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif // _CRT_SECURE_NO_WARNINGS
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
# endif // _CRT_NONSTDC_NO_DEPRECATE
#endif // _WIN32
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else

View File

@@ -3,6 +3,15 @@
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _WIN32
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
# endif
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif //_CRT_SECURE_NO_WARNINGS
#endif // _WIN32
#include "gzguts.h"
#if defined(_WIN32) && !defined(__BORLANDC__)

View File

@@ -3,6 +3,15 @@
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _WIN32
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif // _CRT_SECURE_NO_WARNINGS
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
# endif // _CRT_NONSTDC_NO_DEPRECATE
#endif // _WIN32
#include "gzguts.h"
/* Local functions */

View File

@@ -2,7 +2,6 @@
* Copyright (C) 2004-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* Local functions */

View File

@@ -23,7 +23,6 @@ z_const char * const z_errmsg[10] = {
(z_const char *)""
};
const char * ZEXPORT zlibVersion()
{
return ZLIB_VERSION;

View File

@@ -108,6 +108,10 @@ namespace Assimp {
* allocations and may take some time, so it's better to reuse them as often as
* possible.
*
* If you want to let assimp deal with OutOfMemory-exception make sure that
* ASSIMP_CATCH_GLOBAL_EXCEPTIONS is set.
* If this is not the case you need to catch the exception by yourself.
*
* If you need the Importer to do custom file handling to access the files,
* implement IOSystem and IOStream and supply an instance of your custom
* IOSystem implementation by calling SetIOHandler() before calling ReadFile().

View File

@@ -1175,6 +1175,9 @@ enum aiComponent
#endif // AI_CONFIG_APP_SCALE_KEY
#define AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS \
"POSTPROCESS_USE_MIKKTSPACE_TANGENTS"
// ---------- All the Build/Compile-time defines ------------
/** @brief Specifies if double precision is supported inside assimp
@@ -1182,6 +1185,6 @@ enum aiComponent
* Property type: Bool. Default value: undefined.
*/
#cmakedefine ASSIMP_DOUBLE_PRECISION 1
#define ASSIMP_DOUBLE_PRECISION 1
#endif // !! AI_CONFIG_H_INC

View File

@@ -1174,4 +1174,3 @@ struct aiSkeleton {
#endif //! extern "C"
#endif // AI_MESH_H_INC

View File

@@ -118,7 +118,7 @@ extern "C" {
/** Maximum dimension for strings, ASSIMP strings are zero terminated. */
#ifdef __cplusplus
static const size_t AI_MAXLEN = 1024;
static constexpr size_t AI_MAXLEN = 1024;
#else
#define AI_MAXLEN 1024
#endif

View File

@@ -59,6 +59,10 @@ endif()
# Assimp library can be found, even if it is not installed system-wide yet.
LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib )
SET(TOOLS
unit/Tools/TestTools.h
)
SET( COMMON
unit/utSimd.cpp
unit/utIOSystem.cpp
@@ -219,6 +223,7 @@ SOURCE_GROUP( UnitTests\\GeometryTools FILES ${Geometry} )
SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} )
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
SOURCE_GROUP( UnitTests\\Tools FILES ${TOOLS} )
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
add_executable( unit
@@ -227,11 +232,12 @@ add_executable( unit
../code/Common/Version.cpp
../code/Common/Base64.cpp
${COMMON}
${Geometry}
${Geometry}
${IMPORTERS}
${MATERIAL}
${MATH}
${POST_PROCESSES}
${POST_PROCESSES}
${TOOLS}
)
if(ASSIMP_HUNTER_ENABLED)

View File

@@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -43,20 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace ::Assimp;
class TestDefaultIOStream : public DefaultIOStream {
class TestDefaultIOStream final : public DefaultIOStream {
public:
TestDefaultIOStream()
: DefaultIOStream() {
// empty
}
TestDefaultIOStream( FILE* pFile, const std::string &strFilename )
: DefaultIOStream( pFile, strFilename ) {
// empty
}
virtual ~TestDefaultIOStream() {
// empty
}
TestDefaultIOStream() = default;
TestDefaultIOStream(FILE* pFile, const std::string &strFilename) : DefaultIOStream(pFile, strFilename) {}
~TestDefaultIOStream() override = default;
};

View File

@@ -0,0 +1,27 @@
#pragma once
#include <gtest/gtest.h>
#include <cstdio>
#include <string>
namespace Assimp::Unittest {
class TestTools final {
public:
TestTools() = default;
~TestTools() = default;
static bool openFilestream(FILE **pFile, const char *filename, const char *mode);
};
inline bool TestTools::openFilestream(FILE **fs, const char *filename, const char *mode) {
#if defined(_WIN32)
errno_t err{ 0 };
err = fopen_s(fs, filename, mode);
EXPECT_EQ(err, 0);
#else
*fs = fopen(filename, mode);
#endif
return fs != nullptr;
}
} // namespace Assimp::Unittest

View File

@@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@@ -39,42 +39,60 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#pragma once
#ifdef _WIN32
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
# endif // _CRT_NONSTDC_NO_DEPRECATE
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif
#endif
#include <cstdio>
#include <cstdlib>
#include <gtest/gtest.h>
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
#define TMP_PATH "./"
# define TMP_PATH "./"
#elif defined(__GNUC__) || defined(__clang__)
#define TMP_PATH "/tmp/"
# define TMP_PATH "/var/tmp/"
#endif
#if defined(_MSC_VER)
#include <io.h>
inline FILE* MakeTmpFile(char* tmplate)
{
auto pathtemplate = _mktemp(tmplate);
inline FILE* MakeTmpFile(char* tmplate, size_t len, std::string &tmpName) {
size_t tmpLen = len + 1;
char *pathtemplate = new char[tmpLen];
strcpy_s(pathtemplate, tmpLen, tmplate);
int err_code = _mktemp_s(pathtemplate, tmpLen);
EXPECT_EQ(err_code, 0);
EXPECT_NE(pathtemplate, nullptr);
if(pathtemplate == nullptr)
{
if(pathtemplate == nullptr) {
delete[] pathtemplate;
return nullptr;
}
auto* fs = std::fopen(pathtemplate, "w+");
errno_t err;
FILE *fs{nullptr};
err = fopen_s(&fs, pathtemplate, "w+");
EXPECT_EQ(0, err);
tmpName = pathtemplate;
EXPECT_NE(fs, nullptr);
delete[] pathtemplate;
return fs;
}
#elif defined(__GNUC__) || defined(__clang__)
inline FILE* MakeTmpFile(char* tmplate)
{
inline FILE *MakeTmpFile(char *tmplate, size_t len, std::string &tmpName) {
auto fd = mkstemp(tmplate);
EXPECT_NE(-1, fd);
if(fd == -1)
{
if(fd == -1) {
return nullptr;
}
auto fs = fdopen(fd, "w+");
EXPECT_NE(nullptr, fs);
tmpName += tmplate;
return fs;
}
#endif

View File

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,

View File

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,

View File

@@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <gtest/gtest.h>
#include "TestIOStream.h"
#include "UnitTestFileGenerator.h"
#include "Tools/TestTools.h"
#include <cstdio>
#include <cstdlib>
#include <string>
@@ -60,8 +61,9 @@ TEST_F( utDefaultIOStream, FileSizeTest ) {
const auto dataSize = sizeof(data);
const auto dataCount = dataSize / sizeof(*data);
char fpath[] = { TMP_PATH"rndfp.XXXXXX" };
auto* fs = MakeTmpFile(fpath);
char fpath[] = { TMP_PATH"rndfp.XXXXXX\0" };
std::string tmpName;
auto *fs = MakeTmpFile(fpath, std::strlen(fpath), tmpName);
ASSERT_NE(nullptr, fs);
{
auto written = std::fwrite(data, sizeof(*data), dataCount, fs );
@@ -71,13 +73,13 @@ TEST_F( utDefaultIOStream, FileSizeTest ) {
ASSERT_EQ(vflush, 0);
std::fclose(fs);
fs = std::fopen(fpath, "r");
ASSERT_NE(nullptr, fs);
EXPECT_TRUE(Unittest::TestTools::openFilestream(&fs, tmpName.c_str(), "r"));
ASSERT_NE(nullptr, fs);
TestDefaultIOStream myStream( fs, fpath);
size_t size = myStream.FileSize();
EXPECT_EQ( size, dataSize);
}
remove(fpath);
remove(tmpName.c_str());
}

View File

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -44,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "UnitTestPCH.h"
#include <assimp/IOStreamBuffer.h>
#include "TestIOStream.h"
#include "Tools/TestTools.h"
#include "UnitTestFileGenerator.h"
class IOStreamBufferTest : public ::testing::Test {
@@ -86,18 +85,21 @@ TEST_F( IOStreamBufferTest, open_close_Test ) {
const auto dataCount = dataSize / sizeof(*data);
char fname[]={ "octest.XXXXXX" };
auto* fs = MakeTmpFile(fname);
std::string tmpName;
auto* fs = MakeTmpFile(fname, std::strlen(fname), tmpName);
ASSERT_NE(nullptr, fs);
auto written = std::fwrite( data, sizeof(*data), dataCount, fs );
auto written = std::fwrite(data, sizeof(*data), dataCount, fs);
EXPECT_NE( 0U, written );
auto flushResult = std::fflush( fs );
ASSERT_EQ(0, flushResult);
std::fclose( fs );
fs = std::fopen(fname, "r");
ASSERT_NE(nullptr, fs);
fclose(fs);
FILE *new_fs{ nullptr };
EXPECT_TRUE(Unittest::TestTools::openFilestream(&new_fs, tmpName.c_str(), "r"));
ASSERT_NE(nullptr, new_fs);
{
TestDefaultIOStream myStream( fs, fname );
TestDefaultIOStream myStream(new_fs, fname);
EXPECT_TRUE( myBuffer.open( &myStream ) );
EXPECT_FALSE( myBuffer.open( &myStream ) );
@@ -111,8 +113,9 @@ TEST_F( IOStreamBufferTest, readlineTest ) {
const auto dataSize = sizeof(data);
const auto dataCount = dataSize / sizeof(*data);
char fname[]={ "readlinetest.XXXXXX" };
auto* fs = MakeTmpFile(fname);
char fname[]={ "readlinetest.XXXXXX\0" };
std::string tmpName;
auto* fs = MakeTmpFile(fname, std::strlen(fname), tmpName);
ASSERT_NE(nullptr, fs);
auto written = std::fwrite( data, sizeof(*data), dataCount, fs );
@@ -121,23 +124,25 @@ TEST_F( IOStreamBufferTest, readlineTest ) {
auto flushResult = std::fflush(fs);
ASSERT_EQ(0, flushResult);
std::fclose(fs);
fs = std::fopen(fname, "r");
ASSERT_NE(nullptr, fs);
FILE *new_fs{ nullptr };
EXPECT_TRUE(Unittest::TestTools::openFilestream(&new_fs, tmpName.c_str(), "r"));
ASSERT_NE(nullptr, new_fs);
const auto tCacheSize = 26u;
IOStreamBuffer<char> myBuffer( tCacheSize );
EXPECT_EQ(tCacheSize, myBuffer.cacheSize() );
IOStreamBuffer<char> myBuffer(tCacheSize);
EXPECT_EQ(tCacheSize, myBuffer.cacheSize());
TestDefaultIOStream myStream( fs, fname );
TestDefaultIOStream myStream(new_fs, fname);
auto size = myStream.FileSize();
auto numBlocks = size / myBuffer.cacheSize();
if ( size % myBuffer.cacheSize() > 0 ) {
numBlocks++;
}
EXPECT_TRUE( myBuffer.open( &myStream ) );
EXPECT_EQ( numBlocks, myBuffer.getNumBlocks() );
EXPECT_TRUE( myBuffer.close() );
EXPECT_TRUE(myBuffer.open(&myStream));
EXPECT_EQ(numBlocks, myBuffer.getNumBlocks() );
EXPECT_TRUE(myBuffer.close() );
}
TEST_F( IOStreamBufferTest, accessBlockIndexTest ) {

View File

@@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AbstractImportExportBase.h"
#include "UnitTestPCH.h"
#include "Tools/TestTools.h"
#include <assimp/commonMetaData.h>
#include <assimp/postprocess.h>
#include <assimp/config.h>
@@ -472,7 +472,8 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFan) {
std::vector<char> ReadFile(const char *name) {
std::vector<char> ret;
FILE *p = ::fopen(name, "r");
FILE *p{ nullptr };
EXPECT_TRUE(Unittest::TestTools::openFilestream(&p, name, "r"));
if (nullptr == p) {
return ret;
}