diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index fcd6ece87..b6cfae367 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -130,7 +130,7 @@ jobs: prerelease: true - run: | echo '${{steps.create-release.outputs.upload_url}}' > release_upload_url.txt - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v4 with: name: create-release path: release_upload_url.txt @@ -171,13 +171,13 @@ jobs: runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') steps: - - uses: softprops/action-gh-release@v1 + - uses: softprops/action-gh-release@v2 with: name: create-release - id: upload-url run: | echo "url=$(cat create-release/release_upload_url.txt)" >> $GITHUB_OUTPUT - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}' - uses: actions/upload-release-asset@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index d160f48b6..074d64839 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,15 @@ CMAKE_MINIMUM_REQUIRED( VERSION 3.22 ) # auto-cloned during build; so MUST disable the feature or the PR will be rejected option(ASSIMP_BUILD_USD_IMPORTER "Enable USD file import" off) option(ASSIMP_BUILD_USD_VERBOSE_LOGS "Enable verbose USD import debug logging" off) +option(ASSIMP_BUILD_USE_CCACHE "Use ccache to speed up compilation." on) + +if(ASSIMP_BUILD_USE_CCACHE) + find_program(CCACHE_PATH ccache) + if (CCACHE_PATH) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH}) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH}) + endif() +endif() # Disabled importers: m3d for 5.1 or later ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_IMPORTER) diff --git a/code/AssetLib/3MF/D3MFExporter.cpp b/code/AssetLib/3MF/D3MFExporter.cpp index 6caa4c84e..6c09f097d 100644 --- a/code/AssetLib/3MF/D3MFExporter.cpp +++ b/code/AssetLib/3MF/D3MFExporter.cpp @@ -249,10 +249,10 @@ void D3MFExporter::writeBaseMaterials() { if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) { hexDiffuseColor = ai_rgba2hex( - (int)((ai_real)color.r) * 255, - (int)((ai_real)color.g) * 255, - (int)((ai_real)color.b) * 255, - (int)((ai_real)color.a) * 255, + (int)(((ai_real)color.r) * 255), + (int)(((ai_real)color.g) * 255), + (int)(((ai_real)color.b) * 255), + (int)(((ai_real)color.a) * 255), true); } else { diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 234931cbe..fd54c63f4 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -2128,6 +2128,10 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_ TrySetTextureProperties(out_mat, _textures, "Maya|emissionColor", aiTextureType_EMISSION_COLOR, mesh); TrySetTextureProperties(out_mat, _textures, "Maya|metalness", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, _textures, "Maya|diffuseRoughness", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + TrySetTextureProperties(out_mat, _textures, "Maya|base", aiTextureType_MAYA_BASE, mesh); + TrySetTextureProperties(out_mat, _textures, "Maya|specular", aiTextureType_MAYA_SPECULAR, mesh); + TrySetTextureProperties(out_mat, _textures, "Maya|specularColor", aiTextureType_MAYA_SPECULAR_COLOR, mesh); + TrySetTextureProperties(out_mat, _textures, "Maya|specularRoughness", aiTextureType_MAYA_SPECULAR_ROUGHNESS, mesh); // Maya stingray TrySetTextureProperties(out_mat, _textures, "Maya|TEX_color_map", aiTextureType_BASE_COLOR, mesh); diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index bfefc92c9..79fa572af 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -2487,6 +2487,57 @@ const std::map> transform_types = { {"GeometricScalingInverse", {"GeometricScalingInverse", 'i'}} }; +//add metadata to fbx property +void add_meta(FBX::Node& fbx_node, const aiNode* node){ + if(node->mMetaData == nullptr) return; + aiMetadata* meta = node->mMetaData; + for (unsigned int i = 0; i < meta->mNumProperties; ++i) { + aiString key = meta->mKeys[i]; + aiMetadataEntry* entry = &meta->mValues[i]; + switch (entry->mType) { + case AI_BOOL:{ + bool val = *static_cast(entry->mData); + fbx_node.AddP70bool(key.C_Str(), val); + break; + } + case AI_INT32:{ + int32_t val = *static_cast(entry->mData); + fbx_node.AddP70int(key.C_Str(), val); + break; + } + case AI_UINT64:{ + //use string to add uint64 + uint64_t val = *static_cast(entry->mData); + fbx_node.AddP70string(key.C_Str(), std::to_string(val).c_str()); + break; + } + case AI_FLOAT:{ + float val = *static_cast(entry->mData); + fbx_node.AddP70double(key.C_Str(), val); + break; + } + case AI_DOUBLE:{ + double val = *static_cast(entry->mData); + fbx_node.AddP70double(key.C_Str(), val); + break; + } + case AI_AISTRING:{ + aiString val = *static_cast(entry->mData); + fbx_node.AddP70string(key.C_Str(), val.C_Str()); + break; + } + case AI_AIMETADATA: { + //ignore + break; + } + default: + break; + } + + } + +} + // write a single model node to the stream void FBXExporter::WriteModelNode( StreamWriterLE& outstream, @@ -2554,6 +2605,7 @@ void FBXExporter::WriteModelNode( } } } + add_meta(p, node); m.AddChild(p); // not sure what these are for, diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 3e42ffe57..0ca23863c 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -940,7 +940,7 @@ namespace glTF2 { if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) { throw DeadlyExportError("Failed to write body data!"); } - if (curPaddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) { + if (curPaddingLength && outfile->Write(&padding, 1, curPaddingLength) != curPaddingLength) { throw DeadlyExportError("Failed to write body data padding!"); } } diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 30730f716..9b2708623 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1575,7 +1575,7 @@ if(MSVC AND ASSIMP_INSTALL_PDB) COMPILE_PDB_NAME_DEBUG assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX} ) - IF(GENERATOR_IS_MULTI_CONFIG) + IF(is_multi_config) install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION ${ASSIMP_LIB_INSTALL_DIR} CONFIGURATIONS Debug diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 7954d4d01..88fa49793 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -63,6 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace Assimp { @@ -252,6 +253,14 @@ void SceneCombiner::AttachToGraph(aiScene *master, std::vector &srcList, unsigned int flags) { if (nullptr == _dest) { + std::unordered_set uniqueScenes; + uniqueScenes.insert(master); + for (const auto &item : srcList) { + uniqueScenes.insert(item.scene); + } + for (const auto &item : uniqueScenes) { + delete item; + } return; } @@ -259,6 +268,7 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vectormFlags = src->mFlags; // source private data might be nullptr if the scene is user-allocated (i.e. for use with the export API) - if (dest->mPrivate != nullptr) { + if (src->mPrivate != nullptr) { ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0; } } diff --git a/include/assimp/material.h b/include/assimp/material.h index a8c6282c4..244c6607e 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -292,6 +292,14 @@ enum aiTextureType { aiTextureType_DIFFUSE_ROUGHNESS = 16, aiTextureType_AMBIENT_OCCLUSION = 17, + /** Unknown texture + * + * A texture reference that does not match any of the definitions + * above is considered to be 'unknown'. It is still imported, + * but is excluded from any further post-processing. + */ + aiTextureType_UNKNOWN = 18, + /** PBR Material Modifiers * Some modern renderers have further PBR modifiers that may be overlaid * on top of the 'base' PBR materials for additional realism. @@ -318,20 +326,20 @@ enum aiTextureType { */ aiTextureType_TRANSMISSION = 21, - /** Unknown texture - * - * A texture reference that does not match any of the definitions - * above is considered to be 'unknown'. It is still imported, - * but is excluded from any further post-processing. - */ - aiTextureType_UNKNOWN = 18, + /** + * Maya material declarations + */ + aiTextureType_MAYA_BASE = 22, + aiTextureType_MAYA_SPECULAR = 23, + aiTextureType_MAYA_SPECULAR_COLOR = 24, + aiTextureType_MAYA_SPECULAR_ROUGHNESS = 25, #ifndef SWIG _aiTextureType_Force32Bit = INT_MAX #endif }; -#define AI_TEXTURE_TYPE_MAX aiTextureType_TRANSMISSION +#define AI_TEXTURE_TYPE_MAX aiTextureType_MAYA_SPECULAR_ROUGHNESS // ------------------------------------------------------------------------------- /** diff --git a/include/assimp/module.modulemap b/include/assimp/module.modulemap new file mode 100644 index 000000000..b29725bfc --- /dev/null +++ b/include/assimp/module.modulemap @@ -0,0 +1,33 @@ +// Export headers for Swift (iOS) +module libassimp { + header "ColladaMetaData.h" + header "GltfMaterial.h" + header "ObjMaterial.h" + header "anim.h" + header "camera.h" + header "cexport.h" + header "cfileio.h" + header "cimport.h" + header "color4.h" + header "commonMetaData.h" + header "config.h" + header "defs.h" + header "importerdesc.h" + header "light.h" + header "material.h" + header "matrix3x3.h" + header "matrix4x4.h" + header "mesh.h" + header "metadata.h" + header "pbrmaterial.h" + header "postprocess.h" + header "quaternion.h" + header "revision.h" + header "scene.h" + header "texture.h" + header "types.h" + header "vector2.h" + header "vector3.h" + header "version.h" + export * +} diff --git a/include/assimp/scene.h b/include/assimp/scene.h index 9137a856c..f3701d600 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -401,8 +401,9 @@ struct ASSIMP_API aiScene { //! Returns a short filename from a full path static const char* GetShortFilename(const char* filename) { const char* lastSlash = strrchr(filename, '/'); - if (lastSlash == nullptr) { - lastSlash = strrchr(filename, '\\'); + const char* lastBackSlash = strrchr(filename, '\\'); + if (lastSlash < lastBackSlash) { + lastSlash = lastBackSlash; } const char* shortFilename = lastSlash != nullptr ? lastSlash + 1 : filename; return shortFilename; diff --git a/port/PyAssimp/pyassimp/structs.py b/port/PyAssimp/pyassimp/structs.py index d442df9fb..e34ddd800 100644 --- a/port/PyAssimp/pyassimp/structs.py +++ b/port/PyAssimp/pyassimp/structs.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_double, c_ubyte, c_size_t, c_uint32 +from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_double, c_ubyte, c_size_t, c_uint32, c_int class Vector2D(Structure): @@ -78,7 +78,7 @@ class String(Structure): # the number of bytes from the beginning of the string to its end. ("length", c_uint32), - # String buffer. Size limit is MAXLEN + # String buffer. Size limit is AI_MAXLEN ("data", c_char*AI_MAXLEN), ] @@ -1010,6 +1010,54 @@ class Animation(Structure): ] +class SkeletonBone(Structure): + """ + See 'mesh.h' for details + """ + _fields_ = [ + # The parent bone index, is -1 one if this bone represents the root bone. + ("mParent", c_int), + + # The number of weights + ("mNumnWeights", c_uint), + + # The mesh index, which will get influenced by the weight + ("mMeshId", POINTER(Mesh)), + + # The influence weights of this bone, by vertex index. + ("mWeights", POINTER(VertexWeight)), + + # Matrix that transforms from bone space to mesh space in bind pose. + # + # This matrix describes the position of the mesh + # in the local space of this bone when the skeleton was bound. + # Thus it can be used directly to determine a desired vertex position, + # given the world-space transform of the bone when animated, + # and the position of the vertex in mesh space. + # + # It is sometimes called an inverse-bind matrix, + # or inverse bind pose matrix + ("mOffsetMatrix", Matrix4x4), + + # Matrix that transforms the locale bone in bind pose. + ("mLocalMatrix", Matrix4x4) + ] + +class Skeleton(Structure): + """ + See 'mesh.h' for details + """ + _fields_ = [ + # Name + ("mName", String), + + # Number of bones + ("mNumBones", c_uint), + + # Bones + ("mBones", POINTER(POINTER(SkeletonBone))) + ] + class ExportDataBlob(Structure): """ See 'cexport.h' for details. @@ -1131,6 +1179,15 @@ class Scene(Structure): # can be used to store format-specific metadata as well. ("mMetadata", POINTER(Metadata)), + # The name of the scene itself + ("mName", String), + + # Number of skeletons + ("mNumSkeletons", c_uint), + + # Skeletons + ("mSkeletons", POINTER(POINTER(Skeleton))), + # Internal data, do not touch ("mPrivate", POINTER(c_char)), ] diff --git a/port/iOS/README.md b/port/iOS/README.md index ca5632a1f..7204694a9 100644 --- a/port/iOS/README.md +++ b/port/iOS/README.md @@ -1,7 +1,13 @@ # assimp for iOS (deployment target 6.0+, 32/64bit) -Builds assimp libraries for several iOS CPU architectures at once, and outputs a fat binary from the result. +### Requirements +- cmake +- pkg-config + +Note: all these packages can be installed with [brew](https://brew.sh) + +Builds assimp libraries for several iOS CPU architectures at once, and outputs a fat binary / XCFramework from the result. Run the **build.sh** script from the ```./port/iOS/``` directory. See **./build.sh --help** for information about command line options. @@ -15,11 +21,11 @@ shadeds-Mac:iOS arul$ ./build.sh --help Example: ```bash cd ./port/iOS/ -./build.sh --stdlib=libc++ --archs="armv7 arm64 i386" +./build.sh --stdlib=libc++ --archs="arm64 x86_64" --no-fat --min-version="16.0" ``` Supported architectures/devices: -### Simulator +### Simulator [CPU Architectures](https://docs.elementscompiler.com/Platforms/Cocoa/CpuArchitectures/) - i386 - x86_64 diff --git a/port/iOS/build.sh b/port/iOS/build.sh index 64e564848..39df1e3d0 100755 --- a/port/iOS/build.sh +++ b/port/iOS/build.sh @@ -76,7 +76,7 @@ build_arch() rm CMakeCache.txt - CMAKE_CLI_INPUT="-DCMAKE_C_COMPILER=$CMAKE_C_COMPILER -DCMAKE_CXX_COMPILER=$CMAKE_CXX_COMPILER -DCMAKE_TOOLCHAIN_FILE=./port/iOS/IPHONEOS_$(echo $1 | tr '[:lower:]' '[:upper:]')_TOOLCHAIN.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS" + CMAKE_CLI_INPUT="-DCMAKE_C_COMPILER=$CMAKE_C_COMPILER -DCMAKE_CXX_COMPILER=$CMAKE_CXX_COMPILER -DCMAKE_TOOLCHAIN_FILE=./port/iOS/IPHONEOS_$(echo $1 | tr '[:lower:]' '[:upper:]')_TOOLCHAIN.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DASSIMP_BUILD_ZLIB=ON" echo "[!] Running CMake with -G 'Unix Makefiles' $CMAKE_CLI_INPUT" @@ -102,6 +102,7 @@ CPP_STD_LIB=${CPP_STD_LIB_LIST[0]} CPP_STD=${CPP_STD_LIST[0]} DEPLOY_ARCHS=${BUILD_ARCHS_ALL[*]} DEPLOY_FAT=1 +DEPLOY_XCFramework=1 for i in "$@"; do case $i in @@ -117,6 +118,11 @@ for i in "$@"; do DEPLOY_ARCHS=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` echo "[!] Selecting architectures: $DEPLOY_ARCHS" ;; + --min-version=*) + MIN_IOS_VERSION=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + IOS_SDK_TARGET=$MIN_IOS_VERSION + echo "[!] Selecting minimum iOS version: $MIN_IOS_VERSION" + ;; --debug) BUILD_TYPE=Debug echo "[!] Selecting build type: Debug" @@ -129,11 +135,17 @@ for i in "$@"; do DEPLOY_FAT=0 echo "[!] Fat binary will not be created." ;; + --no-xcframework) + DEPLOY_XCFramework=0 + echo "[!] XCFramework will not be created." + ;; -h|--help) echo " - don't build fat library (--no-fat)." + echo " - don't build XCFramework (--no-xcframework)." echo " - Include debug information and symbols, no compiler optimizations (--debug)." echo " - generate dynamic libraries rather than static ones (--shared-lib)." echo " - supported architectures (--archs): $(echo $(join , ${BUILD_ARCHS_ALL[*]}) | sed 's/,/, /g')" + echo " - minimum iOS version (--min-version): 16.0" echo " - supported C++ STD libs (--stdlib): $(echo $(join , ${CPP_STD_LIB_LIST[*]}) | sed 's/,/, /g')" echo " - supported C++ standards (--std): $(echo $(join , ${CPP_STD_LIST[*]}) | sed 's/,/, /g')" exit @@ -196,3 +208,32 @@ if [[ "$DEPLOY_FAT" -eq 1 ]]; then echo "[!] Done! The fat binaries can be found at $BUILD_DIR" fi + +make_xcframework() +{ + LIB_NAME=$1 + FRAMEWORK_PATH=$BUILD_DIR/$LIB_NAME.xcframework + + ARGS = "" + for ARCH_TARGET in $DEPLOY_ARCHS; do + if [[ "$BUILD_SHARED_LIBS" =~ "ON" ]]; then + ARGS="$ARGS -library $BUILD_DIR/$ARCH_TARGET/$LIB_NAME.dylib -headers ./include " + else + ARGS="$ARGS -library $BUILD_DIR/$ARCH_TARGET/$LIB_NAME.a -headers ./include " + fi + done + + xcodebuild -create-xcframework $ARGS -output $FRAMEWORK_PATH +} + +if [[ "$DEPLOY_XCFramework" -eq 1 ]]; then + echo '[+] Creating XCFramework ...' + + if [[ "$BUILD_TYPE" =~ "Debug" ]]; then + make_xcframework 'libassimpd' + else + make_xcframework 'libassimp' + fi + + echo "[!] Done! The XCFramework can be found at $BUILD_DIR" +fi \ No newline at end of file diff --git a/test/unit/utMaterialSystem.cpp b/test/unit/utMaterialSystem.cpp index 8b1691b3f..4d335a979 100644 --- a/test/unit/utMaterialSystem.cpp +++ b/test/unit/utMaterialSystem.cpp @@ -260,6 +260,10 @@ TEST_F(MaterialSystemTest, testMaterialTextureTypeEnum) { case aiTextureType_METALNESS: case aiTextureType_DIFFUSE_ROUGHNESS: case aiTextureType_AMBIENT_OCCLUSION: + case aiTextureType_MAYA_BASE: + case aiTextureType_MAYA_SPECULAR: + case aiTextureType_MAYA_SPECULAR_COLOR: + case aiTextureType_MAYA_SPECULAR_ROUGHNESS: case aiTextureType_SHEEN: case aiTextureType_CLEARCOAT: case aiTextureType_TRANSMISSION: