Compare commits
16 Commits
v6.0.2
...
kimkulling
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14307f41d1 | ||
|
|
c524e66d2d | ||
|
|
76af4cc396 | ||
|
|
f56a0b4592 | ||
|
|
11899f0120 | ||
|
|
5081d263db | ||
|
|
a79dc358cf | ||
|
|
db0bde758e | ||
|
|
b447485c06 | ||
|
|
4c61ca3af5 | ||
|
|
4b6cc8c28a | ||
|
|
d99f9bd2f7 | ||
|
|
b2afe717d3 | ||
|
|
ad6e8e210a | ||
|
|
a5a9f1ba33 | ||
|
|
35e0f6d80f |
10
.github/workflows/ccpp.yml
vendored
10
.github/workflows/ccpp.yml
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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 . .
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Additionally, assimp features various __mesh post-processing tools__: normals an
|
||||

|
||||
|
||||
### 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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -102,6 +102,7 @@ private:
|
||||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
float configMaxAngle;
|
||||
unsigned int configSourceUV;
|
||||
bool mActive = true;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
99
code/PostProcessing/GenerateMikkTSpaceTangents.cpp
Normal file
99
code/PostProcessing/GenerateMikkTSpaceTangents.cpp
Normal 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
|
||||
25
code/PostProcessing/GenerateMikkTSpaceTangents.h
Normal file
25
code/PostProcessing/GenerateMikkTSpaceTangents.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
1893
contrib/MikkTSpace/mikktspace.c
Normal file
1893
contrib/MikkTSpace/mikktspace.c
Normal file
File diff suppressed because it is too large
Load Diff
145
contrib/MikkTSpace/mikktspace.h
Normal file
145
contrib/MikkTSpace/mikktspace.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -23,7 +23,6 @@ z_const char * const z_errmsg[10] = {
|
||||
(z_const char *)""
|
||||
};
|
||||
|
||||
|
||||
const char * ZEXPORT zlibVersion()
|
||||
{
|
||||
return ZLIB_VERSION;
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1174,4 +1174,3 @@ struct aiSkeleton {
|
||||
#endif //! extern "C"
|
||||
|
||||
#endif // AI_MESH_H_INC
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
27
test/unit/Tools/TestTools.h
Normal file
27
test/unit/Tools/TestTools.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user