Merge branch 'master' into pugi_xml

pull/2966/head
Kim Kulling 2020-09-25 21:00:09 +02:00
commit d6892b3f58
161 changed files with 12572 additions and 1672 deletions

View File

@ -8,30 +8,39 @@ on:
jobs: jobs:
job: job:
name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test name: ${{ matrix.name }}-build-and-test
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang] name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux. # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include: include:
- name: windows-msvc - name: windows-latest-cl.exe
os: windows-latest os: windows-latest
cxx: cl.exe cxx: cl.exe
cc: cl.exe cc: cl.exe
- name: ubuntu-clang - name: ubuntu-latest-clang++
os: ubuntu-latest os: ubuntu-latest
cxx: clang++ cxx: clang++
cc: clang cc: clang
- name: macos-clang - name: macos-latest-clang++
os: macos-latest os: macos-latest
cxx: clang++ cxx: clang++
cc: clang cc: clang
- name: ubuntu-gcc - name: ubuntu-latest-g++
os: ubuntu-latest os: ubuntu-latest
cxx: g++ cxx: g++
cc: gcc cc: gcc
- name: ubuntu-gcc-hunter
os: ubuntu-latest
toolchain: ninja-gcc-cxx17-fpic
- name: macos-clang-hunter
os: macos-latest
toolchain: ninja-clang-cxx17-fpic
- name: windows-msvc-hunter
os: windows-latest
toolchain: ninja-vs-win64-cxx17
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -40,20 +49,75 @@ jobs:
- uses: ilammy/msvc-dev-cmd@v1 - uses: ilammy/msvc-dev-cmd@v1
- uses: lukka/set-shell-env@v1 - name: Set Compiler Environment
if: "!endsWith(matrix.name, 'hunter')"
uses: lukka/set-shell-env@v1
with: with:
CXX: ${{ matrix.cxx }} CXX: ${{ matrix.cxx }}
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
- name: Set Compiler Environment for Hunter on Windows
if: startsWith(matrix.name, 'windows') && endsWith(matrix.name, 'hunter')
uses: lukka/set-shell-env@v1
with:
VS160COMNTOOLS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools
- name: Checkout Hunter toolchains
if: endsWith(matrix.name, 'hunter')
uses: actions/checkout@v2
with:
repository: cpp-pm/polly
path: cmake/polly
- name: Cache DX SDK
id: dxcache
if: contains(matrix.name, 'windows')
uses: actions/cache@v2
with:
path: '${{ github.workspace }}/DX_SDK'
key: ${{ runner.os }}-DX_SDK
restore-keys: |
${{ runner.os }}-DX_SDK
- name: Download DXSetup
if: contains(matrix.name, 'windows') && 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')
id: windows_extra_cmake_args
run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1"
- name: Set Hunter specific CMake arguments
if: contains(matrix.name, 'hunter')
id: hunter_extra_cmake_args
run: echo "::set-output name=args::-DBUILD_SHARED_LIBS=OFF -DASSIMP_HUNTER_ENABLED=ON -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/polly/${{ matrix.toolchain }}.cmake"
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v2 uses: lukka/run-cmake@v2
env:
DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release' cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
buildWithCMakeArgs: '-- -v' buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/' buildDirectory: '${{ github.workspace }}/build/'
- name: Exclude certain tests in Hunter specific builds
if: contains(matrix.name, 'hunter')
id: hunter_extra_test_args
run: echo "::set-output name=args::--gtest_filter=-utOpenGEXImportExport.Importissue1340_EmptyCameraObject:utColladaZaeImportExport.importBlenFromFileTest"
- name: test - name: test
run: cd build/bin && ./unit run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
shell: bash shell: bash
- uses: actions/upload-artifact@v2
if: matrix.name == 'windows-msvc'
with:
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
path: build/bin

View File

@ -35,6 +35,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)
CMAKE_MINIMUM_REQUIRED( VERSION 3.0 ) CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
@ -44,8 +45,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake/HunterGate.cmake") include("cmake/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.23.269.tar.gz"
SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a" SHA1 "64024b7b95b4c86d50ae05b926814448c93a70a0"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
@ -254,7 +255,11 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
SET(LIBSTDC++_LIBRARIES -lstdc++) SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSEIF(MSVC) ELSEIF(MSVC)
# enable multi-core compilation with MSVC # enable multi-core compilation with MSVC
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX ) IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
@ -318,26 +323,27 @@ ENDIF()
IF (ASSIMP_UBSAN) IF (ASSIMP_UBSAN)
MESSAGE(STATUS "Undefined Behavior sanitizer enabled") MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
ENDIF() ENDIF()
INCLUDE (FindPkgMacros) INCLUDE (FindPkgMacros)
INCLUDE (PrecompiledHeader) INCLUDE (PrecompiledHeader)
# If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR), # Set Assimp project output directory variables.
# write the library/executable files to the respective directories in the SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
# source tree. During an out-of-source build, however, do not litter this SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
# directory, since that is probably what the user wanted to avoid. SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" ) # Macro used to set the output directories of a target to the
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" ) # respective Assimp output directories.
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" ) MACRO(TARGET_USE_COMMON_OUTPUT_DIRECTORY target)
ELSE() set_target_properties(${target} PROPERTIES
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib") RUNTIME_OUTPUT_DIRECTORY ${ASSIMP_RUNTIME_OUTPUT_DIRECTORY}
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") LIBRARY_OUTPUT_DIRECTORY ${ASSIMP_LIBRARY_OUTPUT_DIRECTORY}
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") ARCHIVE_OUTPUT_DIRECTORY ${ASSIMP_ARCHIVE_OUTPUT_DIRECTORY}
ENDIF () )
ENDMACRO()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
@ -354,6 +360,34 @@ IF (NOT TARGET uninstall)
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF() ENDIF()
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs)
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
ELSE()
# Cache these to allow the user to override them on non-Unix platforms
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
"Path the built library files are installed to." )
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
"Path the header files are installed to." )
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
"Path the tool executables are installed to." )
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
ENDIF()
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(INCLUDE_INSTALL_DIR "include") set(INCLUDE_INSTALL_DIR "include")
@ -392,34 +426,6 @@ IF(ASSIMP_HUNTER_ENABLED)
DESTINATION "${CONFIG_INSTALL_DIR}" DESTINATION "${CONFIG_INSTALL_DIR}"
) )
ELSE() ELSE()
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs)
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
ELSE()
# Cache these to allow the user to override them on non-Unix platforms
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
"Path the built library files are installed to." )
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
"Path the header files are installed to." )
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
"Path the tool executables are installed to." )
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
ENDIF()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
IF (is_multi_config) IF (is_multi_config)
@ -671,7 +677,8 @@ if(WIN32)
ENDIF() ENDIF()
IF(MSVC_TOOLSET_VERSION) IF(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") SET(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
SET(ASSIMP_MSVC_VERSION ${MCVS_PREFIX})
ELSE() ELSE()
IF(MSVC12) IF(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120") SET(ASSIMP_MSVC_VERSION "vc120")

View File

@ -4,8 +4,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
### Current project status ### ### Current project status ###
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg) ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
[![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
<a href="https://scan.coverity.com/projects/5607"> <a href="https://scan.coverity.com/projects/5607">
<img alt="Coverity Scan Build Status" <img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5607/badge.svg"/> src="https://scan.coverity.com/projects/5607/badge.svg"/>
@ -72,7 +70,7 @@ The source code is organized in the following way:
For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format. For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
(CHMs for Windows are included in some release packages and should be located right here in the root folder). (CHMs for Windows are included in some release packages and should be located right here in the root folder).
If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github. If the docs don't solve your problem, ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_ For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2013-2018, Ruslan Baratov # Copyright (c) 2013-2019, Ruslan Baratov
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -60,7 +60,7 @@ option(HUNTER_STATUS_PRINT "Print working status" ON)
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors")
function(hunter_gate_status_print) function(hunter_gate_status_print)
if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
@ -79,9 +79,9 @@ function(hunter_gate_status_debug)
endif() endif()
endfunction() endfunction()
function(hunter_gate_wiki wiki_page) function(hunter_gate_error_page error_page)
message("------------------------------ WIKI -------------------------------") message("------------------------------ ERROR ------------------------------")
message(" ${HUNTER_WIKI}/${wiki_page}") message(" ${HUNTER_ERROR_PAGE}/${error_page}.html")
message("-------------------------------------------------------------------") message("-------------------------------------------------------------------")
message("") message("")
message(FATAL_ERROR "") message(FATAL_ERROR "")
@ -94,14 +94,13 @@ function(hunter_gate_internal_error)
endforeach() endforeach()
message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("") message("")
hunter_gate_wiki("error.internal") hunter_gate_error_page("error.internal")
endfunction() endfunction()
function(hunter_gate_fatal_error) function(hunter_gate_fatal_error)
cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) if("${hunter_ERROR_PAGE}" STREQUAL "")
if(have_no_wiki) hunter_gate_internal_error("Expected ERROR_PAGE")
hunter_gate_internal_error("Expected wiki")
endif() endif()
message("") message("")
foreach(x ${hunter_UNPARSED_ARGUMENTS}) foreach(x ${hunter_UNPARSED_ARGUMENTS})
@ -109,11 +108,11 @@ function(hunter_gate_fatal_error)
endforeach() endforeach()
message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("") message("")
hunter_gate_wiki("${hunter_WIKI}") hunter_gate_error_page("${hunter_ERROR_PAGE}")
endfunction() endfunction()
function(hunter_gate_user_error) function(hunter_gate_user_error)
hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data")
endfunction() endfunction()
function(hunter_gate_self root version sha1 result) function(hunter_gate_self root version sha1 result)
@ -195,7 +194,7 @@ function(hunter_gate_detect_root)
hunter_gate_fatal_error( hunter_gate_fatal_error(
"Can't detect HUNTER_ROOT" "Can't detect HUNTER_ROOT"
WIKI "error.detect.hunter.root" ERROR_PAGE "error.detect.hunter.root"
) )
endfunction() endfunction()
@ -214,7 +213,7 @@ function(hunter_gate_download dir)
"Settings:" "Settings:"
" HUNTER_ROOT: ${HUNTER_GATE_ROOT}" " HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
" HUNTER_SHA1: ${HUNTER_GATE_SHA1}" " HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
WIKI "error.run.install" ERROR_PAGE "error.run.install"
) )
endif() endif()
string(COMPARE EQUAL "${dir}" "" is_bad) string(COMPARE EQUAL "${dir}" "" is_bad)
@ -400,7 +399,7 @@ macro(HunterGate)
hunter_gate_fatal_error( hunter_gate_fatal_error(
"Please set HunterGate *before* 'project' command. " "Please set HunterGate *before* 'project' command. "
"Detected project: ${PROJECT_NAME}" "Detected project: ${PROJECT_NAME}"
WIKI "error.huntergate.before.project" ERROR_PAGE "error.huntergate.before.project"
) )
endif() endif()
@ -470,7 +469,7 @@ macro(HunterGate)
"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
"(Use at your own risk!)" "(Use at your own risk!)"
WIKI "error.spaces.in.hunter.root" ERROR_PAGE "error.spaces.in.hunter.root"
) )
endif() endif()
endif() endif()

View File

@ -2,7 +2,7 @@
find_package(RapidJSON CONFIG REQUIRED) find_package(RapidJSON CONFIG REQUIRED)
find_package(ZLIB CONFIG REQUIRED) find_package(ZLIB CONFIG REQUIRED)
find_package(utf8 CONFIG REQUIRED) find_package(utf8cpp CONFIG REQUIRED)
find_package(irrXML CONFIG REQUIRED) find_package(irrXML CONFIG REQUIRED)
find_package(minizip CONFIG REQUIRED) find_package(minizip CONFIG REQUIRED)
find_package(openddlparser CONFIG REQUIRED) find_package(openddlparser CONFIG REQUIRED)

View File

@ -296,6 +296,12 @@ void Discreet3DSExporter::WriteMaterials() {
WriteColor(color); WriteColor(color);
} }
float f;
if (mat.Get(AI_MATKEY_OPACITY, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TRANSPARENCY);
WritePercentChunk(1.0f - f);
}
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
WriteColor(color); WriteColor(color);
@ -333,7 +339,6 @@ void Discreet3DSExporter::WriteMaterials() {
writer.PutU2(static_cast<uint16_t>(shading_mode_out)); writer.PutU2(static_cast<uint16_t>(shading_mode_out));
} }
float f;
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS); ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
WritePercentChunk(f); WritePercentChunk(f);

View File

@ -321,9 +321,10 @@ public:
struct Face : public FaceWithSmoothingGroup { struct Face : public FaceWithSmoothingGroup {
}; };
#ifdef _WIN32 #ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4315) #pragma warning(disable : 4315)
#endif #endif // _MSC_VER
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure representing a texture */ /** Helper structure representing a texture */
@ -412,6 +413,10 @@ struct Texture {
#include <assimp/Compiler/poppack1.h> #include <assimp/Compiler/poppack1.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure representing a 3ds material */ /** Helper structure representing a 3ds material */
struct Material { struct Material {

View File

@ -147,7 +147,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
// We should have at least one chunk // We should have at least one chunk
if (theStream.GetRemainingSize() < 16) { if (theStream.GetRemainingSize() < 16) {
throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile);
} }
this->stream = &theStream; this->stream = &theStream;
@ -178,7 +178,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
// file. // file.
for (auto &mesh : mScene->mMeshes) { for (auto &mesh : mScene->mMeshes) {
if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) {
throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile); throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile);
} }
CheckIndices(mesh); CheckIndices(mesh);
MakeUnique(mesh); MakeUnique(mesh);

View File

@ -122,7 +122,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mZipArchive() { mZipArchive() {
mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
if (!mZipArchive->isOpen()) { if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile + "."); throw DeadlyImportError("Failed to open file ", rFile, ".");
} }
std::vector<std::string> fileList; std::vector<std::string> fileList;
@ -198,7 +198,7 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
}); });
if (itr == reader.m_relationShips.end()) { if (itr == reader.m_relationShips.end()) {
throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
} }
return (*itr)->target; return (*itr)->target;

View File

@ -471,26 +471,33 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++node->mNumMeshes; ++node->mNumMeshes;
} }
switch ((*it).flags & 0xf) { switch ((*it).GetType()) {
// closed line // closed line
case 0x1: case Surface::ClosedLine:
needMat[idx].first += (unsigned int)(*it).entries.size(); needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u; needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
break; break;
// unclosed line // unclosed line
case 0x2: case Surface::OpenLine:
needMat[idx].first += (unsigned int)(*it).entries.size() - 1; needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u; needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
break; break;
// 0 == polygon, else unknown // triangle strip
default: case Surface::TriangleStrip:
if ((*it).flags & 0xf) { needMat[idx].first += (unsigned int)(*it).entries.size() - 2;
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown"); needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3;
(*it).flags &= ~(0xf); break;
}
default:
// Coerce unknowns to a polygon and warn
ASSIMP_LOG_WARN_F("AC3D: The type flag of a surface is unknown: ", (*it).flags);
(*it).flags &= ~(Surface::Mask);
// fallthrough
// polygon
case Surface::Polygon:
// the number of faces increments by one, the number // the number of faces increments by one, the number
// of vertices by surface.numref. // of vertices by surface.numref.
needMat[idx].first++; needMat[idx].first++;
@ -546,8 +553,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
const Surface &src = *it; const Surface &src = *it;
// closed polygon // closed polygon
unsigned int type = (*it).flags & 0xf; uint8_t type = (*it).GetType();
if (!type) { if (type == Surface::Polygon) {
aiFace &face = *faces++; aiFace &face = *faces++;
face.mNumIndices = (unsigned int)src.entries.size(); face.mNumIndices = (unsigned int)src.entries.size();
if (0 != face.mNumIndices) { if (0 != face.mNumIndices) {
@ -570,13 +577,71 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
} }
} }
} }
} else if (type == Surface::TriangleStrip) {
for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
const Surface::SurfaceEntry &entry1 = src.entries[i];
const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
// skip degenerate triangles
if (object.vertices[entry1.first] == object.vertices[entry2.first] ||
object.vertices[entry1.first] == object.vertices[entry3.first] ||
object.vertices[entry2.first] == object.vertices[entry3.first]) {
mesh->mNumFaces--;
mesh->mNumVertices -= 3;
continue;
}
aiFace &face = *faces++;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = cur++;
face.mIndices[1] = cur++;
face.mIndices[2] = cur++;
if (!(i & 1)) {
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
} else {
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
}
if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
throw DeadlyImportError("AC3D: Invalid number of vertices");
}
*vertices++ = object.vertices[entry3.first] + object.translation;
if (uv) {
uv->x = entry3.second.x;
uv->y = entry3.second.y;
++uv;
}
}
} else { } else {
it2 = (*it).entries.begin(); it2 = (*it).entries.begin();
// either a closed or an unclosed line // either a closed or an unclosed line
unsigned int tmp = (unsigned int)(*it).entries.size(); unsigned int tmp = (unsigned int)(*it).entries.size();
if (0x2 == type) --tmp; if (Surface::OpenLine == type) --tmp;
for (unsigned int m = 0; m < tmp; ++m) { for (unsigned int m = 0; m < tmp; ++m) {
aiFace &face = *faces++; aiFace &face = *faces++;
@ -599,7 +664,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++uv; ++uv;
} }
if (0x1 == type && tmp - 1 == m) { if (Surface::ClosedLine == type && tmp - 1 == m) {
// if this is a closed line repeat its beginning now // if this is a closed line repeat its beginning now
it2 = (*it).entries.begin(); it2 = (*it).entries.begin();
} else } else
@ -697,7 +762,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AC3D file " + pFile + "."); throw DeadlyImportError("Failed to open AC3D file ", pFile, ".");
} }
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer

View File

@ -69,7 +69,10 @@ public:
// Represents an AC3D material // Represents an AC3D material
struct Material { struct Material {
Material() : Material() :
rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {} rgb(0.6f, 0.6f, 0.6f),
spec(1.f, 1.f, 1.f),
shin(0.f),
trans(0.f) {}
// base color of the material // base color of the material
aiColor3D rgb; aiColor3D rgb;
@ -96,18 +99,43 @@ public:
// Represents an AC3D surface // Represents an AC3D surface
struct Surface { struct Surface {
Surface() : Surface() :
mat(0), flags(0) {} mat(0),
flags(0) {}
unsigned int mat, flags; unsigned int mat, flags;
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry; typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
std::vector<SurfaceEntry> entries; std::vector<SurfaceEntry> entries;
// Type is low nibble of flags
enum Type : uint8_t {
Polygon = 0x0,
ClosedLine = 0x1,
OpenLine = 0x2,
TriangleStrip = 0x4, // ACC extension (TORCS and Speed Dreams)
Mask = 0xf,
};
inline constexpr uint8_t GetType() const { return (flags & Mask); }
}; };
// Represents an AC3D object // Represents an AC3D object
struct Object { struct Object {
Object() : Object() :
type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {} type(World),
name(""),
children(),
texture(""),
texRepeat(1.f, 1.f),
texOffset(0.0f, 0.0f),
rotation(),
translation(),
vertices(),
surfaces(),
numRefs(0),
subDiv(0),
crease() {}
// Type description // Type description
enum Type { enum Type {

View File

@ -170,7 +170,7 @@ void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const s
} }
void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
throw DeadlyImportError("Not found node with name \"" + pID + "\"."); throw DeadlyImportError("Not found node with name \"", pID, "\".");
} }
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
@ -267,7 +267,7 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AMF file " + pFile + "."); throw DeadlyImportError("Failed to open AMF file ", pFile, ".");
} }
mXmlParser = new XmlParser(); mXmlParser = new XmlParser();
@ -409,7 +409,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
bool read_flag[6] = { false, false, false, false, false, false }; bool read_flag[6] = { false, false, false, false, false, false };
std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "deltax") { if (currentName == "deltax") {
read_flag[0] = true; read_flag[0] = true;
als.Delta.x = (ai_real)std::atof(currentNode.value()); als.Delta.x = (ai_real)std::atof(currentNode.value());
@ -446,8 +446,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Object(XmlNode &node) { void AMFImporter::ParseNode_Object(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
AMFNodeElementBase *ne(nullptr);
// Read attributes for node <object>. // Read attributes for node <object>.
std::string id = node.attribute("id").as_string(); std::string id = node.attribute("id").as_string();
@ -466,7 +465,7 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
if (!node.empty()) { if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "color") { if (currentName == "color") {
ParseNode_Color(currentNode); ParseNode_Color(currentNode);
col_read = true; col_read = true;
@ -523,9 +522,8 @@ bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool p
return true; return true;
} }
if (!extension.length() || pCheckSig) { if (extension.empty() || pCheckSig) {
const char *tokens[] = { "<amf" }; const char *tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }

View File

@ -137,7 +137,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open ASE file " + pFile + "."); throw DeadlyImportError("Failed to open ASE file ", pFile, ".");
} }
// Allocate storage and copy the contents of the file to a memory buffer // Allocate storage and copy the contents of the file to a memory buffer

View File

@ -60,10 +60,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <time.h> #include <time.h>
#ifdef _WIN32 #if _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4706) #pragma warning(disable : 4706)
#endif // _WIN32 #endif // _MSC_VER
namespace Assimp { namespace Assimp {
@ -825,8 +825,8 @@ void DumpSceneToAssbin(
AssbinFileWriter fileWriter(shortened, compressed); AssbinFileWriter fileWriter(shortened, compressed);
fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
} }
#ifdef _WIN32 #if _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -8,9 +8,9 @@ For details, see http://sourceforge.net/projects/libb64
#ifndef BASE64_CENCODE_H #ifndef BASE64_CENCODE_H
#define BASE64_CENCODE_H #define BASE64_CENCODE_H
#ifdef _WIN32 #ifdef _MSC_VER
#pragma warning(disable : 4127 ) #pragma warning(disable : 4127 )
#endif // _WIN32 #endif // _MSC_VER
typedef enum typedef enum
{ {

View File

@ -119,7 +119,7 @@ void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open B3D file " + pFile + "."); throw DeadlyImportError("Failed to open B3D file ", pFile, ".");
} }
// check whether the .b3d file is large enough to contain // check whether the .b3d file is large enough to contain
@ -147,7 +147,7 @@ AI_WONT_RETURN void B3DImporter::Fail(string str) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str); ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
#endif #endif
throw DeadlyImportError("B3D Importer - error in B3D file data: " + str); throw DeadlyImportError("B3D Importer - error in B3D file data: ", str);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -71,6 +71,13 @@ static const aiImporterDesc desc = {
"bvh" "bvh"
}; };
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
template<typename... T>
AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) {
throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BVHLoader::BVHLoader() : BVHLoader::BVHLoader() :
@ -118,7 +125,7 @@ void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst
// read file into memory // read file into memory
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open file " + pFile + "."); throw DeadlyImportError("Failed to open file ", pFile, ".");
} }
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
@ -176,12 +183,12 @@ aiNode *BVHLoader::ReadNode() {
// first token is name // first token is name
std::string nodeName = GetNextToken(); std::string nodeName = GetNextToken();
if (nodeName.empty() || nodeName == "{") if (nodeName.empty() || nodeName == "{")
ThrowException(format() << "Expected node name, but found \"" << nodeName << "\"."); ThrowException("Expected node name, but found \"", nodeName, "\".");
// then an opening brace should follow // then an opening brace should follow
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node // Create a node
aiNode *node = new aiNode(nodeName); aiNode *node = new aiNode(nodeName);
@ -211,7 +218,7 @@ aiNode *BVHLoader::ReadNode() {
siteToken.clear(); siteToken.clear();
siteToken = GetNextToken(); siteToken = GetNextToken();
if (siteToken != "Site") if (siteToken != "Site")
ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"."); ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\".");
aiNode *child = ReadEndSite(nodeName); aiNode *child = ReadEndSite(nodeName);
child->mParent = node; child->mParent = node;
@ -221,7 +228,7 @@ aiNode *BVHLoader::ReadNode() {
break; break;
} else { } else {
// everything else is a parse error // everything else is a parse error
ThrowException(format() << "Unknown keyword \"" << token << "\"."); ThrowException("Unknown keyword \"", token, "\".");
} }
} }
@ -242,7 +249,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
// check opening brace // check opening brace
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node // Create a node
aiNode *node = new aiNode("EndSite_" + pParentName); aiNode *node = new aiNode("EndSite_" + pParentName);
@ -261,7 +268,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
break; break;
} else { } else {
// everything else is a parse error // everything else is a parse error
ThrowException(format() << "Unknown keyword \"" << token << "\"."); ThrowException("Unknown keyword \"", token, "\".");
} }
} }
@ -307,7 +314,7 @@ void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
else if (channelToken == "Zrotation") else if (channelToken == "Zrotation")
pNode.mChannels.push_back(Channel_RotationZ); pNode.mChannels.push_back(Channel_RotationZ);
else else
ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\"."); ThrowException("Invalid channel specifier \"", channelToken, "\".");
} }
} }
@ -317,7 +324,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
// Read number of frames // Read number of frames
std::string tokenFrames = GetNextToken(); std::string tokenFrames = GetNextToken();
if (tokenFrames != "Frames:") if (tokenFrames != "Frames:")
ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\".");
float numFramesFloat = GetNextTokenAsFloat(); float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int)numFramesFloat; mAnimNumFrames = (unsigned int)numFramesFloat;
@ -326,7 +333,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
std::string tokenDuration1 = GetNextToken(); std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken(); std::string tokenDuration2 = GetNextToken();
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"."); ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\".");
mAnimTickDuration = GetNextTokenAsFloat(); mAnimTickDuration = GetNextTokenAsFloat();
@ -393,17 +400,11 @@ float BVHLoader::GetNextTokenAsFloat() {
ctoken = fast_atoreal_move<float>(ctoken, result); ctoken = fast_atoreal_move<float>(ctoken, result);
if (ctoken != token.c_str() + token.length()) if (ctoken != token.c_str() + token.length())
ThrowException(format() << "Expected a floating point number, but found \"" << token << "\"."); ThrowException("Expected a floating point number, but found \"", token, "\".");
return result; return result;
} }
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs an animation for the motion data and stores it in the given scene // Constructs an animation for the motion data and stores it in the given scene
void BVHLoader::CreateAnimation(aiScene *pScene) { void BVHLoader::CreateAnimation(aiScene *pScene) {
@ -453,7 +454,7 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel); std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
if (mapIter == channelMap.end()) if (mapIter == channelMap.end())
throw DeadlyImportError("Missing position channel in node " + nodeName); throw DeadlyImportError("Missing position channel in node ", nodeName);
else { else {
int channelIdx = mapIter->second; int channelIdx = mapIter->second;
switch (channel) { switch (channel) {

View File

@ -134,7 +134,8 @@ protected:
float GetNextTokenAsFloat(); float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX; template<typename... T>
AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX;
/** Constructs an animation for the motion data and stores it in the given scene */ /** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation(aiScene *pScene); void CreateAnimation(aiScene *pScene);

View File

@ -149,7 +149,7 @@ bool isValidCustomDataType(const int cdtype) {
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) { bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) { if (!isValidCustomDataType(cdtype)) {
throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index")); throw Error("CustomData.type ", cdtype, " out of index");
} }
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];

View File

@ -130,9 +130,7 @@ void DNAParser::Parse() {
uint16_t n = stream.GetI2(); uint16_t n = stream.GetI2();
if (n >= types.size()) { if (n >= types.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)");
"BlenderDNA: Invalid type index in structure name", n,
" (there are only ", types.size(), " entries)"));
} }
// maintain separate indexes // maintain separate indexes
@ -151,9 +149,7 @@ void DNAParser::Parse() {
uint16_t j = stream.GetI2(); uint16_t j = stream.GetI2();
if (j >= types.size()) { if (j >= types.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)");
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"));
} }
s.fields.push_back(Field()); s.fields.push_back(Field());
Field &f = s.fields.back(); Field &f = s.fields.back();
@ -164,9 +160,7 @@ void DNAParser::Parse() {
j = stream.GetI2(); j = stream.GetI2();
if (j >= names.size()) { if (j >= names.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)");
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"));
} }
f.name = names[j]; f.name = names[j];
@ -188,9 +182,7 @@ void DNAParser::Parse() {
if (*f.name.rbegin() == ']') { if (*f.name.rbegin() == ']') {
const std::string::size_type rb = f.name.find('['); const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) { if (rb == std::string::npos) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name);
"BlenderDNA: Encountered invalid array declaration ",
f.name));
} }
f.flags |= FieldFlag_Array; f.flags |= FieldFlag_Array;

View File

@ -83,9 +83,10 @@ class ObjectCache;
* ancestry. */ * ancestry. */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct Error : DeadlyImportError { struct Error : DeadlyImportError {
Error(const std::string &s) : template<typename... T>
DeadlyImportError(s) { explicit Error(T&&... args)
// empty : DeadlyImportError(args...)
{
} }
}; };

View File

@ -57,9 +57,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
{ {
std::map<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error((Formatter::format(), throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
"BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
));
} }
return fields[(*it).second]; return fields[(*it).second];
@ -76,9 +74,7 @@ const Field* Structure :: Get (const std::string& ss) const
const Field& Structure :: operator [] (const size_t i) const const Field& Structure :: operator [] (const size_t i) const
{ {
if (i >= fields.size()) { if (i >= fields.size()) {
throw Error((Formatter::format(), throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`");
"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
));
} }
return fields[i]; return fields[i];
@ -109,9 +105,7 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab
// is the input actually an array? // is the input actually an array?
if (!(f.flags & FieldFlag_Array)) { if (!(f.flags & FieldFlag_Array)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
this->name,"` ought to be an array of size ",M
));
} }
db.reader->IncPtr(f.offset); db.reader->IncPtr(f.offset);
@ -148,9 +142,9 @@ void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileD
// is the input actually an array? // is the input actually an array?
if (!(f.flags & FieldFlag_Array)) { if (!(f.flags & FieldFlag_Array)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M,"*",N this->name,"` ought to be an array of size ",M,"*",N
)); );
} }
db.reader->IncPtr(f.offset); db.reader->IncPtr(f.offset);
@ -195,8 +189,8 @@ bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabas
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer")); this->name,"` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -241,8 +235,8 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
#ifdef _DEBUG #ifdef _DEBUG
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array")); this->name,"` ought to be a pointer AND an array");
} }
#endif // _DEBUG #endif // _DEBUG
@ -322,8 +316,8 @@ bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, con
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `", throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer")); this->name, "` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -369,8 +363,8 @@ bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `", throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer")); this->name, "` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -428,9 +422,9 @@ bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const Fil
// and check if it matches the type which we expect. // and check if it matches the type which we expect.
const Structure& ss = db.dna[block->dna_index]; const Structure& ss = db.dna[block->dna_index];
if (ss != s) { if (ss != s) {
throw Error((Formatter::format(),"Expected target to be of type `",s.name, throw Error("Expected target to be of type `",s.name,
"` but seemingly it is a `",ss.name,"` instead" "` but seemingly it is a `",ss.name,"` instead"
)); );
} }
// try to retrieve the object from the cache // try to retrieve the object from the cache
@ -614,16 +608,14 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
if (it == db.entries.end()) { if (it == db.entries.end()) {
// this is crucial, pointers may not be invalid. // this is crucial, pointers may not be invalid.
// this is either a corrupted file or an attempted attack. // this is either a corrupted file or an attempted attack.
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", throw DeadlyImportError("Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range" std::hex,ptrval.val,", no file block falls into this address range");
));
} }
if (ptrval.val >= (*it).address.val + (*it).size) { if (ptrval.val >= (*it).address.val + (*it).size) {
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", throw DeadlyImportError("Failure resolving pointer 0x",
std::hex,ptrval.val,", nearest file block starting at 0x", std::hex,ptrval.val,", nearest file block starting at 0x",
(*it).address.val," ends at 0x", (*it).address.val," ends at 0x",
(*it).address.val + (*it).size (*it).address.val + (*it).size);
));
} }
return &*it; return &*it;
} }
@ -676,7 +668,7 @@ template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,
out = static_cast<T>(db.reader->GetF8()); out = static_cast<T>(db.reader->GetF8());
} }
else { else {
throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name); throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
} }
} }
@ -784,9 +776,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
{ {
std::map<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error((Formatter::format(), throw Error("BlendDNA: Did not find a structure named `",ss,"`");
"BlendDNA: Did not find a structure named `",ss,"`"
));
} }
return structures[(*it).second]; return structures[(*it).second];
@ -803,9 +793,7 @@ const Structure* DNA :: Get (const std::string& ss) const
const Structure& DNA :: operator [] (const size_t i) const const Structure& DNA :: operator [] (const size_t i) const
{ {
if (i >= structures.size()) { if (i >= structures.size()) {
throw Error((Formatter::format(), throw Error("BlendDNA: There is no structure with index `",i,"`");
"BlendDNA: There is no structure with index `",i,"`"
));
} }
return structures[i]; return structures[i];

View File

@ -748,9 +748,8 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) { void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
ai_assert(dt); ai_assert(dt);
if (strcmp(dt->dna_type, check)) { if (strcmp(dt->dna_type, check)) {
ThrowException((format(), ThrowException("Expected object at ", std::hex, dt, " to be of type `", check,
"Expected object at ", std::hex, dt, " to be of type `", check, "`, but it claims to be a `", dt->dna_type, "`instead");
"`, but it claims to be a `", dt->dna_type, "`instead"));
} }
} }

View File

@ -386,7 +386,14 @@ void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& p
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
{ {
#if defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Winvalid-offsetof"
#endif // __clang__
unsigned int pointOffset = offsetof( PointP2T, point2D ); unsigned int pointOffset = offsetof( PointP2T, point2D );
#if defined __clang__
# pragma clang diagnostic pop
#endif
PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset ); PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) ) if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
{ {
@ -394,7 +401,6 @@ inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& poi
} }
return pointStruct; return pointStruct;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
{ {

View File

@ -125,7 +125,7 @@ void COBImporter::SetupProperties(const Importer * /*pImp*/) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) { /*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
throw DeadlyImportError("COB: " + msg); throw DeadlyImportError("COB: ", msg);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -128,7 +128,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == nullptr) { if( file.get() == nullptr) {
throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); throw DeadlyImportError( "Failed to open CSM file ", pFile, ".");
} }
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer

View File

@ -1245,7 +1245,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// time count and value count must match // time count and value count must match
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
if (e.mTimeAccessor->mCount > 0) { if (e.mTimeAccessor->mCount > 0) {
// find bounding times // find bounding times
@ -1462,7 +1462,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
for (size_t a = 0; a < morphAnims.size(); ++a) { for (size_t a = 0; a < morphAnims.size(); ++a) {
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
} }
anim->mTicksPerSecond = 1; anim->mTicksPerSecond = 1000.0;
mAnims.push_back(anim); mAnims.push_back(anim);
} }
} }

View File

@ -101,24 +101,24 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
std::string dae_filename = ReadZaeManifest(*zip_archive); std::string dae_filename = ReadZaeManifest(*zip_archive);
if (dae_filename.empty()) { if (dae_filename.empty()) {
ThrowException(std::string("Invalid ZAE")); throw DeadlyImportError("Invalid ZAE");
} }
daefile.reset(zip_archive->Open(dae_filename.c_str())); daefile.reset(zip_archive->Open(dae_filename.c_str()));
if (daefile == nullptr) { if (daefile == nullptr) {
ThrowException(std::string("Invalid ZAE manifest: '") + std::string(dae_filename) + std::string("' is missing")); throw DeadlyImportError("Invalid ZAE manifest: '", dae_filename, "' is missing");
} }
} else { } else {
// attempt to open the file directly // attempt to open the file directly
daefile.reset(pIOHandler->Open(pFile)); daefile.reset(pIOHandler->Open(pFile));
if (daefile.get() == nullptr) { if (daefile.get() == nullptr) {
throw DeadlyImportError("Failed to open file '" + pFile + "'."); throw DeadlyImportError("Failed to open file '", pFile, "'.");
} }
} }
// generate a XML reader for it // generate a XML reader for it
if (!mXmlParser.parse(daefile.get())) { if (!mXmlParser.parse(daefile.get())) {
ThrowException("Unable to read file, malformed XML"); throw DeadlyImportError("Unable to read file, malformed XML");
} }
// start reading // start reading
XmlNode node = mXmlParser.getRootNode(); XmlNode node = mXmlParser.getRootNode();
@ -391,7 +391,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
if (url) { if (url) {
const std::string urlName = url.as_string(); const std::string urlName = url.as_string();
if (urlName[0] != '#') { if (urlName[0] != '#') {
ThrowException("Unknown reference format"); throw DeadlyImportError("Unknown reference format");
} }
clip.second.push_back(url.as_string()); clip.second.push_back(url.as_string());
} }
@ -430,7 +430,6 @@ void ColladaParser::PostProcessRootAnimations() {
} }
Animation temp; Animation temp;
for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) { for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) {
std::string clipName = it->first; std::string clipName = it->first;
@ -568,8 +567,9 @@ void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChanne
if (XmlParser::hasAttribute(currentNode, "source")) { if (XmlParser::hasAttribute(currentNode, "source")) {
XmlParser::getStdStrAttribute(currentNode, "source", sourceAttr); XmlParser::getStdStrAttribute(currentNode, "source", sourceAttr);
const char *source = sourceAttr.c_str(); const char *source = sourceAttr.c_str();
if (source[0] != '#') if (source[0] != '#') {
ThrowException("Unsupported URL format"); throw DeadlyImportError("Unsupported URL format");
}
source++; source++;
if (semantic == "INPUT") if (semantic == "INPUT")
@ -671,7 +671,7 @@ void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pCo
const char *attrSemantic = currentNode.attribute("semantic").as_string(); const char *attrSemantic = currentNode.attribute("semantic").as_string();
const char *attrSource = currentNode.attribute("source").as_string(); const char *attrSource = currentNode.attribute("source").as_string();
if (attrSource[0] != '#') { if (attrSource[0] != '#') {
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <joints> data <input> element"); throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <joints> data <input> element");
} }
++attrSource; ++attrSource;
// parse source URL to corresponding source // parse source URL to corresponding source
@ -680,7 +680,7 @@ void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pCo
} else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) { } else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
pController.mJointOffsetMatrixSource = attrSource; pController.mJointOffsetMatrixSource = attrSource;
} else { } else {
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <joints> data <input> element"); throw DeadlyImportError("Unknown semantic \"" , attrSemantic , "\" in <joints> data <input> element");
} }
} }
} }
@ -704,7 +704,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
// local URLS always start with a '#'. We don't support global URLs // local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#') { if (attrSource[0] != '#') {
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <vertex_weights> data <input> element"); throw DeadlyImportError( "Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
} }
channel.mAccessor = attrSource + 1; channel.mAccessor = attrSource + 1;
@ -714,14 +714,14 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
} else if (strcmp(attrSemantic, "WEIGHT") == 0) { } else if (strcmp(attrSemantic, "WEIGHT") == 0) {
pController.mWeightInputWeights = channel; pController.mWeightInputWeights = channel;
} else { } else {
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <vertex_weights> data <input> element"); throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
} }
} else if (currentName == "vcount" && vertexCount > 0) { } else if (currentName == "vcount" && vertexCount > 0) {
const char *text = currentNode.value(); const char *text = currentNode.value();
size_t numWeights = 0; size_t numWeights = 0;
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) { for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
if (*text == 0) { if (*text == 0) {
ThrowException("Out of data while reading <vcount>"); throw DeadlyImportError("Out of data while reading <vcount>");
} }
*it = strtoul10(text, &text); *it = strtoul10(text, &text);
@ -737,12 +737,13 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
const char *text = stdText.c_str(); const char *text = stdText.c_str();
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) { for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
if (text == 0) { if (text == 0) {
ThrowException("Out of data while reading <vertex_weights>"); throw DeadlyImportError("Out of data while reading <vertex_weights>");
} }
it->first = strtoul10(text, &text); it->first = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text); SkipSpacesAndLineEnd(&text);
if (*text == 0) if (*text == 0) {
ThrowException("Out of data while reading <vertex_weights>"); throw DeadlyImportError("Out of data while reading <vertex_weights>");
}
it->second = strtoul10(text, &text); it->second = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text); SkipSpacesAndLineEnd(&text);
} }
@ -925,7 +926,7 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
if (currentName == "instance_effect") { if (currentName == "instance_effect") {
const char *url = currentNode.attribute("url").as_string(); const char *url = currentNode.attribute("url").as_string();
if (url[0] != '#') { if (url[0] != '#') {
ThrowException("Unknown reference format"); throw DeadlyImportError("Unknown reference format");
} }
pMaterial.mEffect = url + 1; pMaterial.mEffect = url + 1;
} }
@ -1300,8 +1301,9 @@ void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam)
// surface ID is given inside <instance_image> tags // surface ID is given inside <instance_image> tags
std::string url; std::string url;
XmlParser::getStdStrAttribute(currentNode, "url", url); XmlParser::getStdStrAttribute(currentNode, "url", url);
if (url[0] != '#') if (url[0] != '#') {
ThrowException("Unsupported URL format in instance_image"); throw DeadlyImportError("Unsupported URL format in instance_image");
}
pParam.mType = Param_Sampler; pParam.mType = Param_Sampler;
pParam.mReference = url.c_str() + 1; pParam.mReference = url.c_str() + 1;
} }
@ -1426,8 +1428,9 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
std::string s; std::string s;
for (unsigned int a = 0; a < count; a++) { for (unsigned int a = 0; a < count; a++) {
if (*content == 0) if (*content == 0) {
ThrowException("Expected more values while reading IDREF_array contents."); throw DeadlyImportError("Expected more values while reading IDREF_array contents.");
}
s.clear(); s.clear();
while (!IsSpaceOrNewLine(*content)) while (!IsSpaceOrNewLine(*content))
@ -1440,8 +1443,9 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
data.mValues.reserve(count); data.mValues.reserve(count);
for (unsigned int a = 0; a < count; a++) { for (unsigned int a = 0; a < count; a++) {
if (*content == 0) if (*content == 0) {
ThrowException("Expected more values while reading float_array contents."); throw DeadlyImportError("Expected more values while reading float_array contents.");
}
ai_real value; ai_real value;
// read a number // read a number
@ -1461,9 +1465,10 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
// read accessor attributes // read accessor attributes
std::string source; std::string source;
XmlParser::getStdStrAttribute(node, "source", source); XmlParser::getStdStrAttribute(node, "source", source);
if (source[0] != '#') if (source[0] != '#') {
ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <accessor> element."); throw DeadlyImportError("Unknown reference format in url \"", source, "\" in source attribute of <accessor> element.");
int count; }
int count = 0;
XmlParser::getIntAttribute(node, "count", count); XmlParser::getIntAttribute(node, "count", count);
unsigned int offset = 0; unsigned int offset = 0;
@ -1561,7 +1566,7 @@ void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) {
if (currentName == "input") { if (currentName == "input") {
ReadInputChannel(currentNode, pMesh.mPerVertexData); ReadInputChannel(currentNode, pMesh.mPerVertexData);
} else { } else {
ThrowException(format() << "Unexpected sub element <" << currentName << "> in tag <vertices>"); throw DeadlyImportError("Unexpected sub element <", currentName, "> in tag <vertices>");
} }
} }
} }
@ -1628,8 +1633,9 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
const char *content = v.c_str(); const char *content = v.c_str();
vcount.reserve(numPrimitives); vcount.reserve(numPrimitives);
for (unsigned int a = 0; a < numPrimitives; a++) { for (unsigned int a = 0; a < numPrimitives; a++) {
if (*content == 0) if (*content == 0) {
ThrowException("Expected more values while reading <vcount> contents."); throw DeadlyImportError("Expected more values while reading <vcount> contents.");
}
// read a number // read a number
vcount.push_back((size_t)strtoul10(content, &content)); vcount.push_back((size_t)strtoul10(content, &content));
// skip whitespace after it // skip whitespace after it
@ -1647,7 +1653,7 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
} else if (currentName == "ph") { } else if (currentName == "ph") {
// skip // skip
} else { } else {
ThrowException(format() << "Unexpected sub element <" << currentName << "> in tag <" << elementName << ">"); throw DeadlyImportError("Unexpected sub element <", currentName, "> in tag <", elementName, ">");
} }
} }
@ -1671,17 +1677,14 @@ void ColladaParser::ReadInputChannel(XmlNode &node, std::vector<InputChannel> &p
// read semantic // read semantic
std::string semantic; std::string semantic;
XmlParser::getStdStrAttribute(node, "semantic", semantic); XmlParser::getStdStrAttribute(node, "semantic", semantic);
//int attrSemantic = GetAttribute("semantic");
//std::string semantic = mReader->getAttributeValue(attrSemantic);
channel.mType = GetTypeForSemantic(semantic); channel.mType = GetTypeForSemantic(semantic);
// read source // read source
std::string source; std::string source;
XmlParser::getStdStrAttribute(node, "source", source); XmlParser::getStdStrAttribute(node, "source", source);
//int attrSource = GetAttribute("source"); if (source[0] != '#') {
//const char *source = mReader->getAttributeValue(attrSource); throw DeadlyImportError("Unknown reference format in url \"", source, "\" in source attribute of <input> element.");
if (source[0] != '#') }
ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <input> element.");
channel.mAccessor = source.c_str() + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only channel.mAccessor = source.c_str() + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only
// read index offset, if per-index <input> // read index offset, if per-index <input>
@ -1763,11 +1766,13 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
// HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines' // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets); ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
pNumPrimitives = (indices.size() / numOffsets) / 2; pNumPrimitives = (indices.size() / numOffsets) / 2;
} else } else {
ThrowException("Expected different index count in <p> element."); throw DeadlyImportError("Expected different index count in <p> element.");
}
} else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) } else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) {
ThrowException("Expected different index count in <p> element."); throw DeadlyImportError("Expected different index count in <p> element.");
}
// find the data for all sources // find the data for all sources
for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) { for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
@ -1791,8 +1796,9 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
// ignore vertex pointer, it doesn't refer to an accessor // ignore vertex pointer, it doesn't refer to an accessor
if (input.mType == IT_Vertex) { if (input.mType == IT_Vertex) {
// warn if the vertex channel does not refer to the <vertices> element in the same mesh // warn if the vertex channel does not refer to the <vertices> element in the same mesh
if (input.mAccessor != pMesh.mVertexID) if (input.mAccessor != pMesh.mVertexID) {
ThrowException("Unsupported vertex referencing scheme."); throw DeadlyImportError("Unsupported vertex referencing scheme.");
}
continue; continue;
} }
@ -1859,7 +1865,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
break; break;
default: default:
// LineStrip is not supported due to expected index unmangling // LineStrip is not supported due to expected index unmangling
ThrowException("Unsupported primitive type."); throw DeadlyImportError("Unsupported primitive type.");
break; break;
} }
@ -1915,8 +1921,9 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
return; return;
const Accessor &acc = *pInput.mResolved; const Accessor &acc = *pInput.mResolved;
if (pLocalIndex >= acc.mCount) if (pLocalIndex >= acc.mCount) {
ThrowException(format() << "Invalid data index (" << pLocalIndex << "/" << acc.mCount << ") in primitive specification"); throw DeadlyImportError("Invalid data index (", pLocalIndex, "/", acc.mCount, ") in primitive specification");
}
// get a pointer to the start of the data object referred to by the accessor and the local index // get a pointer to the start of the data object referred to by the accessor and the local index
const ai_real *dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride; const ai_real *dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride;
@ -2121,8 +2128,9 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
if (XmlParser::hasAttribute(currentNode, "url")) { if (XmlParser::hasAttribute(currentNode, "url")) {
std::string url; std::string url;
XmlParser::getStdStrAttribute(currentNode, "url", url); XmlParser::getStdStrAttribute(currentNode, "url", url);
if (url[0] != '#') if (url[0] != '#') {
ThrowException("Unknown reference format in <instance_light> element"); throw DeadlyImportError("Unknown reference format in <instance_light> element");
}
pNode->mLights.push_back(LightInstance()); pNode->mLights.push_back(LightInstance());
pNode->mLights.back().mLight = url.c_str() + 1; pNode->mLights.back().mLight = url.c_str() + 1;
@ -2133,7 +2141,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
std::string url; std::string url;
XmlParser::getStdStrAttribute(currentNode, "url", url); XmlParser::getStdStrAttribute(currentNode, "url", url);
if (url[0] != '#') { if (url[0] != '#') {
ThrowException("Unknown reference format in <instance_camera> element"); throw DeadlyImportError("Unknown reference format in <instance_camera> element");
} }
pNode->mCameras.push_back(CameraInstance()); pNode->mCameras.push_back(CameraInstance());
pNode->mCameras.back().mCamera = url.c_str() + 1; pNode->mCameras.back().mCamera = url.c_str() + 1;
@ -2237,8 +2245,9 @@ void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) {
// referred mesh is given as an attribute of the <instance_geometry> element // referred mesh is given as an attribute of the <instance_geometry> element
std::string url; std::string url;
XmlParser::getStdStrAttribute(node, "url", url); XmlParser::getStdStrAttribute(node, "url", url);
if (url[0] != '#') if (url[0] != '#') {
ThrowException("Unknown reference format"); throw DeadlyImportError("Unknown reference format");
}
Collada::MeshInstance instance; Collada::MeshInstance instance;
instance.mMeshOrController = url.c_str() + 1; // skipping the leading # instance.mMeshOrController = url.c_str() + 1; // skipping the leading #
@ -2277,32 +2286,27 @@ void ColladaParser::ReadScene(XmlNode &node) {
const std::string currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == "instance_visual_scene") { if (currentName == "instance_visual_scene") {
// should be the first and only occurrence // should be the first and only occurrence
if (mRootNode) if (mRootNode) {
ThrowException("Invalid scene containing multiple root nodes in <instance_visual_scene> element"); throw DeadlyImportError("Invalid scene containing multiple root nodes in <instance_visual_scene> element");
}
// read the url of the scene to instance. Should be of format "#some_name" // read the url of the scene to instance. Should be of format "#some_name"
std::string url; std::string url;
XmlParser::getStdStrAttribute(currentNode, "url", url); XmlParser::getStdStrAttribute(currentNode, "url", url);
if (url[0] != '#') { if (url[0] != '#') {
ThrowException("Unknown reference format in <instance_visual_scene> element"); throw DeadlyImportError("Unknown reference format in <instance_visual_scene> element");
} }
// find the referred scene, skip the leading # // find the referred scene, skip the leading #
NodeLibrary::const_iterator sit = mNodeLibrary.find(url.c_str() + 1); NodeLibrary::const_iterator sit = mNodeLibrary.find(url.c_str() + 1);
if (sit == mNodeLibrary.end()) { if (sit == mNodeLibrary.end()) {
ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element."); throw DeadlyImportError("Unable to resolve visual_scene reference \"", std::string(url), "\" in <instance_visual_scene> element.");
} }
mRootNode = sit->second; mRootNode = sit->second;
} }
} }
} }
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
AI_WONT_RETURN void ColladaParser::ThrowException(const std::string &pError) const {
throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError);
}
void ColladaParser::ReportWarning(const char *msg, ...) { void ColladaParser::ReportWarning(const char *msg, ...) {
ai_assert(nullptr != msg); ai_assert(nullptr != msg);

View File

@ -243,8 +243,6 @@ protected:
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected: protected:
/** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX;
void ReportWarning(const char *msg, ...); void ReportWarning(const char *msg, ...);
/** Calculates the resulting transformation from all the given transform steps */ /** Calculates the resulting transformation from all the given transform steps */
@ -348,8 +346,9 @@ protected:
template <typename Type> template <typename Type>
const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const { const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL); typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
if (it == pLibrary.end()) if (it == pLibrary.end()) {
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
}
return it->second; return it->second;
} }

View File

@ -152,7 +152,7 @@ void DXFImporter::InternReadFile( const std::string& filename, aiScene* pScene,
// Check whether we can read the file // Check whether we can read the file
if( file.get() == nullptr ) { if( file.get() == nullptr ) {
throw DeadlyImportError( "Failed to open DXF file " + filename + ""); throw DeadlyImportError( "Failed to open DXF file ", filename, "");
} }
// Check whether this is a binary DXF file - we can't read binary DXF files :-( // Check whether this is a binary DXF file - we can't read binary DXF files :-(

View File

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/ByteSwapper.h> #include <assimp/ByteSwapper.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/StringUtils.h>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -126,7 +127,7 @@ namespace {
AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
{ {
throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset)); throw DeadlyImportError("FBX-Tokenize", Util::GetOffsetText(offset), message);
} }
@ -456,11 +457,21 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
ASSIMP_LOG_DEBUG_F("FBX version: ", version); ASSIMP_LOG_DEBUG_F("FBX version: ", version);
const bool is64bits = version >= 7500; const bool is64bits = version >= 7500;
const char *end = input + length; const char *end = input + length;
while (cursor < end ) { try
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { {
break; while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
break;
}
} }
} }
catch (const DeadlyImportError& e)
{
if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", to_string(version), ") of the FBX format. (", e.what(), ")");
}
throw;
}
} }
} // !FBX } // !FBX

View File

@ -1988,6 +1988,7 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_
TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh); TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh); TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh); TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
TrySetTextureProperties(out_mat, _textures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
//Maya counterparts //Maya counterparts
TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh); TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh); TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);

View File

@ -61,7 +61,7 @@ namespace Util {
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
void DOMError(const std::string& message, const Token& token) void DOMError(const std::string& message, const Token& token)
{ {
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token)); throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -70,7 +70,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
if(element) { if(element) {
DOMError(message,element->KeyToken()); DOMError(message,element->KeyToken());
} }
throw DeadlyImportError("FBX-DOM " + message); throw DeadlyImportError("FBX-DOM ", message);
} }
@ -79,7 +79,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
void DOMWarning(const std::string& message, const Token& token) void DOMWarning(const std::string& message, const Token& token)
{ {
if(DefaultLogger::get()) { if(DefaultLogger::get()) {
ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token)); ASSIMP_LOG_WARN_F("FBX-DOM", Util::GetTokenText(&token), message);
} }
} }

View File

@ -400,6 +400,65 @@ void FBXExporter::WriteHeaderExtension ()
); );
} }
// WriteGlobalSettings helpers
void WritePropInt(const aiScene* scene, FBX::Node& p, const std::string& key, int defaultValue)
{
int value;
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
p.AddP70int(key, value);
} else {
p.AddP70int(key, defaultValue);
}
}
void WritePropDouble(const aiScene* scene, FBX::Node& p, const std::string& key, double defaultValue)
{
double value;
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
p.AddP70double(key, value);
} else {
// fallback lookup float instead
float floatValue;
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, floatValue)) {
p.AddP70double(key, (double)floatValue);
} else {
p.AddP70double(key, defaultValue);
}
}
}
void WritePropEnum(const aiScene* scene, FBX::Node& p, const std::string& key, int defaultValue)
{
int value;
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
p.AddP70enum(key, value);
} else {
p.AddP70enum(key, defaultValue);
}
}
void WritePropColor(const aiScene* scene, FBX::Node& p, const std::string& key, const aiVector3D& defaultValue)
{
aiVector3D value;
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
// ai_real can be float or double, cast to avoid warnings
p.AddP70color(key, (double)value.x, (double)value.y, (double)value.z);
} else {
p.AddP70color(key, (double)defaultValue.x, (double)defaultValue.y, (double)defaultValue.z);
}
}
void WritePropString(const aiScene* scene, FBX::Node& p, const std::string& key, const std::string& defaultValue)
{
aiString value; // MetaData doesn't hold std::string
if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
p.AddP70string(key, value.C_Str());
} else {
p.AddP70string(key, defaultValue);
}
}
void FBXExporter::WriteGlobalSettings () void FBXExporter::WriteGlobalSettings ()
{ {
if (!binary) { if (!binary) {
@ -409,26 +468,26 @@ void FBXExporter::WriteGlobalSettings ()
gs.AddChild("Version", int32_t(1000)); gs.AddChild("Version", int32_t(1000));
FBX::Node p("Properties70"); FBX::Node p("Properties70");
p.AddP70int("UpAxis", 1); WritePropInt(mScene, p, "UpAxis", 1);
p.AddP70int("UpAxisSign", 1); WritePropInt(mScene, p, "UpAxisSign", 1);
p.AddP70int("FrontAxis", 2); WritePropInt(mScene, p, "FrontAxis", 2);
p.AddP70int("FrontAxisSign", 1); WritePropInt(mScene, p, "FrontAxisSign", 1);
p.AddP70int("CoordAxis", 0); WritePropInt(mScene, p, "CoordAxis", 0);
p.AddP70int("CoordAxisSign", 1); WritePropInt(mScene, p, "CoordAxisSign", 1);
p.AddP70int("OriginalUpAxis", 1); WritePropInt(mScene, p, "OriginalUpAxis", 1);
p.AddP70int("OriginalUpAxisSign", 1); WritePropInt(mScene, p, "OriginalUpAxisSign", 1);
p.AddP70double("UnitScaleFactor", 1.0); WritePropDouble(mScene, p, "UnitScaleFactor", 1.0);
p.AddP70double("OriginalUnitScaleFactor", 1.0); WritePropDouble(mScene, p, "OriginalUnitScaleFactor", 1.0);
p.AddP70color("AmbientColor", 0.0, 0.0, 0.0); WritePropColor(mScene, p, "AmbientColor", aiVector3D((ai_real)0.0, (ai_real)0.0, (ai_real)0.0));
p.AddP70string("DefaultCamera", "Producer Perspective"); WritePropString(mScene, p,"DefaultCamera", "Producer Perspective");
p.AddP70enum("TimeMode", 11); WritePropEnum(mScene, p, "TimeMode", 11);
p.AddP70enum("TimeProtocol", 2); WritePropEnum(mScene, p, "TimeProtocol", 2);
p.AddP70enum("SnapOnFrameMode", 0); WritePropEnum(mScene, p, "SnapOnFrameMode", 0);
p.AddP70time("TimeSpanStart", 0); // TODO: animation support p.AddP70time("TimeSpanStart", 0); // TODO: animation support
p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support
p.AddP70double("CustomFrameRate", -1.0); WritePropDouble(mScene, p, "CustomFrameRate", -1.0);
p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is
p.AddP70int("CurrentTimeMarker", -1); WritePropInt(mScene, p, "CurrentTimeMarker", -1);
gs.AddChild(p); gs.AddChild(p);
gs.Dump(outfile, binary, 0); gs.Dump(outfile, binary, 0);

View File

@ -141,7 +141,10 @@ void FBXImporter::SetupProperties(const Importer *pImp) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb")); auto streamCloser = [&](IOStream *pStream) {
pIOHandler->Close(pStream);
};
std::unique_ptr<IOStream, decltype(streamCloser)> stream(pIOHandler->Open(pFile, "rb"), streamCloser);
if (!stream) { if (!stream) {
ThrowException("Could not open file for reading"); ThrowException("Could not open file for reading");
} }

View File

@ -73,7 +73,7 @@ namespace {
AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
{ {
throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -83,7 +83,7 @@ namespace {
if(element) { if(element) {
ParseError(message,element->KeyToken()); ParseError(message,element->KeyToken());
} }
throw DeadlyImportError("FBX-Parser " + message); throw DeadlyImportError("FBX-Parser ", message);
} }

View File

@ -90,7 +90,7 @@ namespace {
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
{ {
throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column)); throw DeadlyImportError("FBX-Tokenize", Util::GetLineAndColumnText(line,column), message);
} }

View File

@ -86,32 +86,30 @@ const char* TokenTypeString(TokenType t)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset) std::string GetOffsetText(size_t offset)
{ {
return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); return static_cast<std::string>( Formatter::format() << " (offset 0x" << std::hex << offset << ") " );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) std::string GetLineAndColumnText(unsigned int line, unsigned int column)
{ {
return static_cast<std::string>( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); return static_cast<std::string>( Formatter::format() << " (line " << line << " << col " << column << ") " );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) std::string GetTokenText(const Token* tok)
{ {
if(tok->IsBinary()) { if(tok->IsBinary()) {
return static_cast<std::string>( (Formatter::format() << prefix << return static_cast<std::string>( Formatter::format() <<
" (" << TokenTypeString(tok->Type()) << " (" << TokenTypeString(tok->Type()) <<
", offset 0x" << std::hex << tok->Offset() << ") " << ", offset 0x" << std::hex << tok->Offset() << ") " );
text) );
} }
return static_cast<std::string>( (Formatter::format() << prefix << return static_cast<std::string>( Formatter::format() <<
" (" << TokenTypeString(tok->Type()) << " (" << TokenTypeString(tok->Type()) <<
", line " << tok->Line() << ", line " << tok->Line() <<
", col " << tok->Column() << ") " << ", col " << tok->Column() << ") " );
text) );
} }
// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;

View File

@ -73,31 +73,24 @@ const char* TokenTypeString(TokenType t);
/** Format log/error messages using a given offset in the source binary file /** Format log/error messages using a given offset in the source binary file
* *
* @param prefix Message prefix to be preprended to the location info. * @param offset offset within the file
* @param text Message text * @return A string of the following format: " (offset 0x{offset}) "*/
* @param line Line index, 1-based std::string GetOffsetText(size_t offset);
* @param column Column index, 1-based
* @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
/** Format log/error messages using a given line location in the source file. /** Format log/error messages using a given line location in the source file.
* *
* @param prefix Message prefix to be preprended to the location info.
* @param text Message text
* @param line Line index, 1-based * @param line Line index, 1-based
* @param column Column index, 1-based * @param column Column index, 1-based
* @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/ * @return A string of the following format: " (line {line}, col {column}) "*/
std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column); std::string GetLineAndColumnText(unsigned int line, unsigned int column);
/** Format log/error messages using a given cursor token. /** Format log/error messages using a given cursor token.
* *
* @param prefix Message prefix to be preprended to the location info.
* @param text Message text
* @param tok Token where parsing/processing stopped * @param tok Token where parsing/processing stopped
* @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/ * @return A string of the following format: " ({token-type}, line {line}, col {column}) "*/
std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok); std::string GetTokenText(const Token* tok);
/** Decode a single Base64-encoded character. /** Decode a single Base64-encoded character.
* *

View File

@ -115,7 +115,7 @@ void HMPImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open HMP file " + pFile + "."); throw DeadlyImportError("Failed to open HMP file ", pFile, ".");
} }
// Check whether the HMP file is large enough to contain // Check whether the HMP file is large enough to contain
@ -159,8 +159,8 @@ void HMPImporter::InternReadFile(const std::string &pFile,
szBuffer[4] = '\0'; szBuffer[4] = '\0';
// We're definitely unable to load this file // We're definitely unable to load this file
throw DeadlyImportError("Unknown HMP subformat " + pFile + throw DeadlyImportError("Unknown HMP subformat ", pFile,
". Magic word (" + szBuffer + ") is not known"); ". Magic word (", szBuffer, ") is not known");
} }
// Set the AI_SCENE_FLAGS_TERRAIN bit // Set the AI_SCENE_FLAGS_TERRAIN bit

View File

@ -45,6 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "IFCReaderGen_2x3.h" #include "IFCReaderGen_2x3.h"
#if _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4702)
#endif // _MSC_VER
namespace Assimp { namespace Assimp {
using namespace ::Assimp::IFC; using namespace ::Assimp::IFC;
@ -3165,4 +3170,8 @@ template <> size_t GenericFill<IfcLightSourceDirectional>(const DB& db, const LI
} // ! STEP } // ! STEP
} // ! Assimp } // ! Assimp
#if _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER
#endif #endif

View File

@ -43,6 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "IFCReaderGen_2x3.h" #include "IFCReaderGen_2x3.h"
#if _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4702)
#endif // _MSC_VER
namespace Assimp { namespace Assimp {
using namespace IFC; using namespace IFC;
using namespace ::Assimp::IFC::Schema_2x3; using namespace ::Assimp::IFC::Schema_2x3;
@ -1915,4 +1920,8 @@ template <> size_t GenericFill<IfcConditionCriterion>(const DB& db, const LIST&
} // ! STEP } // ! STEP
} // ! Assimp } // ! Assimp
#if _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER
#endif #endif

View File

@ -45,9 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetLib/Step/STEPFile.h" #include "AssetLib/Step/STEPFile.h"
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push)
# pragma warning( disable : 4512 ) # pragma warning( disable : 4512 )
#endif // _WIN32 #endif // _MSC_VER
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
@ -4372,4 +4373,8 @@ namespace STEP {
} //! STEP } //! STEP
} //! Assimp } //! Assimp
#ifdef _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER
#endif // INCLUDED_IFC_READER_GEN_H #endif // INCLUDED_IFC_READER_GEN_H

View File

@ -145,7 +145,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open LWO file " + pFile + "."); throw DeadlyImportError("Failed to open LWO file ", pFile, ".");
} }
if ((this->fileSize = (unsigned int)file->FileSize()) < 12) { if ((this->fileSize = (unsigned int)file->FileSize()) < 12) {
@ -212,7 +212,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
szBuff[2] = (char)(fileType >> 8u); szBuff[2] = (char)(fileType >> 8u);
szBuff[3] = (char)(fileType); szBuff[3] = (char)(fileType);
szBuff[4] = '\0'; szBuff[4] = '\0';
throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff); throw DeadlyImportError("Unknown LWO sub format: ", szBuff);
} }
if (AI_LWO_FOURCC_LWOB != fileType) { if (AI_LWO_FOURCC_LWOB != fileType) {
@ -232,7 +232,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
} }
if (configLayerName.length() && !hasNamedLayer) { if (configLayerName.length() && !hasNamedLayer) {
throw DeadlyImportError("LWO2: Unable to find the requested layer: " + configLayerName); throw DeadlyImportError("LWO2: Unable to find the requested layer: ", configLayerName);
} }
} }

View File

@ -502,7 +502,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open LWS file " + pFile + "."); throw DeadlyImportError("Failed to open LWS file ", pFile, ".");
} }
// Allocate storage and copy the contents of the file to a memory buffer // Allocate storage and copy the contents of the file to a memory buffer

View File

@ -160,21 +160,21 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
// Read file into memory // Read file into memory
std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb")); std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
if (!pStream.get()) { if (!pStream.get()) {
throw DeadlyImportError("Failed to open file " + file + "."); throw DeadlyImportError("Failed to open file ", file, ".");
} }
// Get the file-size and validate it, throwing an exception when fails // Get the file-size and validate it, throwing an exception when fails
size_t fileSize = pStream->FileSize(); size_t fileSize = pStream->FileSize();
if (fileSize < 8) { if (fileSize < 8) {
throw DeadlyImportError("M3D-file " + file + " is too small."); throw DeadlyImportError("M3D-file ", file, " is too small.");
} }
std::vector<unsigned char> buffer(fileSize); std::vector<unsigned char> buffer(fileSize);
if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) { if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
throw DeadlyImportError("Failed to read the file " + file + "."); throw DeadlyImportError("Failed to read the file ", file, ".");
} }
// extra check for binary format's first 8 bytes. Not done for the ASCII variant // extra check for binary format's first 8 bytes. Not done for the ASCII variant
if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) { if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
throw DeadlyImportError("Bad binary header in file " + file + "."); throw DeadlyImportError("Bad binary header in file ", file, ".");
} }
#ifdef M3D_ASCII #ifdef M3D_ASCII
// make sure there's a terminator zero character, as input must be ASCIIZ // make sure there's a terminator zero character, as input must be ASCIIZ
@ -200,7 +200,7 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
M3DWrapper m3d(pIOHandler, buffer); M3DWrapper m3d(pIOHandler, buffer);
if (!m3d) { if (!m3d) {
throw DeadlyImportError("Unable to parse " + file + " as M3D."); throw DeadlyImportError("Unable to parse ", file, " as M3D.");
} }
// create the root node // create the root node

File diff suppressed because it is too large Load Diff

View File

@ -222,7 +222,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open MD2 file " + pFile + ""); throw DeadlyImportError("Failed to open MD2 file ", pFile, "");
} }
// check whether the md3 file is large enough to contain // check whether the md3 file is large enough to contain

View File

@ -715,7 +715,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open MD3 file " + pFile + "."); throw DeadlyImportError("Failed to open MD3 file ", pFile, ".");
} }
// Check whether the md3 file is large enough to contain the header // Check whether the md3 file is large enough to contain the header

View File

@ -675,7 +675,7 @@ void MD5Importer::LoadMD5CameraFile() {
// Check whether we can read from the file // Check whether we can read from the file
if (!file.get() || !file->FileSize()) { if (!file.get() || !file->FileSize()) {
throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile); throw DeadlyImportError("Failed to read MD5CAMERA file: ", pFile);
} }
mHadMD5Camera = true; mHadMD5Camera = true;
LoadFileIntoMemory(file.get()); LoadFileIntoMemory(file.get());

View File

@ -219,7 +219,7 @@ void MDCImporter::InternReadFile(
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open MDC file " + pFile + "."); throw DeadlyImportError("Failed to open MDC file ", pFile, ".");
} }
// check whether the mdc file is large enough to contain the file header // check whether the mdc file is large enough to contain the file header

View File

@ -68,9 +68,9 @@ namespace Assimp {
namespace MDL { namespace MDL {
namespace HalfLife { namespace HalfLife {
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(disable : 4706) # pragma warning(disable : 4706)
#endif // _WIN32 #endif // _MSC_VER
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
HL1MDLLoader::HL1MDLLoader( HL1MDLLoader::HL1MDLLoader(

View File

@ -218,12 +218,12 @@ private:
template <typename MDLFileHeader> template <typename MDLFileHeader>
void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) { void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) {
if (!io_->Exists(file_path)) if (!io_->Exists(file_path))
throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + "."); throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), ".");
std::unique_ptr<IOStream> file(io_->Open(file_path)); std::unique_ptr<IOStream> file(io_->Open(file_path));
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + "."); throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), ".");
} }
const size_t file_size = file->FileSize(); const size_t file_size = file->FileSize();

View File

@ -167,7 +167,7 @@ void MDLImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open MDL file " + pFile + "."); throw DeadlyImportError("Failed to open MDL file ", pFile, ".");
} }
// This should work for all other types of MDL files, too ... // This should work for all other types of MDL files, too ...
@ -251,8 +251,8 @@ void MDLImporter::InternReadFile(const std::string &pFile,
} }
} else { } else {
// print the magic word to the log file // print the magic word to the log file
throw DeadlyImportError("Unknown MDL subformat " + pFile + throw DeadlyImportError("Unknown MDL subformat ", pFile,
". Magic word (" + std::string((char *)&iMagicWord, 4) + ") is not known"); ". Magic word (", std::string((char *)&iMagicWord, 4), ") is not known");
} }
// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system

View File

@ -111,7 +111,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
// Read file by istream // Read file by istream
std::filebuf fb; std::filebuf fb;
if (!fb.open(file, std::ios::in | std::ios::binary)) { if (!fb.open(file, std::ios::in | std::ios::binary)) {
throw DeadlyImportError("Failed to open file " + file + "."); throw DeadlyImportError("Failed to open file ", file, ".");
} }
std::istream fileStream(&fb); std::istream fileStream(&fb);
@ -122,7 +122,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
fileStream.seekg(0, fileStream.beg); fileStream.seekg(0, fileStream.beg);
if (fileSize < sizeof(pmx::PmxModel)) { if (fileSize < sizeof(pmx::PmxModel)) {
throw DeadlyImportError(file + " is too small."); throw DeadlyImportError(file, " is too small.");
} }
pmx::PmxModel model; pmx::PmxModel model;

View File

@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "MMDPmxParser.h" #include "MMDPmxParser.h"
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#ifdef ASSIMP_USE_HUNTER #ifdef ASSIMP_USE_HUNTER
# include <utf8/utf8.h> # include <utf8.h>
#else #else
# include "../contrib/utf8cpp/source/utf8.h" # include "../contrib/utf8cpp/source/utf8.h"
#endif #endif
@ -524,7 +524,7 @@ namespace pmx
if (version != 2.0f && version != 2.1f) if (version != 2.0f && version != 2.1f)
{ {
std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl; std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but " + to_string(version)); throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but ", to_string(version));
} }
this->setting.Read(stream); this->setting.Read(stream);

View File

@ -229,7 +229,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
stream.CopyAndAdvance(head,10); stream.CopyAndAdvance(head,10);
stream >> version; stream >> version;
if (strncmp(head,"MS3D000000",10)) { if (strncmp(head,"MS3D000000",10)) {
throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile); throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: ", pFile);
} }
if (version != 4) { if (version != 4) {

View File

@ -96,7 +96,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_FLOAT(f) \ #define AI_NFF_PARSE_FLOAT(f) \
SkipSpaces(&sz); \ SkipSpaces(&sz); \
if (!::IsLineEnd(*sz)) sz = fast_atoreal_move<float>(sz, (float &)f); if (!::IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_TRIPLE(v) \ #define AI_NFF_PARSE_TRIPLE(v) \
@ -214,7 +214,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (!file.get()) if (!file.get())
throw DeadlyImportError("Failed to open NFF file " + pFile + "."); throw DeadlyImportError("Failed to open NFF file ", pFile, ".");
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero) // (terminate it with zero)
@ -233,7 +233,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// camera parameters // camera parameters
aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f); aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
float angle = 45.f; ai_real angle = 45.f;
aiVector2D resolution; aiVector2D resolution;
bool hasCam = false; bool hasCam = false;
@ -262,7 +262,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// check whether this is the NFF2 file format // check whether this is the NFF2 file format
if (TokenMatch(buffer, "nff", 3)) { if (TokenMatch(buffer, "nff", 3)) {
const float qnan = get_qnan(); const ai_real qnan = get_qnan();
const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f); const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f);
const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f); const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f);
@ -706,7 +706,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
} }
// 'f' - shading information block // 'f' - shading information block
else if (TokenMatch(sz, "f", 1)) { else if (TokenMatch(sz, "f", 1)) {
float d; ai_real d;
// read the RGB colors // read the RGB colors
AI_NFF_PARSE_TRIPLE(s.color); AI_NFF_PARSE_TRIPLE(s.color);
@ -856,7 +856,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// read the two center points and the respective radii // read the two center points and the respective radii
aiVector3D center1, center2; aiVector3D center1, center2;
float radius1 = 0.f, radius2 = 0.f; ai_real radius1 = 0.f, radius2 = 0.f;
AI_NFF_PARSE_TRIPLE(center1); AI_NFF_PARSE_TRIPLE(center1);
AI_NFF_PARSE_FLOAT(radius1); AI_NFF_PARSE_FLOAT(radius1);
@ -874,7 +874,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
curMesh.dir = center2 - center1; curMesh.dir = center2 - center1;
curMesh.center = center1 + curMesh.dir / (ai_real)2.0; curMesh.center = center1 + curMesh.dir / (ai_real)2.0;
float f; ai_real f;
if ((f = curMesh.dir.Length()) < 10e-3f) { if ((f = curMesh.dir.Length()) < 10e-3f) {
ASSIMP_LOG_ERROR("NFF: Cone height is close to zero"); ASSIMP_LOG_ERROR("NFF: Cone height is close to zero");
continue; continue;

View File

@ -113,14 +113,14 @@ private:
{} {}
aiColor3D color,diffuse,specular,ambient,emissive; aiColor3D color,diffuse,specular,ambient,emissive;
float refracti; ai_real refracti;
std::string texFile; std::string texFile;
// For NFF2 // For NFF2
bool twoSided; bool twoSided;
bool shaded; bool shaded;
float opacity, shininess; ai_real opacity, shininess;
std::string name; std::string name;
@ -155,7 +155,7 @@ private:
{} {}
aiVector3D position; aiVector3D position;
float intensity; ai_real intensity;
aiColor3D color; aiColor3D color;
}; };

View File

@ -123,7 +123,7 @@ void OFFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == nullptr) { if( file.get() == nullptr) {
throw DeadlyImportError( "Failed to open OFF file " + pFile + "."); throw DeadlyImportError( "Failed to open OFF file ", pFile, ".");
} }
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer

View File

@ -109,9 +109,12 @@ const aiImporterDesc *ObjFileImporter::GetInfo() const {
void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) { void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
// Read file into memory // Read file into memory
static const std::string mode = "rb"; static const std::string mode = "rb";
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode)); auto streamCloser = [&](IOStream *pStream) {
pIOHandler->Close(pStream);
};
std::unique_ptr<IOStream, decltype(streamCloser)> fileStream(pIOHandler->Open(file, mode), streamCloser);
if (!fileStream.get()) { if (!fileStream.get()) {
throw DeadlyImportError("Failed to open file " + file + "."); throw DeadlyImportError("Failed to open file ", file, ".");
} }
// Get the file-size and validate it, throwing an exception when fails // Get the file-size and validate it, throwing an exception when fails

View File

@ -187,8 +187,8 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) {
/// @todo Check what we can actually support. /// @todo Check what we can actually support.
std::string version = serializer.ReadLine(); std::string version = serializer.ReadLine();
if (version != MESH_VERSION_1_8) { if (version != MESH_VERSION_1_8) {
throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again." throw DeadlyExportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.",
<< " Supported versions: " << MESH_VERSION_1_8); " Supported versions: ", MESH_VERSION_1_8);
} }
Mesh *mesh = new Mesh(); Mesh *mesh = new Mesh();
@ -471,7 +471,7 @@ void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) {
uint16_t submeshIndex = Read<uint16_t>(); uint16_t submeshIndex = Read<uint16_t>();
SubMesh *submesh = mesh->GetSubMesh(submeshIndex); SubMesh *submesh = mesh->GetSubMesh(submeshIndex);
if (!submesh) { if (!submesh) {
throw DeadlyImportError(Formatter::format() << "Ogre Mesh does not include submesh " << submeshIndex << " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file."); throw DeadlyImportError("Ogre Mesh does not include submesh ", submeshIndex, " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file.");
} }
submesh->name = ReadLine(); submesh->name = ReadLine();
@ -788,7 +788,7 @@ MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHand
IOStream *f = pIOHandler->Open(filename, "rb"); IOStream *f = pIOHandler->Open(filename, "rb");
if (!f) { if (!f) {
throw DeadlyImportError("Failed to open skeleton file " + filename); throw DeadlyImportError("Failed to open skeleton file ", filename);
} }
return MemoryStreamReaderPtr(new MemoryStreamReader(f)); return MemoryStreamReaderPtr(new MemoryStreamReader(f));
@ -803,8 +803,8 @@ void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) {
// This deserialization supports both versions of the skeleton spec // This deserialization supports both versions of the skeleton spec
std::string version = ReadLine(); std::string version = ReadLine();
if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) { if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) {
throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer." throw DeadlyExportError("Skeleton version ", version, " not supported by this importer.",
<< " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1); " Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1);
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
@ -871,7 +871,7 @@ void OgreBinarySerializer::ReadBone(Skeleton *skeleton) {
// Bone indexes need to start from 0 and be contiguous // Bone indexes need to start from 0 and be contiguous
if (bone->id != skeleton->bones.size()) { if (bone->id != skeleton->bones.size()) {
throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id); throw DeadlyImportError("Ogre Skeleton bone indexes not contiguous. Error at bone index ", bone->id);
} }
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", bone->id, " ", bone->name); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", bone->id, " ", bone->name);
@ -889,7 +889,7 @@ void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton) {
if (child && parent) if (child && parent)
parent->AddChild(child); parent->AddChild(child);
else else
throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId); throw DeadlyImportError("Failed to find bones for parenting: Child id ", childId, " for parent id ", parentId);
} }
void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) { void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) {
@ -926,7 +926,7 @@ void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, A
uint16_t boneId = Read<uint16_t>(); uint16_t boneId = Read<uint16_t>();
Bone *bone = dest->parentSkeleton->BoneById(boneId); Bone *bone = dest->parentSkeleton->BoneById(boneId);
if (!bone) { if (!bone) {
throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton"); throw DeadlyImportError("Cannot read animation track, target bone ", boneId, " not in target Skeleton");
} }
VertexAnimationTrack track; VertexAnimationTrack track;

View File

@ -91,7 +91,7 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
// Open source file // Open source file
IOStream *f = pIOHandler->Open(pFile, "rb"); IOStream *f = pIOHandler->Open(pFile, "rb");
if (!f) { if (!f) {
throw DeadlyImportError("Failed to open file " + pFile); throw DeadlyImportError("Failed to open file ", pFile);
} }
// Binary .mesh import // Binary .mesh import

View File

@ -476,7 +476,7 @@ void SubMesh::Reset(){
aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) { aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) {
if (operationType != OT_TRIANGLE_LIST) { if (operationType != OT_TRIANGLE_LIST) {
throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType); throw DeadlyImportError("Only mesh operation type OT_TRIANGLE_LIST is supported. Found ", operationType);
} }
aiMesh *dest = new aiMesh(); aiMesh *dest = new aiMesh();
@ -944,7 +944,7 @@ void Bone::AddChild(Bone *bone) {
if (!bone) if (!bone)
return; return;
if (bone->IsParented()) if (bone->IsParented())
throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name); throw DeadlyImportError("Attaching child Bone that is already parented: ", bone->name);
bone->parent = this; bone->parent = this;
bone->parentId = id; bone->parentId = id;
@ -963,7 +963,7 @@ void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) {
for (auto boneId : children) { for (auto boneId : children) {
Bone *child = skeleton->BoneById(boneId); Bone *child = skeleton->BoneById(boneId);
if (!child) { if (!child) {
throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << boneId << " for parent " << id << " " << name); throw DeadlyImportError("CalculateWorldMatrixAndDefaultPose: Failed to find child bone ", boneId, " for parent ", id, " ", name);
} }
child->CalculateWorldMatrixAndDefaultPose(skeleton); child->CalculateWorldMatrixAndDefaultPose(skeleton);
} }
@ -983,7 +983,7 @@ aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) {
for (size_t i = 0, len = children.size(); i < len; ++i) { for (size_t i = 0, len = children.size(); i < len; ++i) {
Bone *child = skeleton->BoneById(children[i]); Bone *child = skeleton->BoneById(children[i]);
if (!child) { if (!child) {
throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name); throw DeadlyImportError("ConvertToAssimpNode: Failed to find child bone ", children[i], " for parent ", id, " ", name);
} }
node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node); node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node);
} }
@ -1022,7 +1022,7 @@ aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleto
Bone *bone = skeleton->BoneByName(boneName); Bone *bone = skeleton->BoneByName(boneName);
if (!bone) { if (!bone) {
throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton"); throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone ", boneName, " from parent Skeleton");
} }
// Keyframes // Keyframes

View File

@ -60,9 +60,9 @@ namespace Ogre {
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) { AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
if (!error.empty()) { if (!error.empty()) {
throw DeadlyImportError(error + " in node '" + nodeName + "' and attribute '" + name + "'"); throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'");
} else { } else {
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + nodeName + "'"); throw DeadlyImportError("Attribute '", name, "' does not exist in node '", nodeName, "'");
} }
} }
@ -321,18 +321,18 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *d
// Sanity checks // Sanity checks
if (dest->positions.size() != dest->count) { if (dest->positions.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->positions.size(), " positions when should have read ", dest->count);
} }
if (normals && dest->normals.size() != dest->count) { if (normals && dest->normals.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->normals.size(), " normals when should have read ", dest->count);
} }
if (tangents && dest->tangents.size() != dest->count) { if (tangents && dest->tangents.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->tangents.size(), " tangents when should have read ", dest->count);
} }
for (unsigned int i = 0; i < dest->uvs.size(); ++i) { for (unsigned int i = 0; i < dest->uvs.size(); ++i) {
if (dest->uvs[i].size() != dest->count) { if (dest->uvs[i].size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() throw DeadlyImportError("Read only ", dest->uvs[i].size(),
<< " uvs for uv index " << i << " when should have read " << dest->count); " uvs for uv index ", i, " when should have read ", dest->count);
} }
} }
} }
@ -389,7 +389,7 @@ void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) { if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount);
} else { } else {
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount); throw DeadlyImportError("Read only ", submesh->indexData->faces.size(), " faces when should have read ", submesh->indexData->faceCount);
} }
} else if (currentName == nnGeometry) { } else if (currentName == nnGeometry) {
if (submesh->usesSharedVertexData) { if (submesh->usesSharedVertexData) {
@ -515,7 +515,7 @@ XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, cons
std::unique_ptr<IOStream> file(pIOHandler->Open(filename)); std::unique_ptr<IOStream> file(pIOHandler->Open(filename));
if (!file.get()) { if (!file.get()) {
throw DeadlyImportError("Failed to open skeleton file " + filename); throw DeadlyImportError("Failed to open skeleton file ", filename);
} }
XmlParserPtr xmlParser = XmlParserPtr(new XmlParser); XmlParserPtr xmlParser = XmlParserPtr(new XmlParser);
@ -568,7 +568,7 @@ void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
ReadAnimationTracks(currentChildNode, anim); ReadAnimationTracks(currentChildNode, anim);
skeleton->animations.push_back(anim); skeleton->animations.push_back(anim);
} else { } else {
throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << anim->name); throw DeadlyImportError( "No <tracks> found in <animation> ", anim->name);
} }
} }
} }
@ -588,7 +588,7 @@ void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
ReadAnimationKeyFrames(currentChildNode, dest, &track); ReadAnimationKeyFrames(currentChildNode, dest, &track);
dest->tracks.push_back(track); dest->tracks.push_back(track);
} else { } else {
throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << dest->name); throw DeadlyImportError( "No <keyframes> found in <track> ", dest->name);
} }
} }
@ -657,7 +657,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) {
if (bone && parent) { if (bone && parent) {
parent->AddChild(bone); parent->AddChild(bone);
} else { } else {
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); throw DeadlyImportError("Failed to find bones for parenting: Child ", name, " for parent ", parentName);
} }
} }
} }
@ -704,7 +704,7 @@ void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
bone->rotation = aiQuaternion(axis, angle); bone->rotation = aiQuaternion(axis, angle);
} else { } else {
throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id); throw DeadlyImportError( "No axis specified for bone rotation in bone ", bone->id);
} }
} }
} else if (currentChildName == nnScale) { } else if (currentChildName == nnScale) {
@ -736,7 +736,7 @@ void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name);
if (b->id != static_cast<uint16_t>(i)) { if (b->id != static_cast<uint16_t>(i)) {
throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i); throw DeadlyImportError("Bone ids are not in sequence starting from 0. Missing index ", i);
} }
} }
} }

View File

@ -302,7 +302,7 @@ void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pSce
// open source file // open source file
IOStream *file = pIOHandler->Open( filename, "rb" ); IOStream *file = pIOHandler->Open( filename, "rb" );
if( !file ) { if( !file ) {
throw DeadlyImportError( "Failed to open file " + filename ); throw DeadlyImportError( "Failed to open file ", filename );
} }
std::vector<char> buffer; std::vector<char> buffer;

View File

@ -151,13 +151,13 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
const std::string mode = "rb"; const std::string mode = "rb";
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode)); std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
if (!fileStream.get()) { if (!fileStream.get()) {
throw DeadlyImportError("Failed to open file " + pFile + "."); throw DeadlyImportError("Failed to open file ", pFile, ".");
} }
// Get the file-size // Get the file-size
const size_t fileSize(fileStream->FileSize()); const size_t fileSize(fileStream->FileSize());
if (0 == fileSize) { if (0 == fileSize) {
throw DeadlyImportError("File " + pFile + " is empty."); throw DeadlyImportError("File ", pFile, " is empty.");
} }
IOStreamBuffer<char> streamedBuffer(1024 * 1024); IOStreamBuffer<char> streamedBuffer(1024 * 1024);

View File

@ -180,7 +180,7 @@ const aiImporterDesc *Q3BSPFileImporter::GetInfo() const {
void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, IOSystem *ioHandler) { void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, IOSystem *ioHandler) {
ZipArchiveIOSystem Archive(ioHandler, rFile); ZipArchiveIOSystem Archive(ioHandler, rFile);
if (!Archive.isOpen()) { if (!Archive.isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile + "."); throw DeadlyImportError("Failed to open file ", rFile, ".");
} }
std::string archiveName(""), mapName(""); std::string archiveName(""), mapName("");

View File

@ -110,13 +110,12 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
// The header is 22 bytes large // The header is 22 bytes large
if (stream.GetRemainingSize() < 22) if (stream.GetRemainingSize() < 22)
throw DeadlyImportError("File is either empty or corrupt: " + pFile); throw DeadlyImportError("File is either empty or corrupt: ", pFile);
// Check the file's signature // Check the file's signature
if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) && if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) &&
ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) { ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) {
throw DeadlyImportError("Not a Quick3D file. Signature string is: " + throw DeadlyImportError("Not a Quick3D file. Signature string is: ", std::string((const char *)stream.GetPtr(), 8));
std::string((const char *)stream.GetPtr(), 8));
} }
// Print the file format version // Print the file format version

View File

@ -101,7 +101,7 @@ void RAWImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open RAW file " + pFile + "."); throw DeadlyImportError("Failed to open RAW file ", pFile, ".");
} }
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer

View File

@ -59,7 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StreamReader.h> #include <assimp/StreamReader.h>
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#ifdef ASSIMP_USE_HUNTER #ifdef ASSIMP_USE_HUNTER
#include <utf8/utf8.h> #include <utf8.h>
#else #else
//# include "../contrib/ConvertUTF/ConvertUTF.h" //# include "../contrib/ConvertUTF/ConvertUTF.h"
#include "../contrib/utf8cpp/source/utf8.h" #include "../contrib/utf8cpp/source/utf8.h"
@ -808,7 +808,7 @@ void SIBImporter::InternReadFile(const std::string &pFile,
// We should have at least one chunk // We should have at least one chunk
if (stream.GetRemainingSize() < 16) if (stream.GetRemainingSize() < 16)
throw DeadlyImportError("SIB file is either empty or corrupt: " + pFile); throw DeadlyImportError("SIB file is either empty or corrupt: ", pFile);
SIB sib; SIB sib;

View File

@ -695,7 +695,7 @@ void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler) {
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open SMD/VTA file " + pFile + "."); throw DeadlyImportError("Failed to open SMD/VTA file ", pFile, ".");
} }
iFileSize = (unsigned int)file->FileSize(); iFileSize = (unsigned int)file->FileSize();

View File

@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "STEPFileEncoding.h" #include "STEPFileEncoding.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#ifdef ASSIMP_USE_HUNTER #ifdef ASSIMP_USE_HUNTER
# include <utf8/utf8.h> # include <utf8.h>
#else #else
# include <contrib/utf8cpp/source/utf8.h> # include <contrib/utf8cpp/source/utf8.h>
#endif #endif

View File

@ -181,7 +181,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open STL file " + pFile + "."); throw DeadlyImportError("Failed to open STL file ", pFile, ".");
} }
mFileSize = (unsigned int)file->FileSize(); mFileSize = (unsigned int)file->FileSize();
@ -207,7 +207,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
} else if (IsAsciiSTL(mBuffer, mFileSize)) { } else if (IsAsciiSTL(mBuffer, mFileSize)) {
LoadASCIIFile(mScene->mRootNode); LoadASCIIFile(mScene->mRootNode);
} else { } else {
throw DeadlyImportError("Failed to determine STL storage representation for " + pFile + "."); throw DeadlyImportError("Failed to determine STL storage representation for ", pFile, ".");
} }
// create a single default material, using a white diffuse color for consistency with // create a single default material, using a white diffuse color for consistency with

View File

@ -54,10 +54,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4127 4456 4245 4512 ) # pragma warning(disable : 4127 4456 4245 4512 )
#endif // _WIN32 #endif // _MSC_VER
// //
#if _MSC_VER > 1500 || (defined __GNUC___) #if _MSC_VER > 1500 || (defined __GNUC___)
@ -130,8 +130,8 @@ namespace STEP {
* coupled with a line number. */ * coupled with a line number. */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct SyntaxError : DeadlyImportError { struct SyntaxError : DeadlyImportError {
enum { enum : uint64_t {
LINE_NOT_SPECIFIED = 0xffffffffffffffffLL LINE_NOT_SPECIFIED = 0xfffffffffffffffLL
}; };
SyntaxError(const std::string &s, uint64_t line = LINE_NOT_SPECIFIED); SyntaxError(const std::string &s, uint64_t line = LINE_NOT_SPECIFIED);
@ -143,8 +143,8 @@ struct SyntaxError : DeadlyImportError {
* It is typically coupled with both an entity id and a line number.*/ * It is typically coupled with both an entity id and a line number.*/
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct TypeError : DeadlyImportError { struct TypeError : DeadlyImportError {
enum { enum : uint64_t {
ENTITY_NOT_SPECIFIED = 0xffffffffffffffffLL, ENTITY_NOT_SPECIFIED = 0xffffffffffffffffUL,
ENTITY_NOT_SPECIFIED_32 = 0x00000000ffffffff ENTITY_NOT_SPECIFIED_32 = 0x00000000ffffffff
}; };
@ -727,7 +727,7 @@ struct InternGenericConvert<Maybe<T>> {
} }
}; };
#ifdef _WIN32 #if _MSC_VER > 1920
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif // _WIN32 #endif // _WIN32
@ -960,9 +960,9 @@ private:
const EXPRESS::ConversionSchema *schema; const EXPRESS::ConversionSchema *schema;
}; };
#ifdef _WIN32 #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
} // namespace STEP } // namespace STEP

View File

@ -121,7 +121,7 @@ void TerragenImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file // Check whether we can read from the file
if (file == nullptr) if (file == nullptr)
throw DeadlyImportError("Failed to open TERRAGEN TERRAIN file " + pFile + "."); throw DeadlyImportError("Failed to open TERRAGEN TERRAIN file ", pFile, ".");
// Construct a stream reader to read all data in the correct endianness // Construct a stream reader to read all data in the correct endianness
StreamReaderLE reader(file); StreamReaderLE reader(file);

View File

@ -114,7 +114,7 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I
// read file into memory // read file into memory
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile)); std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
if ( file.get() == nullptr ) { if ( file.get() == nullptr ) {
throw DeadlyImportError( "Failed to open file " + pFile + "." ); throw DeadlyImportError( "Failed to open file ", pFile, "." );
} }
static const size_t MinSize = 16; static const size_t MinSize = 16;

View File

@ -82,6 +82,17 @@ static void dummy_free(void * /*opaque*/, void *address) {
#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
// ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text.
template<typename... T>
AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) {
if (mIsBinaryFormat) {
throw DeadlyImportError(args...);
} else {
throw DeadlyImportError("Line ", mLineNumber, ": ", args...);
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. Creates a data structure out of the XFile given in the memory block. // Constructor. Creates a data structure out of the XFile given in the memory block.
XFileParser::XFileParser(const std::vector<char> &pBuffer) : XFileParser::XFileParser(const std::vector<char> &pBuffer) :
@ -122,13 +133,13 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
mIsBinaryFormat = true; mIsBinaryFormat = true;
compressed = true; compressed = true;
} else } else
ThrowException(format() << "Unsupported xfile format '" << mP[8] << mP[9] << mP[10] << mP[11] << "'"); ThrowException("Unsupported xfile format '", mP[8], mP[9], mP[10], mP[11], "'");
// float size // float size
mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48); mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48);
if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64) if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
ThrowException(format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header."); ThrowException("Unknown float size ", mBinaryFloatSize, " specified in xfile header.");
// The x format specifies size in bits, but we work in bytes // The x format specifies size in bits, but we work in bytes
mBinaryFloatSize /= 8; mBinaryFloatSize /= 8;
@ -864,7 +875,7 @@ void XFileParser::ParseDataObjectAnimationKey(AnimBone *pAnimBone) {
} }
default: default:
ThrowException(format() << "Unknown key type " << keyType << " in animation."); ThrowException("Unknown key type ", keyType, " in animation.");
break; break;
} // end switch } // end switch
@ -1355,16 +1366,6 @@ aiColor3D XFileParser::ReadRGB() {
return color; return color;
} }
// ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text.
AI_WONT_RETURN void XFileParser::ThrowException(const std::string &pText) {
if (mIsBinaryFormat) {
throw DeadlyImportError(pText);
} else {
throw DeadlyImportError(format() << "Line " << mLineNumber << ": " << pText);
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Filters the imported hierarchy for some degenerated cases that some exporters produce. // Filters the imported hierarchy for some degenerated cases that some exporters produce.
void XFileParser::FilterHierarchy(XFile::Node *pNode) { void XFileParser::FilterHierarchy(XFile::Node *pNode) {

View File

@ -133,7 +133,8 @@ protected:
aiColor4D ReadRGBA(); aiColor4D ReadRGBA();
/** Throws an exception with a line number and the given text. */ /** Throws an exception with a line number and the given text. */
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX; template<typename... T>
AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX;
/** /**
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce. * @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.

View File

@ -155,99 +155,37 @@ void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode)); std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
if (!fileStream.get()) { if (!fileStream.get()) {
throw DeadlyImportError("Failed to open file " + file + "."); throw DeadlyImportError("Failed to open file " + file + ".");
} }
} }
/*********************************************************************************************************************************************/ bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig ) const {
/************************************************************ Functions: find set ************************************************************/ if (checkSig) {
/*********************************************************************************************************************************************/ std::string::size_type pos = pFile.find_last_of(".x3d");
if (pos != std::string::npos) {
bool X3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const { return true;
const std::string extension = GetExtension(pFile); }
if ((extension == "x3d") || (extension == "x3db")) {
return true;
}
if (!extension.length() || pCheckSig) {
const char *tokens[] = { "DOCTYPE X3D PUBLIC", "http://www.web3d.org/specifications/x3d" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
} }
return false; return false;
} }
void X3DImporter::GetExtensionList(std::set<std::string> &pExtensionList) { void X3DImporter::GetExtensionList( std::set<std::string> &extensionList ) {
pExtensionList.insert("x3d"); extensionList.insert("x3d");
pExtensionList.insert("x3db"); }
void X3DImporter::InternReadFile( const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler ) {
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (!stream) {
throw DeadlyImportError("Could not open file for reading");
}
pScene->mRootNode = new aiNode(pFile);
} }
const aiImporterDesc *X3DImporter::GetInfo() const { const aiImporterDesc *X3DImporter::GetInfo() const {
return &Description; return &Description;
} }
void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
mpIOHandler = pIOHandler;
Clear(); // delete old graph.
std::string::size_type slashPos = pFile.find_last_of("\\/");
pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
ParseFile(pFile, pIOHandler);
pIOHandler->PopDirectory();
if (NodeElement_List.empty())
return;
//
// Assimp use static arrays of objects for fast speed of rendering. That's good, but need some additional operations/
// We know that geometry objects(meshes) are stored in <Shape>, also in <Shape>-><Appearance> materials(in Assimp logical view)
// are stored. So at first we need to count how meshes and materials are stored in scene graph.
//
// at first creating root node for aiScene.
pScene->mRootNode = new aiNode;
pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
//search for root node element
mNodeElementCur = NodeElement_List.front();
while (mNodeElementCur->Parent != nullptr)
mNodeElementCur = mNodeElementCur->Parent;
{ // fill aiScene with objects.
std::list<aiMesh *> mesh_list;
std::list<aiMaterial *> mat_list;
std::list<aiLight *> light_list;
// create nodes tree
// Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list);
// copy needed data to scene
if (!mesh_list.empty()) {
std::list<aiMesh *>::const_iterator it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (size_t i = 0; i < pScene->mNumMeshes; i++)
pScene->mMeshes[i] = *it++;
}
if (!mat_list.empty()) {
std::list<aiMaterial *>::const_iterator it = mat_list.begin();
pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size());
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
for (size_t i = 0; i < pScene->mNumMaterials; i++)
pScene->mMaterials[i] = *it++;
}
if (!light_list.empty()) {
std::list<aiLight *>::const_iterator it = light_list.begin();
pScene->mNumLights = static_cast<unsigned int>(light_list.size());
pScene->mLights = new aiLight *[pScene->mNumLights];
for (size_t i = 0; i < pScene->mNumLights; i++)
pScene->mLights[i] = *it++;
}
}
} }
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GLTFASSET_H_INC #ifndef GLTFASSET_H_INC
#define GLTFASSET_H_INC #define GLTFASSET_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_IMPORTER)
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -60,19 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
#ifndef RAPIDJSON_HAS_STDSTRING
#define RAPIDJSON_HAS_STDSTRING 1
#endif
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0) #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif #endif
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#define RAPIDJSON_NOMEMBERITERATORCLASS
#endif
#include <rapidjson/rapidjson.h> #include <rapidjson/rapidjson.h>
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>

View File

@ -57,10 +57,10 @@ namespace glTF {
namespace { namespace {
#ifdef _WIN32 #if _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4706) # pragma warning(disable : 4706)
#endif // _WIN32 #endif // _MSC_VER
// //
// JSON Value reading helpers // JSON Value reading helpers
@ -235,15 +235,15 @@ Ref<T> LazyDict<T>::Get(const char *id) {
// read it from the JSON object // read it from the JSON object
if (!mDict) { if (!mDict) {
throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\""); throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
} }
Value::MemberIterator obj = mDict->FindMember(id); Value::MemberIterator obj = mDict->FindMember(id);
if (obj == mDict->MemberEnd()) { if (obj == mDict->MemberEnd()) {
throw DeadlyImportError("GLTF: Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\""); throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
} }
if (!obj->value.IsObject()) { if (!obj->value.IsObject()) {
throw DeadlyImportError("GLTF: Object with id \"" + std::string(id) + "\" is not a JSON object"); throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
} }
// create an instance of the given type // create an instance of the given type
@ -317,13 +317,13 @@ inline void Buffer::Read(Value &obj, Asset &r) {
this->mData.reset(data, std::default_delete<uint8_t[]>()); this->mData.reset(data, std::default_delete<uint8_t[]>());
if (statedLength > 0 && this->byteLength != statedLength) { if (statedLength > 0 && this->byteLength != statedLength) {
throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength),
" bytes, but found " + to_string(dataURI.dataLength)); " bytes, but found ", to_string(dataURI.dataLength));
} }
} else { // assume raw data } else { // assume raw data
if (statedLength != dataURI.dataLength) { if (statedLength != dataURI.dataLength) {
throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength),
" bytes, but found " + to_string(dataURI.dataLength)); " bytes, but found ", to_string(dataURI.dataLength));
} }
this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>()); this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
@ -339,9 +339,9 @@ inline void Buffer::Read(Value &obj, Asset &r) {
delete file; delete file;
if (!ok) if (!ok)
throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\""); throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
} else { } else {
throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\""); throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
} }
} }
} }
@ -372,8 +372,8 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod
char val[val_size]; char val[val_size];
ai_snprintf(val, val_size, "%llu", (long long)pOffset); ai_snprintf(val, val_size, AI_SIZEFMT, pOffset);
throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region."); throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region.");
} }
// Check length // Check length
@ -382,8 +382,8 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod
char val[val_size]; char val[val_size];
ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length); ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length);
throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range."); throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range.");
} }
// Add new region // Add new region
@ -403,7 +403,7 @@ inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
} }
} }
throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found."); throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found.");
} }
inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) { inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
@ -836,8 +836,8 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
if (json_extensions == nullptr) goto mr_skip_extensions; if (json_extensions == nullptr) goto mr_skip_extensions;
for (Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) {
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
for (Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) {
if (it_memb->name.GetString() == std::string("Open3DGC-compression")) { if (it_memb->name.GetString() == std::string("Open3DGC-compression")) {
// Search for compressed data. // Search for compressed data.
// Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and // Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
@ -851,7 +851,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
/************** Read data from JSON-document **************/ /************** Read data from JSON-document **************/
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
if (!ReadMember(*comp_data, pFieldName, pOut)) { \ if (!ReadMember(*comp_data, pFieldName, pOut)) { \
throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \ throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
} }
const char *mode_str; const char *mode_str;
@ -880,18 +880,18 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
else if (strcmp(mode_str, "ascii") == 0) else if (strcmp(mode_str, "ascii") == 0)
ext_o3dgc->Binary = false; ext_o3dgc->Binary = false;
else else
throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\"."); throw DeadlyImportError("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"", mode_str, "\".");
/************************ Decoding ************************/ /************************ Decoding ************************/
Decode_O3DGC(*ext_o3dgc, pAsset_Root); Decode_O3DGC(*ext_o3dgc, pAsset_Root);
Extension.push_back(ext_o3dgc); // store info in mesh extensions list. Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
} // if(it_memb->name.GetString() == "Open3DGC-compression") } // if(it_memb->name.GetString() == "Open3DGC-compression")
else else
#endif
{ {
throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\"."); throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
} }
} // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++) } // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
#endif
mr_skip_extensions: mr_skip_extensions:
@ -923,24 +923,24 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
size_t size_coordindex = ifs.GetNCoordIndex() * 3; // See float attributes note. size_t size_coordindex = ifs.GetNCoordIndex() * 3; // See float attributes note.
if (primitives[0].indices->count != size_coordindex) if (primitives[0].indices->count != size_coordindex)
throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + to_string(size_coordindex) + throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (", to_string(size_coordindex),
") not equal to uncompressed (" + to_string(primitives[0].indices->count) + ")."); ") not equal to uncompressed (", to_string(primitives[0].indices->count), ").");
size_coordindex *= sizeof(IndicesType); size_coordindex *= sizeof(IndicesType);
// Coordinates // Coordinates
size_t size_coord = ifs.GetNCoord(); // See float attributes note. size_t size_coord = ifs.GetNCoord(); // See float attributes note.
if (primitives[0].attributes.position[0]->count != size_coord) if (primitives[0].attributes.position[0]->count != size_coord)
throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + to_string(size_coord) + throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (", to_string(size_coord),
") not equal to uncompressed (" + to_string(primitives[0].attributes.position[0]->count) + ")."); ") not equal to uncompressed (", to_string(primitives[0].attributes.position[0]->count), ").");
size_coord *= 3 * sizeof(float); size_coord *= 3 * sizeof(float);
// Normals // Normals
size_t size_normal = ifs.GetNNormal(); // See float attributes note. size_t size_normal = ifs.GetNNormal(); // See float attributes note.
if (primitives[0].attributes.normal[0]->count != size_normal) if (primitives[0].attributes.normal[0]->count != size_normal)
throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + to_string(size_normal) + throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (", to_string(size_normal),
") not equal to uncompressed (" + to_string(primitives[0].attributes.normal[0]->count) + ")."); ") not equal to uncompressed (", to_string(primitives[0].attributes.normal[0]->count), ").");
size_normal *= 3 * sizeof(float); size_normal *= 3 * sizeof(float);
// Additional attributes. // Additional attributes.
@ -961,8 +961,8 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
// Check situation when encoded data contain texture coordinates but primitive not. // Check situation when encoded data contain texture coordinates but primitive not.
if (idx_texcoord < primitives[0].attributes.texcoord.size()) { if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
if (primitives[0].attributes.texcoord[idx]->count != tval) if (primitives[0].attributes.texcoord[idx]->count != tval)
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + to_string(tval) + throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", to_string(tval),
") not equal to uncompressed (" + to_string(primitives[0].attributes.texcoord[idx]->count) + ")."); ") not equal to uncompressed (", to_string(primitives[0].attributes.texcoord[idx]->count), ").");
idx_texcoord++; idx_texcoord++;
} else { } else {
@ -971,7 +971,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
break; break;
default: default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))); throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
} }
tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array. tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array.
@ -990,7 +990,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
break; break;
default: default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx)))); throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
} }
tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note. tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note.
@ -1025,7 +1025,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
break; break;
default: default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))); throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
} }
} }
@ -1039,7 +1039,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint))); // ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
default: default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx)))); throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
} }
} }
@ -1231,7 +1231,7 @@ inline void AssetMetadata::Read(Document &doc) {
} }
if (version.empty() || version[0] != '1') { if (version.empty() || version[0] != '1') {
throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
} }
} }
@ -1309,7 +1309,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
if (doc.HasParseError()) { if (doc.HasParseError()) {
char buffer[32]; char buffer[32];
ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset())); ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": " + GetParseError_En(doc.GetParseError())); throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
} }
if (!doc.IsObject()) { if (!doc.IsObject()) {
@ -1412,8 +1412,8 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
return id; return id;
} }
#ifdef _WIN32 #if _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // WIN32 #endif // _MSC_VER
} // namespace glTF } // namespace glTF

View File

@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GLTFASSETWRITER_H_INC #ifndef GLTFASSETWRITER_H_INC
#define GLTFASSETWRITER_H_INC #define GLTFASSETWRITER_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_IMPORTER)
#include "glTFAsset.h" #include "glTFAsset.h"

View File

@ -43,10 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rapidjson/writer.h> #include <rapidjson/writer.h>
#include <rapidjson/prettywriter.h> #include <rapidjson/prettywriter.h>
#ifdef _WIN32 #if _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning( disable : 4706) # pragma warning( disable : 4706)
#endif // _WIN32 #endif // _MSC_VER
namespace glTF { namespace glTF {
@ -305,11 +305,11 @@ namespace glTF {
Value json_extensions; Value json_extensions;
json_extensions.SetObject(); json_extensions.SetObject();
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
for(Mesh::SExtension* ptr_ext : m.Extension) for(Mesh::SExtension* ptr_ext : m.Extension)
{ {
switch(ptr_ext->Type) switch(ptr_ext->Type)
{ {
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
case Mesh::SExtension::EType::Compression_Open3DGC: case Mesh::SExtension::EType::Compression_Open3DGC:
{ {
Value json_comp_data; Value json_comp_data;
@ -339,11 +339,11 @@ namespace glTF {
} }
break; break;
#endif
default: default:
throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported."); throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
}// switch(ptr_ext->Type) }// switch(ptr_ext->Type)
}// for(Mesh::SExtension* ptr_ext : m.Extension) }// for(Mesh::SExtension* ptr_ext : m.Extension)
#endif
// Add extensions to mesh // Add extensions to mesh
obj.AddMember("extensions", json_extensions, w.mAl); obj.AddMember("extensions", json_extensions, w.mAl);
@ -707,7 +707,7 @@ namespace glTF {
w.WriteObjects(d); w.WriteObjects(d);
} }
#ifdef _WIN32 #if _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _WIN32

View File

@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
#include "AssetLib/glTF/glTFCommon.h" #include "AssetLib/glTF/glTFCommon.h"
namespace glTFCommon { namespace glTFCommon {
@ -187,3 +189,5 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out) {
} // namespace Util } // namespace Util
} // namespace glTFCommon } // namespace glTFCommon
#endif

View File

@ -52,8 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#define RAPIDJSON_HAS_STDSTRING 1
#define RAPIDJSON_NOMEMBERITERATORCLASS
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>
#include <rapidjson/rapidjson.h> #include <rapidjson/rapidjson.h>
@ -190,10 +188,10 @@ inline void CopyValue(const glTFCommon::mat4 &v, aiMatrix4x4 &o) {
o.d4 = v[15]; o.d4 = v[15];
} }
#ifdef _WIN32 #if _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4310) # pragma warning(disable : 4310)
#endif // _WIN32 #endif // _MSC_VER
inline std::string getCurrentAssetDir(const std::string &pFile) { inline std::string getCurrentAssetDir(const std::string &pFile) {
std::string path = pFile; std::string path = pFile;
@ -204,9 +202,9 @@ inline std::string getCurrentAssetDir(const std::string &pFile) {
return path; return path;
} }
#ifdef _WIN32 #if _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
namespace Util { namespace Util {

View File

@ -525,6 +525,12 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref<Mesh>& meshRef, Ref<Buf
delete[] vertexJointData; delete[] vertexJointData;
} }
#if defined(__has_warning)
#if __has_warning("-Wunused-but-set-variable")
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
#endif
void glTFExporter::ExportMeshes() void glTFExporter::ExportMeshes()
{ {
// Not for // Not for
@ -536,10 +542,12 @@ void glTFExporter::ExportMeshes()
// Variables needed for compression. BEGIN. // Variables needed for compression. BEGIN.
// Indices, not pointers - because pointer to buffer is changing while writing to it. // Indices, not pointers - because pointer to buffer is changing while writing to it.
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
size_t idx_srcdata_begin = 0; // Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer. size_t idx_srcdata_begin = 0; // Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals. size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer. size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
#endif
std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
bool comp_allow;// Point that data of current mesh can be compressed. bool comp_allow;// Point that data of current mesh can be compressed.
// Variables needed for compression. END. // Variables needed for compression. END.
@ -609,13 +617,17 @@ void glTFExporter::ExportMeshes()
/******************* Vertices ********************/ /******************* Vertices ********************/
// If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored. // If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored.
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
if(comp_allow) idx_srcdata_begin = b->byteLength; if(comp_allow) idx_srcdata_begin = b->byteLength;
#endif
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (v) p.attributes.position.push_back(v); if (v) p.attributes.position.push_back(v);
/******************** Normals ********************/ /******************** Normals ********************/
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
if(comp_allow && (aim->mNormals != 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array. if(comp_allow && (aim->mNormals != 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array.
#endif
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (n) p.attributes.normal.push_back(n); if (n) p.attributes.normal.push_back(n);
@ -640,7 +652,9 @@ void glTFExporter::ExportMeshes()
} }
/*************** Vertices indices ****************/ /*************** Vertices indices ****************/
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
idx_srcdata_ind = b->byteLength;// Store index of indices array. idx_srcdata_ind = b->byteLength;// Store index of indices array.
#endif
if (aim->mNumFaces > 0) { if (aim->mNumFaces > 0) {
std::vector<IndicesType> indices; std::vector<IndicesType> indices;
@ -677,7 +691,7 @@ void glTFExporter::ExportMeshes()
{ {
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
// Only one type of compression supported at now - Open3DGC. // Only one type of compression supported at now - Open3DGC.
// //
o3dgc::BinaryStream bs; o3dgc::BinaryStream bs;
o3dgc::SC3DMCEncoder<IndicesType> encoder; o3dgc::SC3DMCEncoder<IndicesType> encoder;
o3dgc::IndexedFaceSet<IndicesType> comp_o3dgc_ifs; o3dgc::IndexedFaceSet<IndicesType> comp_o3dgc_ifs;
@ -793,6 +807,12 @@ void glTFExporter::ExportMeshes()
} }
} }
#if defined(__has_warning)
#if __has_warning("-Wunused-but-set-variable")
#pragma GCC diagnostic pop
#endif
#endif
/* /*
* Export the root node of the node hierarchy. * Export the root node of the node hierarchy.
* Calls ExportNode for all children. * Calls ExportNode for all children.

View File

@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_GLTFEXPORTER_H_INC #ifndef AI_GLTFEXPORTER_H_INC
#define AI_GLTFEXPORTER_H_INC #define AI_GLTFEXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER)
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/material.h> #include <assimp/material.h>

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_IMPORTER)
#include "AssetLib/glTF/glTFImporter.h" #include "AssetLib/glTF/glTFImporter.h"
#include "AssetLib/glTF/glTFAsset.h" #include "AssetLib/glTF/glTFAsset.h"
@ -215,8 +215,8 @@ void glTFImporter::ImportMeshes(glTF::Asset &r) {
// Check if mesh extensions is used // Check if mesh extensions is used
if (mesh.Extension.size() > 0) { if (mesh.Extension.size() > 0) {
for (Mesh::SExtension *cur_ext : mesh.Extension) {
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
for (Mesh::SExtension *cur_ext : mesh.Extension) {
if (cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC) { if (cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC) {
// Limitations for meshes when using Open3DGC-compression. // Limitations for meshes when using Open3DGC-compression.
// It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive? // It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive?
@ -233,12 +233,12 @@ void glTFImporter::ImportMeshes(glTF::Asset &r) {
buf->EncodedRegion_SetCurrent(mesh.id); buf->EncodedRegion_SetCurrent(mesh.id);
} else } else
#endif
{ {
throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"" + to_string(cur_ext->Type) + throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"", to_string(cur_ext->Type),
"\"), only Open3DGC is supported."); "\"), only Open3DGC is supported.");
} }
} }
#endif
} // if(mesh.Extension.size() > 0) } // if(mesh.Extension.size() > 0)
meshOffsets.push_back(k); meshOffsets.push_back(k);

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GLTF2ASSET_H_INC #ifndef GLTF2ASSET_H_INC
#define GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -62,19 +62,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#ifndef RAPIDJSON_HAS_STDSTRING
#define RAPIDJSON_HAS_STDSTRING 1
#endif
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0) #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif #endif
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#define RAPIDJSON_NOMEMBERITERATORCLASS
#endif
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>
#include <rapidjson/rapidjson.h> #include <rapidjson/rapidjson.h>
@ -202,7 +194,7 @@ inline unsigned int ComponentTypeSize(ComponentType t) {
case ComponentType_UNSIGNED_BYTE: case ComponentType_UNSIGNED_BYTE:
return 1; return 1;
default: default:
throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t)); throw DeadlyImportError("GLTF: Unsupported Component Type ", to_string(t));
} }
} }
@ -406,6 +398,8 @@ struct Accessor : public Object {
void ExtractData(T *&outData); void ExtractData(T *&outData);
void WriteData(size_t count, const void *src_buffer, size_t src_stride); void WriteData(size_t count, const void *src_buffer, size_t src_stride);
void WriteSparseValues(size_t count, const void *src_data, size_t src_dataStride);
void WriteSparseIndices(size_t count, const void *src_idx, size_t src_idxStride);
//! Helper class to iterate the data //! Helper class to iterate the data
class Indexer { class Indexer {
@ -802,7 +796,7 @@ struct CustomExtension : public Object {
Nullable<std::vector<CustomExtension>> mValues; Nullable<std::vector<CustomExtension>> mValues;
operator bool() const { operator bool() const {
return Size(); return Size() != 0;
} }
size_t Size() const { size_t Size() const {
@ -1066,6 +1060,7 @@ public:
} extensionsRequired; } extensionsRequired;
AssetMetadata asset; AssetMetadata asset;
Value* extras = nullptr;
// Dictionaries for each type of object // Dictionaries for each type of object

View File

@ -269,21 +269,21 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
// read it from the JSON object // read it from the JSON object
if (!mDict) { if (!mDict) {
throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\""); throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
} }
if (!mDict->IsArray()) { if (!mDict->IsArray()) {
throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\""); throw DeadlyImportError("GLTF: Field is not an array \"", mDictId, "\"");
} }
Value &obj = (*mDict)[i]; Value &obj = (*mDict)[i];
if (!obj.IsObject()) { if (!obj.IsObject()) {
throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object"); throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" is not a JSON object");
} }
if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) { if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" has recursive reference to itself"); throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" has recursive reference to itself");
} }
mRecursiveReferenceCheck.insert(i); mRecursiveReferenceCheck.insert(i);
@ -381,13 +381,13 @@ inline void Buffer::Read(Value &obj, Asset &r) {
this->mData.reset(data, std::default_delete<uint8_t[]>()); this->mData.reset(data, std::default_delete<uint8_t[]>());
if (statedLength > 0 && this->byteLength != statedLength) { if (statedLength > 0 && this->byteLength != statedLength) {
throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength),
" bytes, but found " + to_string(dataURI.dataLength)); " bytes, but found ", to_string(dataURI.dataLength));
} }
} else { // assume raw data } else { // assume raw data
if (statedLength != dataURI.dataLength) { if (statedLength != dataURI.dataLength) {
throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength),
" bytes, but found " + to_string(dataURI.dataLength)); " bytes, but found ", to_string(dataURI.dataLength));
} }
this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>()); this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
@ -403,9 +403,9 @@ inline void Buffer::Read(Value &obj, Asset &r) {
delete file; delete file;
if (!ok) if (!ok)
throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\""); throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
} else { } else {
throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\""); throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
} }
} }
} }
@ -436,8 +436,8 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod
char val[val_size]; char val[val_size];
ai_snprintf(val, val_size, "%llu", (long long)pOffset); ai_snprintf(val, val_size, AI_SIZEFMT, pOffset);
throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region."); throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region.");
} }
// Check length // Check length
@ -446,8 +446,8 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod
char val[val_size]; char val[val_size];
ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length); ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length);
throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range."); throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range.");
} }
// Add new region // Add new region
@ -467,7 +467,7 @@ inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
} }
} }
throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found."); throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found.");
} }
inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) { inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
@ -731,8 +731,14 @@ void Accessor::ExtractData(T *&outData) {
const size_t stride = bufferView && bufferView->byteStride ? bufferView->byteStride : elemSize; const size_t stride = bufferView && bufferView->byteStride ? bufferView->byteStride : elemSize;
const size_t targetElemSize = sizeof(T); const size_t targetElemSize = sizeof(T);
ai_assert(elemSize <= targetElemSize);
ai_assert(count * stride <= (bufferView ? bufferView->byteLength : sparse->data.size())); if (elemSize > targetElemSize) {
throw DeadlyImportError("GLTF: elemSize > targetElemSize");
}
if (count*stride > (bufferView ? bufferView->byteLength : sparse->data.size())) {
throw DeadlyImportError("GLTF: count*stride out of range");
}
outData = new T[count]; outData = new T[count];
if (stride == elemSize && targetElemSize == elemSize) { if (stride == elemSize && targetElemSize == elemSize) {
@ -757,6 +763,33 @@ inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t sr
CopyData(_count, src, src_stride, dst, dst_stride); CopyData(_count, src, src_stride, dst, dst_stride);
} }
inline void Accessor::WriteSparseValues(size_t _count, const void *src_data, size_t src_dataStride) {
if (!sparse)
return;
// values
uint8_t *value_buffer_ptr = sparse->values->buffer->GetPointer();
size_t value_offset = sparse->valuesByteOffset + sparse->values->byteOffset;
size_t value_dst_stride = GetNumComponents() * GetBytesPerComponent();
const uint8_t *value_src = reinterpret_cast<const uint8_t *>(src_data);
uint8_t *value_dst = reinterpret_cast<uint8_t *>(value_buffer_ptr + value_offset);
ai_assert(value_dst + _count * value_dst_stride <= value_buffer_ptr + sparse->values->buffer->byteLength);
CopyData(_count, value_src, src_dataStride, value_dst, value_dst_stride);
}
inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, size_t src_idxStride) {
if (!sparse)
return;
// indices
uint8_t *indices_buffer_ptr = sparse->indices->buffer->GetPointer();
size_t indices_offset = sparse->indicesByteOffset + sparse->indices->byteOffset;
size_t indices_dst_stride = 1 * sizeof(unsigned short);
const uint8_t *indices_src = reinterpret_cast<const uint8_t *>(src_idx);
uint8_t *indices_dst = reinterpret_cast<uint8_t *>(indices_buffer_ptr + indices_offset);
ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
}
inline Accessor::Indexer::Indexer(Accessor &acc) : inline Accessor::Indexer::Indexer(Accessor &acc) :
accessor(acc), accessor(acc),
data(acc.GetPointer()), data(acc.GetPointer()),
@ -1015,10 +1048,10 @@ inline int Compare(const char *attr, const char (&str)[N]) {
return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0; return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
} }
#ifdef _WIN32 #if _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4706) #pragma warning(disable : 4706)
#endif // _WIN32 #endif // _MSC_VER
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) { inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
if ((pos = Compare(attr, "POSITION"))) { if ((pos = Compare(attr, "POSITION"))) {
@ -1287,6 +1320,8 @@ inline void Node::Read(Value &obj, Asset &r) {
} }
} }
// Do not retrieve a skin here, just take a reference, to avoid infinite recursion
// Skins will be properly loaded later
Value *curSkin = FindUInt(obj, "skin"); Value *curSkin = FindUInt(obj, "skin");
if (nullptr != curSkin) { if (nullptr != curSkin) {
this->skin = r.skins.Get(curSkin->GetUint()); this->skin = r.skins.Get(curSkin->GetUint());
@ -1429,7 +1464,7 @@ inline void AssetMetadata::Read(Document &doc) {
} }
if (version.empty() || version[0] != '2') { if (version.empty() || version[0] != '2') {
throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
} }
} }
@ -1541,7 +1576,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
if (doc.HasParseError()) { if (doc.HasParseError()) {
char buffer[32]; char buffer[32];
ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset())); ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": " + GetParseError_En(doc.GetParseError())); throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
} }
if (!doc.IsObject()) { if (!doc.IsObject()) {
@ -1584,7 +1619,6 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
} }
} }
// Read skins after nodes have been loaded to avoid infinite recursion
if (Value *skinsArray = FindArray(doc, "skins")) { if (Value *skinsArray = FindArray(doc, "skins")) {
for (unsigned int i = 0; i < skinsArray->Size(); ++i) { for (unsigned int i = 0; i < skinsArray->Size(); ++i) {
skins.Retrieve(i); skins.Retrieve(i);
@ -1695,8 +1729,8 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
return id; return id;
} }
#ifdef _WIN32 #if _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
} // namespace glTF2 } // namespace glTF2

View File

@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GLTF2ASSETWRITER_H_INC #ifndef GLTF2ASSETWRITER_H_INC
#define GLTF2ASSETWRITER_H_INC #define GLTF2ASSETWRITER_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
#include "glTF2Asset.h" #include "glTF2Asset.h"

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -107,21 +107,47 @@ namespace glTF2 {
inline void Write(Value& obj, Accessor& a, AssetWriter& w) inline void Write(Value& obj, Accessor& a, AssetWriter& w)
{ {
obj.AddMember("bufferView", a.bufferView->index, w.mAl); if (a.bufferView) {
obj.AddMember("byteOffset", (unsigned int)a.byteOffset, w.mAl); obj.AddMember("bufferView", a.bufferView->index, w.mAl);
obj.AddMember("byteOffset", (unsigned int)a.byteOffset, w.mAl);
Value vTmpMax, vTmpMin;
if (a.componentType == ComponentType_FLOAT) {
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else {
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
}
}
obj.AddMember("componentType", int(a.componentType), w.mAl); obj.AddMember("componentType", int(a.componentType), w.mAl);
obj.AddMember("count", (unsigned int)a.count, w.mAl); obj.AddMember("count", (unsigned int)a.count, w.mAl);
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
Value vTmpMax, vTmpMin; if (a.sparse) {
if (a.componentType == ComponentType_FLOAT) { Value sparseValue;
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); sparseValue.SetObject();
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else { //count
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl); sparseValue.AddMember("count", (unsigned int)a.sparse->count, w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
} //indices
Value indices;
indices.SetObject();
indices.AddMember("bufferView", a.sparse->indices->index, w.mAl);
indices.AddMember("byteOffset", (unsigned int)a.sparse->indicesByteOffset, w.mAl);
indices.AddMember("componentType", int(a.sparse->indicesType), w.mAl);
sparseValue.AddMember("indices", indices, w.mAl);
//values
Value values;
values.SetObject();
values.AddMember("bufferView", a.sparse->values->index, w.mAl);
values.AddMember("byteOffset", (unsigned int)a.sparse->valuesByteOffset, w.mAl);
sparseValue.AddMember("values", values, w.mAl);
obj.AddMember("sparse", sparseValue, w.mAl);
}
} }
inline void Write(Value& obj, Animation& a, AssetWriter& w) inline void Write(Value& obj, Animation& a, AssetWriter& w)
@ -616,6 +642,10 @@ namespace glTF2 {
if (mAsset.scene) { if (mAsset.scene) {
mDoc.AddMember("scene", mAsset.scene->index, mAl); mDoc.AddMember("scene", mAsset.scene->index, mAl);
} }
if(mAsset.extras) {
mDoc.AddMember("extras", *mAsset.extras, mAl);
}
} }
inline void AssetWriter::WriteFile(const char* path) inline void AssetWriter::WriteFile(const char* path)
@ -709,10 +739,13 @@ namespace glTF2 {
// Binary chunk // Binary chunk
// //
int GLB_Chunk_count = 1;
uint32_t binaryChunkLength = 0; uint32_t binaryChunkLength = 0;
if (bodyBuffer->byteLength > 0) { if (bodyBuffer->byteLength > 0) {
binaryChunkLength = (bodyBuffer->byteLength + 3) & ~3; // Round up to next multiple of 4 binaryChunkLength = (bodyBuffer->byteLength + 3) & ~3; // Round up to next multiple of 4
//auto curPaddingLength = binaryChunkLength - bodyBuffer->byteLength;
auto curPaddingLength = binaryChunkLength - bodyBuffer->byteLength;
++GLB_Chunk_count;
GLB_Chunk binaryChunk; GLB_Chunk binaryChunk;
binaryChunk.chunkLength = binaryChunkLength; binaryChunk.chunkLength = binaryChunkLength;
@ -727,7 +760,7 @@ namespace glTF2 {
if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) { if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) {
throw DeadlyExportError("Failed to write body data!"); throw DeadlyExportError("Failed to write body data!");
} }
if (paddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) { if (curPaddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) {
throw DeadlyExportError("Failed to write body data padding!"); throw DeadlyExportError("Failed to write body data padding!");
} }
} }
@ -742,7 +775,7 @@ namespace glTF2 {
header.version = 2; header.version = 2;
AI_SWAP4(header.version); AI_SWAP4(header.version);
header.length = uint32_t(sizeof(GLB_Header) + 2 * sizeof(GLB_Chunk) + jsonChunkLength + binaryChunkLength); header.length = uint32_t(sizeof(GLB_Header) + GLB_Chunk_count * sizeof(GLB_Chunk) + jsonChunkLength + binaryChunkLength);
AI_SWAP4(header.length); AI_SWAP4(header.length);
outfile->Seek(0, aiOrigin_SET); outfile->Seek(0, aiOrigin_SET);

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -116,6 +116,13 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
ExportAnimations(); ExportAnimations();
// export extras
if(mProperties->HasPropertyCallback("extras"))
{
std::function<void*(void*)> ExportExtras = mProperties->GetPropertyCallback("extras");
mAsset->extras = (rapidjson::Value*)ExportExtras(0);
}
AssetWriter writer(*mAsset); AssetWriter writer(*mAsset);
if (isBinary) { if (isBinary) {
@ -214,6 +221,158 @@ inline void SetAccessorRange(ComponentType compType, Ref<Accessor> acc, void* da
} }
} }
// compute the (data-dataBase), store the non-zero data items
template <typename T>
size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn, unsigned int numCompsOut, void *&outputNZDiff, void *&outputNZIdx) {
std::vector<T> vNZDiff;
std::vector<unsigned short> vNZIdx;
size_t totalComps = count * numCompsIn;
T *bufferData_ptr = static_cast<T *>(data);
T *bufferData_end = bufferData_ptr + totalComps;
T *bufferBase_ptr = static_cast<T *>(dataBase);
// Search and set extreme values.
for (short idx = 0; bufferData_ptr < bufferData_end; idx += 1, bufferData_ptr += numCompsIn) {
bool bNonZero = false;
//for the data, check any component Non Zero
for (unsigned int j = 0; j < numCompsOut; j++) {
double valueData = bufferData_ptr[j];
double valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
if ((valueData - valueBase) != 0) {
bNonZero = true;
break;
}
}
//all zeros, continue
if (!bNonZero)
continue;
//non zero, store the data
for (unsigned int j = 0; j < numCompsOut; j++) {
T valueData = bufferData_ptr[j];
T valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
vNZDiff.push_back(valueData - valueBase);
}
vNZIdx.push_back(idx);
}
//avoid all-0, put 1 item
if (vNZDiff.size() == 0) {
for (unsigned int j = 0; j < numCompsOut; j++)
vNZDiff.push_back(0);
vNZIdx.push_back(0);
}
//process data
outputNZDiff = new T[vNZDiff.size()];
memcpy(outputNZDiff, vNZDiff.data(), vNZDiff.size() * sizeof(T));
outputNZIdx = new unsigned short[vNZIdx.size()];
memcpy(outputNZIdx, vNZIdx.data(), vNZIdx.size() * sizeof(unsigned short));
return vNZIdx.size();
}
inline size_t NZDiff(ComponentType compType, void *data, void *dataBase, size_t count, unsigned int numCompsIn, unsigned int numCompsOut, void *&nzDiff, void *&nzIdx) {
switch (compType) {
case ComponentType_SHORT:
return NZDiff<short>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
case ComponentType_UNSIGNED_SHORT:
return NZDiff<unsigned short>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
case ComponentType_UNSIGNED_INT:
return NZDiff<unsigned int>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
case ComponentType_FLOAT:
return NZDiff<float>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
case ComponentType_BYTE:
return NZDiff<int8_t>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
case ComponentType_UNSIGNED_BYTE:
return NZDiff<uint8_t>(data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
}
return 0;
}
inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffer> &buffer,
size_t count, void *data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, BufferViewTarget target = BufferViewTarget_NONE, void *dataBase = 0) {
if (!count || !data) {
return Ref<Accessor>();
}
unsigned int numCompsIn = AttribType::GetNumComponents(typeIn);
unsigned int numCompsOut = AttribType::GetNumComponents(typeOut);
unsigned int bytesPerComp = ComponentTypeSize(compType);
// accessor
Ref<Accessor> acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor"));
// if there is a basic data vector
if (dataBase) {
size_t base_offset = buffer->byteLength;
size_t base_padding = base_offset % bytesPerComp;
base_offset += base_padding;
size_t base_length = count * numCompsOut * bytesPerComp;
buffer->Grow(base_length + base_padding);
Ref<BufferView> bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));
bv->buffer = buffer;
bv->byteOffset = base_offset;
bv->byteLength = base_length; //! The target that the WebGL buffer should be bound to.
bv->byteStride = 0;
bv->target = target;
acc->bufferView = bv;
acc->WriteData(count, dataBase, numCompsIn * bytesPerComp);
}
acc->byteOffset = 0;
acc->componentType = compType;
acc->count = count;
acc->type = typeOut;
if (data) {
void *nzDiff = 0, *nzIdx = 0;
size_t nzCount = NZDiff(compType, data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
acc->sparse.reset(new Accessor::Sparse);
acc->sparse->count = nzCount;
//indices
unsigned int bytesPerIdx = sizeof(unsigned short);
size_t indices_offset = buffer->byteLength;
size_t indices_padding = indices_offset % bytesPerIdx;
indices_offset += indices_padding;
size_t indices_length = nzCount * 1 * bytesPerIdx;
buffer->Grow(indices_length + indices_padding);
Ref<BufferView> indicesBV = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));
indicesBV->buffer = buffer;
indicesBV->byteOffset = indices_offset;
indicesBV->byteLength = indices_length;
indicesBV->byteStride = 0;
acc->sparse->indices = indicesBV;
acc->sparse->indicesType = ComponentType_UNSIGNED_SHORT;
acc->sparse->indicesByteOffset = 0;
acc->WriteSparseIndices(nzCount, nzIdx, 1 * bytesPerIdx);
//values
size_t values_offset = buffer->byteLength;
size_t values_padding = values_offset % bytesPerComp;
values_offset += values_padding;
size_t values_length = nzCount * numCompsOut * bytesPerComp;
buffer->Grow(values_length + values_padding);
Ref<BufferView> valuesBV = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));
valuesBV->buffer = buffer;
valuesBV->byteOffset = values_offset;
valuesBV->byteLength = values_length;
valuesBV->byteStride = 0;
acc->sparse->values = valuesBV;
acc->sparse->valuesByteOffset = 0;
acc->WriteSparseValues(nzCount, nzDiff, numCompsIn * bytesPerComp);
//clear
delete[] (char*)nzDiff;
delete[] (char*)nzIdx;
}
return acc;
}
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer, inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
size_t count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, BufferViewTarget target = BufferViewTarget_NONE) size_t count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, BufferViewTarget target = BufferViewTarget_NONE)
{ {
@ -824,6 +983,10 @@ void glTF2Exporter::ExportMeshes()
/*************** Targets for blendshapes ****************/ /*************** Targets for blendshapes ****************/
if (aim->mNumAnimMeshes > 0) { if (aim->mNumAnimMeshes > 0) {
bool bUseSparse = this->mProperties->HasPropertyBool("GLTF2_SPARSE_ACCESSOR_EXP") &&
this->mProperties->GetPropertyBool("GLTF2_SPARSE_ACCESSOR_EXP");
bool bIncludeNormal = this->mProperties->HasPropertyBool("GLTF2_TARGET_NORMAL_EXP") &&
this->mProperties->GetPropertyBool("GLTF2_TARGET_NORMAL_EXP");
bool bExportTargetNames = this->mProperties->HasPropertyBool("GLTF2_TARGETNAMES_EXP") && bool bExportTargetNames = this->mProperties->HasPropertyBool("GLTF2_TARGETNAMES_EXP") &&
this->mProperties->GetPropertyBool("GLTF2_TARGETNAMES_EXP"); this->mProperties->GetPropertyBool("GLTF2_TARGETNAMES_EXP");
@ -832,7 +995,6 @@ void glTF2Exporter::ExportMeshes()
aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am]; aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am];
if (bExportTargetNames) if (bExportTargetNames)
m->targetNames.push_back(pAnimMesh->mName.data); m->targetNames.push_back(pAnimMesh->mName.data);
// position // position
if (pAnimMesh->HasPositions()) { if (pAnimMesh->HasPositions()) {
// NOTE: in gltf it is the diff stored // NOTE: in gltf it is the diff stored
@ -840,9 +1002,16 @@ void glTF2Exporter::ExportMeshes()
for (unsigned int vt = 0; vt < pAnimMesh->mNumVertices; ++vt) { for (unsigned int vt = 0; vt < pAnimMesh->mNumVertices; ++vt) {
pPositionDiff[vt] = pAnimMesh->mVertices[vt] - aim->mVertices[vt]; pPositionDiff[vt] = pAnimMesh->mVertices[vt] - aim->mVertices[vt];
} }
Ref<Accessor> vec = ExportData(*mAsset, meshId, b, Ref<Accessor> vec;
pAnimMesh->mNumVertices, pPositionDiff, if (bUseSparse) {
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); vec = ExportDataSparse(*mAsset, meshId, b,
pAnimMesh->mNumVertices, pPositionDiff,
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
} else {
vec = ExportData(*mAsset, meshId, b,
pAnimMesh->mNumVertices, pPositionDiff,
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
}
if (vec) { if (vec) {
p.targets[am].position.push_back(vec); p.targets[am].position.push_back(vec);
} }
@ -850,14 +1019,21 @@ void glTF2Exporter::ExportMeshes()
} }
// normal // normal
if (pAnimMesh->HasNormals()) { if (pAnimMesh->HasNormals() && bIncludeNormal) {
aiVector3D *pNormalDiff = new aiVector3D[pAnimMesh->mNumVertices]; aiVector3D *pNormalDiff = new aiVector3D[pAnimMesh->mNumVertices];
for (unsigned int vt = 0; vt < pAnimMesh->mNumVertices; ++vt) { for (unsigned int vt = 0; vt < pAnimMesh->mNumVertices; ++vt) {
pNormalDiff[vt] = pAnimMesh->mNormals[vt] - aim->mNormals[vt]; pNormalDiff[vt] = pAnimMesh->mNormals[vt] - aim->mNormals[vt];
} }
Ref<Accessor> vec = ExportData(*mAsset, meshId, b, Ref<Accessor> vec;
pAnimMesh->mNumVertices, pNormalDiff, if (bUseSparse) {
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); vec = ExportDataSparse(*mAsset, meshId, b,
pAnimMesh->mNumVertices, pNormalDiff,
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
} else {
vec = ExportData(*mAsset, meshId, b,
pAnimMesh->mNumVertices, pNormalDiff,
AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
}
if (vec) { if (vec) {
p.targets[am].normal.push_back(vec); p.targets[am].normal.push_back(vec);
} }

View File

@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_GLTF2EXPORTER_H_INC #ifndef AI_GLTF2EXPORTER_H_INC
#define AI_GLTF2EXPORTER_H_INC #define AI_GLTF2EXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/material.h> #include <assimp/material.h>

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
#include "AssetLib/glTF2/glTF2Importer.h" #include "AssetLib/glTF2/glTF2Importer.h"
#include "PostProcessing/MakeVerboseFormat.h" #include "PostProcessing/MakeVerboseFormat.h"
@ -298,25 +298,37 @@ void glTF2Importer::ImportMaterials(glTF2::Asset &r) {
} }
} }
static inline void SetFace(aiFace &face, int a) { static inline void SetFaceAndAdvance1(aiFace*& face, unsigned int numVertices, unsigned int a) {
face.mNumIndices = 1; if (a >= numVertices) {
face.mIndices = new unsigned int[1]; return;
face.mIndices[0] = a; }
face->mNumIndices = 1;
face->mIndices = new unsigned int[1];
face->mIndices[0] = a;
++face;
} }
static inline void SetFace(aiFace &face, int a, int b) { static inline void SetFaceAndAdvance2(aiFace*& face, unsigned int numVertices, unsigned int a, unsigned int b) {
face.mNumIndices = 2; if ((a >= numVertices) || (b >= numVertices)) {
face.mIndices = new unsigned int[2]; return;
face.mIndices[0] = a; }
face.mIndices[1] = b; face->mNumIndices = 2;
face->mIndices = new unsigned int[2];
face->mIndices[0] = a;
face->mIndices[1] = b;
++face;
} }
static inline void SetFace(aiFace &face, int a, int b, int c) { static inline void SetFaceAndAdvance3(aiFace*& face, unsigned int numVertices, unsigned int a, unsigned int b, unsigned int c) {
face.mNumIndices = 3; if ((a >= numVertices) || (b >= numVertices) || (c >= numVertices)) {
face.mIndices = new unsigned int[3]; return;
face.mIndices[0] = a; }
face.mIndices[1] = b; face->mNumIndices = 3;
face.mIndices[2] = c; face->mIndices = new unsigned int[3];
face->mIndices[0] = a;
face->mIndices[1] = b;
face->mIndices[2] = c;
++face;
} }
#ifdef ASSIMP_BUILD_DEBUG #ifdef ASSIMP_BUILD_DEBUG
@ -335,7 +347,7 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
void glTF2Importer::ImportMeshes(glTF2::Asset &r) { void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_DEBUG_F("Importing ", r.meshes.Size(), " meshes"); ASSIMP_LOG_DEBUG_F("Importing ", r.meshes.Size(), " meshes");
std::vector<aiMesh *> meshes; std::vector<std::unique_ptr<aiMesh>> meshes;
unsigned int k = 0; unsigned int k = 0;
meshOffsets.clear(); meshOffsets.clear();
@ -350,7 +362,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
Mesh::Primitive &prim = mesh.primitives[p]; Mesh::Primitive &prim = mesh.primitives[p];
aiMesh *aim = new aiMesh(); aiMesh *aim = new aiMesh();
meshes.push_back(aim); meshes.push_back(std::unique_ptr<aiMesh>(aim));
aim->mName = mesh.name.empty() ? mesh.id : mesh.name; aim->mName = mesh.name.empty() ? mesh.id : mesh.name;
@ -486,6 +498,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
} }
aiFace *faces = nullptr; aiFace *faces = nullptr;
aiFace *facePtr = nullptr;
size_t nFaces = 0; size_t nFaces = 0;
if (prim.indices) { if (prim.indices) {
@ -497,9 +510,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
switch (prim.mode) { switch (prim.mode) {
case PrimitiveMode_POINTS: { case PrimitiveMode_POINTS: {
nFaces = count; nFaces = count;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; ++i) { for (unsigned int i = 0; i < count; ++i) {
SetFace(faces[i], data.GetUInt(i)); SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i));
} }
break; break;
} }
@ -510,9 +523,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
count = nFaces * 2; count = nFaces * 2;
} }
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; i += 2) { for (unsigned int i = 0; i < count; i += 2) {
SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1));
} }
break; break;
} }
@ -520,13 +533,13 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
case PrimitiveMode_LINE_LOOP: case PrimitiveMode_LINE_LOOP:
case PrimitiveMode_LINE_STRIP: { case PrimitiveMode_LINE_STRIP: {
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1)); SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1));
for (unsigned int i = 2; i < count; ++i) { for (unsigned int i = 2; i < count; ++i) {
SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i)); SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i));
} }
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast<int>(count) - 1), faces[0].mIndices[0]);
} }
break; break;
} }
@ -537,33 +550,33 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
count = nFaces * 3; count = nFaces * 3;
} }
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; i += 3) { for (unsigned int i = 0; i < count; i += 3) {
SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
} }
break; break;
} }
case PrimitiveMode_TRIANGLE_STRIP: { case PrimitiveMode_TRIANGLE_STRIP: {
nFaces = count - 2; nFaces = count - 2;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < nFaces; ++i) { for (unsigned int i = 0; i < nFaces; ++i) {
//The ordering is to ensure that the triangles are all drawn with the same orientation //The ordering is to ensure that the triangles are all drawn with the same orientation
if ((i + 1) % 2 == 0) { if ((i + 1) % 2 == 0) {
//For even n, vertices n + 1, n, and n + 2 define triangle n //For even n, vertices n + 1, n, and n + 2 define triangle n
SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2)); SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
} else { } else {
//For odd n, vertices n, n+1, and n+2 define triangle n //For odd n, vertices n, n+1, and n+2 define triangle n
SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
} }
} }
break; break;
} }
case PrimitiveMode_TRIANGLE_FAN: case PrimitiveMode_TRIANGLE_FAN:
nFaces = count - 2; nFaces = count - 2;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
for (unsigned int i = 1; i < nFaces; ++i) { for (unsigned int i = 1; i < nFaces; ++i) {
SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2)); SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2));
} }
break; break;
} }
@ -575,9 +588,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
switch (prim.mode) { switch (prim.mode) {
case PrimitiveMode_POINTS: { case PrimitiveMode_POINTS: {
nFaces = count; nFaces = count;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; ++i) { for (unsigned int i = 0; i < count; ++i) {
SetFace(faces[i], i); SetFaceAndAdvance1(facePtr, aim->mNumVertices, i);
} }
break; break;
} }
@ -588,9 +601,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
count = (unsigned int)nFaces * 2; count = (unsigned int)nFaces * 2;
} }
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; i += 2) { for (unsigned int i = 0; i < count; i += 2) {
SetFace(faces[i / 2], i, i + 1); SetFaceAndAdvance2(facePtr, aim->mNumVertices, i, i + 1);
} }
break; break;
} }
@ -598,13 +611,13 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
case PrimitiveMode_LINE_LOOP: case PrimitiveMode_LINE_LOOP:
case PrimitiveMode_LINE_STRIP: { case PrimitiveMode_LINE_STRIP: {
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
SetFace(faces[0], 0, 1); SetFaceAndAdvance2(facePtr, aim->mNumVertices, 0, 1);
for (unsigned int i = 2; i < count; ++i) { for (unsigned int i = 2; i < count; ++i) {
SetFace(faces[i - 1], faces[i - 2].mIndices[1], i); SetFaceAndAdvance2(facePtr, aim->mNumVertices, i - 1, i);
} }
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); SetFaceAndAdvance2(facePtr, aim->mNumVertices, count - 1, 0);
} }
break; break;
} }
@ -615,42 +628,50 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
count = (unsigned int)nFaces * 3; count = (unsigned int)nFaces * 3;
} }
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < count; i += 3) { for (unsigned int i = 0; i < count; i += 3) {
SetFace(faces[i / 3], i, i + 1, i + 2); SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
} }
break; break;
} }
case PrimitiveMode_TRIANGLE_STRIP: { case PrimitiveMode_TRIANGLE_STRIP: {
nFaces = count - 2; nFaces = count - 2;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
for (unsigned int i = 0; i < nFaces; ++i) { for (unsigned int i = 0; i < nFaces; ++i) {
//The ordering is to ensure that the triangles are all drawn with the same orientation //The ordering is to ensure that the triangles are all drawn with the same orientation
if ((i + 1) % 2 == 0) { if ((i + 1) % 2 == 0) {
//For even n, vertices n + 1, n, and n + 2 define triangle n //For even n, vertices n + 1, n, and n + 2 define triangle n
SetFace(faces[i], i + 1, i, i + 2); SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2);
} else { } else {
//For odd n, vertices n, n+1, and n+2 define triangle n //For odd n, vertices n, n+1, and n+2 define triangle n
SetFace(faces[i], i, i + 1, i + 2); SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
} }
} }
break; break;
} }
case PrimitiveMode_TRIANGLE_FAN: case PrimitiveMode_TRIANGLE_FAN:
nFaces = count - 2; nFaces = count - 2;
faces = new aiFace[nFaces]; facePtr = faces = new aiFace[nFaces];
SetFace(faces[0], 0, 1, 2); SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, 1, 2);
for (unsigned int i = 1; i < nFaces; ++i) { for (unsigned int i = 1; i < nFaces; ++i) {
SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2); SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, i + 1, i + 2);
} }
break; break;
} }
} }
if (nullptr != faces) { if (faces) {
aim->mFaces = faces; aim->mFaces = faces;
aim->mNumFaces = static_cast<unsigned int>(nFaces); const unsigned int actualNumFaces = static_cast<unsigned int>(facePtr - faces);
ai_assert(CheckValidFacesIndices(faces, static_cast<unsigned>(nFaces), aim->mNumVertices)); if (actualNumFaces < nFaces) {
ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped.");
}
if (actualNumFaces == 0)
{
throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces");
}
aim->mNumFaces = actualNumFaces;
ai_assert(CheckValidFacesIndices(faces, actualNumFaces, aim->mNumVertices));
} }
if (prim.material) { if (prim.material) {

View File

@ -200,6 +200,7 @@ SET( Common_SRCS
Common/simd.cpp Common/simd.cpp
Common/material.cpp Common/material.cpp
Common/AssertHandler.cpp Common/AssertHandler.cpp
Common/Exceptional.cpp
) )
SOURCE_GROUP(Common FILES ${Common_SRCS}) SOURCE_GROUP(Common FILES ${Common_SRCS})
@ -884,7 +885,7 @@ ENDIF()
# utf8 # utf8
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(utf8) hunter_add_package(utf8)
find_package(utf8 CONFIG REQUIRED) find_package(utf8cpp CONFIG REQUIRED)
ELSE() ELSE()
# utf8 is header-only, so Assimp doesn't need to do anything. # utf8 is header-only, so Assimp doesn't need to do anything.
ENDIF() ENDIF()
@ -1039,6 +1040,8 @@ IF(ASSIMP_HUNTER_ENABLED)
ELSE() ELSE()
INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
INCLUDE_DIRECTORIES( "../contrib" ) INCLUDE_DIRECTORIES( "../contrib" )
ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1 )
ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
ENDIF() ENDIF()
# VC2010 fixes # VC2010 fixes
@ -1051,7 +1054,7 @@ endif()
ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT ) ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT )
if ( MSVC ) IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
endif () endif ()
@ -1121,6 +1124,8 @@ ENDIF ()
ADD_LIBRARY( assimp ${assimp_src} ) ADD_LIBRARY( assimp ${assimp_src} )
ADD_LIBRARY(assimp::assimp ALIAS assimp) ADD_LIBRARY(assimp::assimp ALIAS assimp)
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
# enable warnings as errors ######################################## # enable warnings as errors ########################################
IF (MSVC) IF (MSVC)
TARGET_COMPILE_OPTIONS(assimp PRIVATE /WX) TARGET_COMPILE_OPTIONS(assimp PRIVATE /WX)
@ -1144,7 +1149,7 @@ IF(ASSIMP_HUNTER_ENABLED)
minizip::minizip minizip::minizip
ZLIB::zlib ZLIB::zlib
RapidJSON::rapidjson RapidJSON::rapidjson
utf8::utf8 utf8cpp
zip::zip zip::zip
pugixml::pugixml pugixml::pugixml
) )

View File

@ -130,10 +130,11 @@ aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSyst
// passes scale into ScaleProcess // passes scale into ScaleProcess
UpdateImporterScale(pImp); UpdateImporterScale(pImp);
} catch (const std::exception &err) { } catch( const std::exception &err ) {
// extract error description // extract error description
m_ErrorText = err.what(); m_ErrorText = err.what();
ASSIMP_LOG_ERROR(m_ErrorText); ASSIMP_LOG_ERROR(err.what());
m_Exception = std::current_exception();
return nullptr; return nullptr;
} }
@ -343,7 +344,7 @@ std::string BaseImporter::GetExtension(const std::string &file) {
} }
#ifdef ASSIMP_USE_HUNTER #ifdef ASSIMP_USE_HUNTER
#include <utf8/utf8.h> #include <utf8.h>
#else #else
#include "../contrib/utf8cpp/source/utf8.h" #include "../contrib/utf8cpp/source/utf8.h"
#endif #endif

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -52,27 +50,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
namespace { namespace {
template <size_t sizeOfPointer> template <size_t sizeOfPointer>
size_t select_ftell(FILE *file) { inline size_t select_ftell(FILE *file) {
return ::ftell(file); return ::ftell(file);
} }
template <size_t sizeOfPointer> template <size_t sizeOfPointer>
int select_fseek(FILE *file, int64_t offset, int origin) { inline int select_fseek(FILE *file, int64_t offset, int origin) {
return ::fseek(file, static_cast<long>(offset), origin); return ::fseek(file, static_cast<long>(offset), origin);
} }
#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
template <> template <>
size_t select_ftell<8>(FILE *file) { inline size_t select_ftell<8>(FILE *file) {
return (size_t)::_ftelli64(file); return (size_t)::_ftelli64(file);
} }
template <> template <>
int select_fseek<8>(FILE *file, int64_t offset, int origin) { inline int select_fseek<8>(FILE *file, int64_t offset, int origin) {
return ::_fseeki64(file, offset, origin); return ::_fseeki64(file, offset, origin);
} }
#endif
#endif // #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
} // namespace } // namespace
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@ -100,7 +103,6 @@ size_t DefaultIOStream::Write(const void *pvBuffer,
size_t pCount) { size_t pCount) {
ai_assert(nullptr != pvBuffer); ai_assert(nullptr != pvBuffer);
ai_assert(0 != pSize); ai_assert(0 != pSize);
ai_assert(0 != pCount);
return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0); return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
} }

View File

@ -0,0 +1,52 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Exceptional.cpp
Implementations of the exception classes.
*/
#include <assimp/Exceptional.h>
#include <assimp/TinyFormatter.h>
DeadlyErrorBase::DeadlyErrorBase(Assimp::Formatter::format f) :
runtime_error(std::string(f)){}

Some files were not shown because too many files have changed in this diff Show More