diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a932e5377..e0c2bec9e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ patreon: assimp -Paypal: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4 +custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..dd84ea782 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..bbcbbe7d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 61e804b2e..f29e2e500 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -7,16 +7,117 @@ on: branches: [ master ] jobs: - build-ubuntu: + job: + name: ${{ matrix.name }}-build-and-test + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + 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. + include: + - name: windows-latest-cl.exe + os: windows-latest + cxx: cl.exe + cc: cl.exe + - name: ubuntu-latest-clang++ + os: ubuntu-latest + cxx: clang++ + cc: clang + - name: macos-latest-clang++ + os: macos-latest + cxx: clang++ + cc: clang + - name: ubuntu-latest-g++ + os: ubuntu-latest + cxx: g++ + 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 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: configure - run: cmake CMakeLists.txt - - name: build - run: cmake --build . + - uses: actions/checkout@v2 + + - uses: lukka/get-cmake@latest + + - uses: ilammy/msvc-dev-cmd@v1 + + - name: Set Compiler Environment + if: "!endsWith(matrix.name, 'hunter')" + uses: lukka/set-shell-env@v1 + with: + CXX: ${{ matrix.cxx }} + 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 + uses: lukka/run-cmake@v3 + env: + DXSDK_DIR: '${{ github.workspace }}/DX_SDK' + + with: + cmakeListsOrSettingsJson: CMakeListsTxtAdvanced + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}' + buildWithCMakeArgs: '-- -v' + 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 - run: cd bin && ./unit - + run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }} + shell: bash + + - uses: actions/upload-artifact@v2 + if: matrix.name == 'windows-msvc' + with: + name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}' + path: build/bin diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml new file mode 100644 index 000000000..e2cb1cf53 --- /dev/null +++ b/.github/workflows/sanitizer.yml @@ -0,0 +1,56 @@ +name: C/C++ Sanitizer + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + job1: + name: adress-sanitizer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: lukka/get-cmake@latest + - uses: lukka/set-shell-env@v1 + with: + CXX: clang++ + CC: clang + + - name: configure and build + uses: lukka/run-cmake@v3 + with: + cmakeListsOrSettingsJson: CMakeListsTxtAdvanced + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_ASAN=ON' + buildWithCMakeArgs: '-- -v' + buildDirectory: '${{ github.workspace }}/build/' + + - name: test + run: cd build/bin && ./unit + shell: bash + + job2: + name: undefined-behavior-sanitizer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: lukka/get-cmake@latest + - uses: lukka/set-shell-env@v1 + with: + CXX: clang++ + CC: clang + + - name: configure and build + uses: lukka/run-cmake@v2 + with: + cmakeListsOrSettingsJson: CMakeListsTxtAdvanced + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_UBSAN=ON' + buildWithCMakeArgs: '-- -v' + buildDirectory: '${{ github.workspace }}/build/' + + - name: test + run: cd build/bin && ./unit + shell: bash diff --git a/.gitignore b/.gitignore index e975976bf..fe59f9a70 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/ tools/assimp_view/assimp_viewer.vcxproj.user *.pyc +### Rust ### +# Generated by Cargo; will have compiled files and executables +port/assimp_rs/target/ +# Backup files generated by rustfmt +port/assimp_rs/**/*.rs.bk + # Unix editor backups *~ test/gtest/src/gtest-stamp/gtest-gitinfo.txt diff --git a/AssimpBuildTreeSettings.cmake.in b/AssimpBuildTreeSettings.cmake.in deleted file mode 100644 index 342da1b08..000000000 --- a/AssimpBuildTreeSettings.cmake.in +++ /dev/null @@ -1,3 +0,0 @@ -set(ASSIMP_INCLUDE_DIRS - "@PROJECT_SOURCE_DIR@" - "@PROJECT_BINARY_DIR@") diff --git a/AssimpConfigVersion.cmake.in b/AssimpConfigVersion.cmake.in deleted file mode 100644 index 701fa6158..000000000 --- a/AssimpConfigVersion.cmake.in +++ /dev/null @@ -1,11 +0,0 @@ -set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@") - -# Check whether the requested PACKAGE_FIND_VERSION is compatible -if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}") - set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}") - set(ASSIMP_PACKAGE_VERSION_EXACT TRUE) - endif() -endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index f01ea52ea..4b553ef9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,18 +34,20 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #---------------------------------------------------------------------- +SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) +SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW) CMAKE_MINIMUM_REQUIRED( VERSION 3.0 ) # Toggles the use of the hunter package manager -option(HUNTER_ENABLED "Enable Hunter package manager support" OFF) +option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) include("cmake/HunterGate.cmake") HunterGate( - URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz" - SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a" + URL "https://github.com/cpp-pm/hunter/archive/v0.23.269.tar.gz" + SHA1 "64024b7b95b4c86d50ae05b926814448c93a70a0" ) add_definitions(-DASSIMP_USE_HUNTER) @@ -60,7 +62,7 @@ OPTION( BUILD_SHARED_LIBS ON ) -OPTION( BUILD_FRAMEWORK +OPTION( ASSIMP_BUILD_FRAMEWORK "Build package as Mac OS X Framework bundle." OFF ) @@ -101,17 +103,13 @@ OPTION ( ASSIMP_COVERALLS OFF ) OPTION( ASSIMP_INSTALL - "DIsable this if you want to use assimp as a submodule." + "Disable this if you want to use assimp as a submodule." ON ) OPTION ( ASSIMP_ERROR_MAX "Enable all warnings." OFF ) -OPTION ( ASSIMP_WERROR - "Treat warnings as errors." - OFF -) OPTION ( ASSIMP_ASAN "Enable AddressSanitizer." OFF @@ -120,25 +118,27 @@ OPTION ( ASSIMP_UBSAN "Enable Undefined Behavior sanitizer." OFF ) -OPTION ( SYSTEM_IRRXML - "Use system installed Irrlicht/IrrXML library." - OFF -) -OPTION ( BUILD_DOCS +OPTION ( ASSIMP_BUILD_DOCS "Build documentation using Doxygen." OFF ) -OPTION( INJECT_DEBUG_POSTFIX +OPTION( ASSIMP_INJECT_DEBUG_POSTFIX "Inject debug postfix in .a/.so/.dll lib names" ON ) -OPTION ( IGNORE_GIT_HASH +OPTION ( ASSIMP_IGNORE_GIT_HASH "Don't call git to get the hash." OFF ) -IF (IOS AND NOT HUNTER_ENABLED) +IF ( WIN32 ) + OPTION ( ASSIMP_BUILD_ASSIMP_VIEW + "If the Assimp view tool is built. (requires DirectX)" + OFF ) +ENDIF() + +IF (IOS AND NOT ASSIMP_HUNTER_ENABLED) IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Release") ENDIF () @@ -161,7 +161,7 @@ IF(MSVC) ENDIF() ENDIF() -IF (BUILD_FRAMEWORK) +IF (ASSIMP_BUILD_FRAMEWORK) SET (BUILD_SHARED_LIBS ON) MESSAGE(STATUS "Framework bundle building enabled") ENDIF() @@ -181,12 +181,12 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER SET (ASSIMP_SOVERSION 5) SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) -if(NOT HUNTER_ENABLED) +if(NOT ASSIMP_HUNTER_ENABLED) # Enable C++11 support globally set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) endif() -IF(NOT IGNORE_GIT_HASH) +IF(NOT ASSIMP_IGNORE_GIT_HASH) # Get the current working branch EXECUTE_PROCESS( COMMAND git rev-parse --abbrev-ref HEAD @@ -211,7 +211,7 @@ IF(NOT GIT_COMMIT_HASH) ENDIF() IF(ASSIMP_DOUBLE_PRECISION) - ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) + ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) ENDIF() CONFIGURE_FILE( @@ -243,30 +243,40 @@ IF( UNIX ) INCLUDE(GNUInstallDirs) ENDIF() -# Grouped compiler settings +# Grouped compiler settings ######################################## IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) - IF(NOT HUNTER_ENABLED) - SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}") - SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") + IF(NOT ASSIMP_HUNTER_ENABLED) + SET(CMAKE_CXX_STANDARD 11) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ENDIF() # hide all not-exported symbols - SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") - SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") - SET(LIBSTDC++_LIBRARIES -lstdc++) + IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" ) + SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") + SET(LIBSTDC++_LIBRARIES -lstdc++) + ELSE() + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") + SET(LIBSTDC++_LIBRARIES -lstdc++) + ENDIF() ELSEIF(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 IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") -ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) - IF(NOT HUNTER_ENABLED) - SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") - SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") +ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + IF(NOT ASSIMP_HUNTER_ENABLED) + SET(CMAKE_CXX_STANDARD 11) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ENDIF() - SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" ) + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" ) SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") ELSEIF( CMAKE_COMPILER_IS_MINGW ) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) @@ -274,7 +284,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3) message(WARNING "MinGW is old, if you experience errors, update MinGW.") ENDIF() - IF(NOT HUNTER_ENABLED) + IF(NOT ASSIMP_HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() @@ -283,7 +293,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() -IF ( IOS AND NOT HUNTER_ENABLED) +IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED) IF (CMAKE_BUILD_TYPE STREQUAL "Debug") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") @@ -311,16 +321,6 @@ IF (ASSIMP_ERROR_MAX) ENDIF() ENDIF() -IF (ASSIMP_WERROR) - MESSAGE(STATUS "Treating warnings as errors") - IF (MSVC) - ADD_COMPILE_OPTIONS(/WX) - ELSE() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - ENDIF() -ENDIF() - IF (ASSIMP_ASAN) MESSAGE(STATUS "AddressSanitizer enabled") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") @@ -329,129 +329,124 @@ ENDIF() IF (ASSIMP_UBSAN) MESSAGE(STATUS "Undefined Behavior sanitizer enabled") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") - SET(CMAKE_C_FLAGS "${CMAKE_C_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,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() INCLUDE (FindPkgMacros) INCLUDE (PrecompiledHeader) -# If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR), -# write the library/executable files to the respective directories in the -# source tree. During an out-of-source build, however, do not litter this -# directory, since that is probably what the user wanted to avoid. -IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) - SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" ) - SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" ) - SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" ) -ELSE() - SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib") - SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") - SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") -ENDIF () +# Set Assimp project output directory variables. +SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") +SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") +SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib") -# Cache these to allow the user to override them manually. -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." ) +# Macro used to set the output directories of a target to the +# respective Assimp output directories. +MACRO(TARGET_USE_COMMON_OUTPUT_DIRECTORY target) + set_target_properties(${target} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${ASSIMP_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${ASSIMP_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${ASSIMP_ARCHIVE_OUTPUT_DIRECTORY} + ) +ENDMACRO() get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) -IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug")) +IF (ASSIMP_INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug")) SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") ELSE() SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") ENDIF() # Only generate this target if no higher-level project already has -IF (NOT TARGET uninstall) +IF (NOT TARGET uninstall AND ASSIMP_INSTALL) # add make uninstall capability CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ENDIF() -IF(HUNTER_ENABLED) +# 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() + +set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + +IF(ASSIMP_HUNTER_ENABLED) set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") - set(INCLUDE_INSTALL_DIR "include") - - set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") - - # Configuration + set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-hunter-config.cmake.in") + set(NAMESPACE "${PROJECT_NAME}::") + set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake") - set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") - set(NAMESPACE "${PROJECT_NAME}::") - - # Include module with fuction 'write_basic_package_version_file' - include(CMakePackageConfigHelpers) - - # Note: PROJECT_VERSION is used as a VERSION - write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion) - - # Use variables: - # * TARGETS_EXPORT_NAME - # * PROJECT_NAME - configure_package_config_file( - "cmake/assimp-hunter-config.cmake.in" - "${PROJECT_CONFIG}" - INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" - ) - - install( - FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" - DESTINATION "${CONFIG_INSTALL_DIR}" - ) - - install( - EXPORT "${TARGETS_EXPORT_NAME}" - NAMESPACE "${NAMESPACE}" - DESTINATION "${CONFIG_INSTALL_DIR}" - ) ELSE() - # cmake configuration files - if(${BUILD_SHARED_LIBS}) - set(BUILD_LIB_TYPE SHARED) - else() - set(BUILD_LIB_TYPE STATIC) - 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}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) - IF (is_multi_config) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE) - SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake") - ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE) - SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake") - ELSE() - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE) - SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake") - ENDIF() - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) - #we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...) - INSTALL(FILES - "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" - ${PACKAGE_TARGETS_FILE} - DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) + set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") + set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-plain-config.cmake.in") + string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE) + set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::") + set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets") + set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}ConfigVersion.cmake") + set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}Config.cmake") ENDIF() -IF( BUILD_DOCS ) +set(INCLUDE_INSTALL_DIR "include") + +# Include module with fuction 'write_basic_package_version_file' +include(CMakePackageConfigHelpers) + +# Note: PROJECT_VERSION is used as a VERSION +write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion) + +configure_package_config_file( + ${CMAKE_CONFIG_TEMPLATE_FILE} + "${PROJECT_CONFIG}" + INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" +) + +install( + FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" + DESTINATION "${CONFIG_INSTALL_DIR}" + COMPONENT ${LIBASSIMP-DEV_COMPONENT} +) + +install( + EXPORT "${TARGETS_EXPORT_NAME}" + NAMESPACE "${NAMESPACE}" + DESTINATION "${CONFIG_INSTALL_DIR}" + COMPONENT ${LIBASSIMP-DEV_COMPONENT} +) + +IF( ASSIMP_BUILD_DOCS ) ADD_SUBDIRECTORY(doc) ENDIF() -# Look for system installed irrXML -IF ( SYSTEM_IRRXML ) - FIND_PACKAGE( IrrXML REQUIRED ) -ENDIF() - # Search for external dependencies, and build them from source if not found # Search for zlib -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(ZLIB) find_package(ZLIB CONFIG REQUIRED) @@ -512,19 +507,19 @@ ENDIF() SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING "describe the current architecture." ) -IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") -ELSE () +IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") +ELSE() ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' ) -ENDIF () +ENDIF() # ${CMAKE_GENERATOR} SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING "describe the current compiler." ) -IF ( ASSIMP_BUILD_COMPILER STREQUAL "") -ELSE () +IF( ASSIMP_BUILD_COMPILER STREQUAL "") +ELSE() ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' ) -ENDIF () +ENDIF() MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) @@ -575,10 +570,6 @@ ELSE () ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ENDIF () -IF(NOT HUNTER_ENABLED) - ADD_SUBDIRECTORY(contrib) -ENDIF() - ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) # The viewer for windows only @@ -673,7 +664,8 @@ if(WIN32) ENDIF() 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() IF(MSVC12) SET(ASSIMP_MSVC_VERSION "vc120") diff --git a/INSTALL b/INSTALL index 350a5f109..ecec2585b 100644 --- a/INSTALL +++ b/INSTALL @@ -1,50 +1,50 @@ - -======================================================================== -Open Asset Import Library (assimp) INSTALL -======================================================================== - ------------------------------- -Getting the documentation ------------------------------- - -A regularly-updated copy is available at -http://assimp.sourceforge.net/lib_html/index.html - -A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm. -To build the doxygen documentation on your own, follow these steps: - -a) download & install latest doxygen -b) make sure doxygen is in the executable search path -c) navigate to ./doc -d) and run 'doxygen' - -Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice. -Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop' -and configure the path to it in the DOXYFILE first. - ------------------------------- -Building Assimp ------------------------------- - -More detailed build instructions can be found in the documentation, -this section is just for the inpatient among you. - -CMake is the preferred build system for Assimp. The minimum required version -is 2.6. If you don't have it yet, downloads for CMake can be found on -http://www.cmake.org/. - -For Unix: - -1. mkdir build && cd build -2. cmake .. -G 'Unix Makefiles' -3. make -j4 - -For Windows: -1. Open a command prompt -2. mkdir build -3. cd build -4. cmake .. -5. cmake --build . - -For iOS: -Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS + +======================================================================== +Open Asset Import Library (assimp) INSTALL +======================================================================== + +------------------------------ +Getting the documentation +------------------------------ + +A regularly-updated copy is available at +http://assimp.sourceforge.net/lib_html/index.html + +A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm. +To build the doxygen documentation on your own, follow these steps: + +a) download & install latest doxygen +b) make sure doxygen is in the executable search path +c) navigate to ./doc +d) and run 'doxygen' + +Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice. +Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop' +and configure the path to it in the DOXYFILE first. + +------------------------------ +Building Assimp +------------------------------ + +More detailed build instructions can be found in the documentation, +this section is just for the inpatient among you. + +CMake is the preferred build system for Assimp. The minimum required version +is 2.6. If you don't have it yet, downloads for CMake can be found on +http://www.cmake.org/. + +For Unix: + +1. mkdir build && cd build +2. cmake .. -G 'Unix Makefiles' +3. make -j4 + +For Windows: +1. Open a command prompt +2. mkdir build +3. cd build +4. cmake .. +5. cmake --build . + +For iOS: +Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS diff --git a/Readme.md b/Readme.md index 61fff538f..c6212bcc0 100644 --- a/Readme.md +++ b/Readme.md @@ -2,9 +2,8 @@ Open Asset Import Library (assimp) ================================== A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data. ### Current project status ### +[![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) -[![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) Coverity Scan Build Status @@ -17,114 +16,22 @@ A library to import and export various 3d-model-formats including scene-post-pro
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. - -[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/). - Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. +### Latest Doc's ### +Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). + +### Get involved ### This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). - -Monthly donations via Patreon: -
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp) -
- -One-off donations via PayPal: -
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4) - +You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
- Please check our Wiki as well: https://github.com/assimp/assimp/wiki If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb #### Supported file formats #### - -__Importers__: - -- 3D -- [3DS](https://en.wikipedia.org/wiki/.3ds) -- [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format) -- AC -- [AC3D](https://en.wikipedia.org/wiki/AC3D) -- ACC -- AMJ -- ASE -- ASK -- B3D -- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format)) -- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy) -- CMS -- COB -- [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA) -- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF) -- ENFF -- [FBX](https://en.wikipedia.org/wiki/FBX) -- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB -- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0): - At the moment for glTF2.0 the following extensions are supported: - + KHR_lights_punctual ( 5.0 ) - + KHR_materials_pbrSpecularGlossiness ( 5.0 ) - + KHR_materials_unlit ( 5.0 ) - + KHR_texture_transform ( 5.1 under test ) -- HMB -- IFC-STEP -- IRR / IRRMESH -- [LWO](https://en.wikipedia.org/wiki/LightWave_3D) -- LWS -- LXO -- [M3D](https://bztsrc.gitlab.io/model3d) -- MD2 -- MD3 -- MD5 -- MDC -- MDL -- MESH / MESH.XML -- MOT -- MS3D -- NDO -- NFF -- [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) -- [OFF](https://en.wikipedia.org/wiki/OFF_(file_format)) -- [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange) -- [PLY](https://en.wikipedia.org/wiki/PLY_(file_format)) -- PMX -- PRJ -- Q3O -- Q3S -- RAW -- SCN -- SIB -- SMD -- [STP](https://en.wikipedia.org/wiki/ISO_10303-21) -- [STL](https://en.wikipedia.org/wiki/STL_(file_format)) -- TER -- UC -- VTA -- X -- [X3D](https://en.wikipedia.org/wiki/X3D) -- XGL -- ZGL - -Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): - -- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported - -__Exporters__: - -- DAE (Collada) -- STL -- OBJ -- PLY -- X -- 3DS -- JSON (for WebGl, via https://github.com/acgessler/assimp2json) -- ASSBIN -- STEP -- glTF 1.0 (partial) -- glTF 2.0 (partial) -- 3MF ( experimental ) -- FBX ( experimental ) +You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) ### Building ### Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do. @@ -166,7 +73,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. (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_ [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) @@ -179,6 +86,38 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a Contributions to assimp are highly appreciated. The easiest way to get involved is to submit a pull request with your changes against the main repository's `master` branch. +## Contributors + +### Code Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + +
+ +### Financial Contributors + +Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/assimp/contribute)] + +#### Individuals + + + +Monthly donations via Patreon: +
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp) + +
+ +One-off donations via PayPal: +
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4) + +
+ +#### Organizations + +Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/assimp/contribute)] + + + ### License ### Our license is based on the modified, __3-clause BSD__-License. diff --git a/assimp-config-version.cmake.in b/assimp-config-version.cmake.in deleted file mode 100644 index 68366820a..000000000 --- a/assimp-config-version.cmake.in +++ /dev/null @@ -1,48 +0,0 @@ -# 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. -#---------------------------------------------------------------------- -set( PACKAGE_VERSION "@ASSIMP_VERSION@" ) -if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@") - set(PACKAGE_VERSION_EXACT 1) -endif() -if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_VERSION@" ) - set(PACKAGE_VERSION_COMPATIBLE 1) -elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" ) - # for now backward compatible if minor version is less - if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ ) - set(PACKAGE_VERSION_COMPATIBLE 1) - endif() -endif() -set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@") diff --git a/assimp-config.cmake.in b/assimp-config.cmake.in deleted file mode 100644 index 0ab9fd071..000000000 --- a/assimp-config.cmake.in +++ /dev/null @@ -1 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/assimpTargets.cmake) diff --git a/assimp.pc.in b/assimp.pc.in index 02cf59dc4..555a3a1d3 100644 --- a/assimp.pc.in +++ b/assimp.pc.in @@ -1,7 +1,5 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@/ -libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@ -includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: @CMAKE_PROJECT_NAME@ Description: Import various well-known 3D model formats in an uniform manner. diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in deleted file mode 100644 index 4cb917fd8..000000000 --- a/assimpTargets-debug.cmake.in +++ /dev/null @@ -1,123 +0,0 @@ -#---------------------------------------------------------------- -# Generated CMake target import file for configuration "Debug". -#---------------------------------------------------------------- - -# Commands may need to know the format version. -set(CMAKE_IMPORT_FILE_VERSION 1) - -set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) - -if(MSVC) - if(MSVC_TOOLSET_VERSION) - set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") - else() - if( MSVC70 OR MSVC71 ) - set(MSVC_PREFIX "vc70") - elseif( MSVC80 ) - set(MSVC_PREFIX "vc80") - elseif( MSVC90 ) - set(MSVC_PREFIX "vc90") - elseif( MSVC10 ) - set(MSVC_PREFIX "vc100") - elseif( MSVC11 ) - set(MSVC_PREFIX "vc110") - elseif( MSVC12 ) - set(MSVC_PREFIX "vc120") - elseif( MSVC_VERSION LESS 1910) - set(MSVC_PREFIX "vc140") - elseif( MSVC_VERSION LESS 1920) - set(MSVC_PREFIX "vc141") - elseif( MSVC_VERSION LESS 1930) - set(MSVC_PREFIX "vc142") - else() - set(MSVC_PREFIX "vc150") - endif() - endif() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - - file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX) - - if(ASSIMP_BUILD_SHARED_LIBS) - set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") - set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@") - - # Import target "assimp::assimp" for configuration "Debug" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}" - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) - else() - set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") - - # Import target "assimp::assimp" for configuration "Debug" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") - endif() - -else() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) - if(ASSIMP_BUILD_SHARED_LIBS) - if(WIN32) - # Handle MinGW compiler. - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") - elseif(APPLE) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") - else() - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") - endif() - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_SONAME_DEBUG "${sharedLibraryName}" - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) - else() - set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) - endif() -endif() - - - - -# Commands beyond this point should not need to know the version. -set(CMAKE_IMPORT_FILE_VERSION) - -get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH) -set( ASSIMP_CXX_FLAGS ) # dynamically linked library -set( ASSIMP_LINK_FLAGS "" ) -set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") -set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") -if(ASSIMP_BUILD_SHARED_LIBS) - set( ASSIMP_LIBRARIES ${sharedLibraryName}) -else() - set( ASSIMP_LIBRARIES ${staticLibraryName}) -endif() - -# for compatibility with pkg-config -set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") -set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}") - -MARK_AS_ADVANCED( - ASSIMP_ROOT_DIR - ASSIMP_CXX_FLAGS - ASSIMP_LINK_FLAGS - ASSIMP_INCLUDE_DIRS - ASSIMP_LIBRARIES - ASSIMP_CFLAGS_OTHER - ASSIMP_LDFLAGS_OTHER - ASSIMP_LIBRARY_SUFFIX - ASSIMP_BUILD_SHARED_LIBS -) diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in deleted file mode 100644 index 702109305..000000000 --- a/assimpTargets-release.cmake.in +++ /dev/null @@ -1,122 +0,0 @@ -#---------------------------------------------------------------- -# Generated CMake target import file for configuration "Release". -#---------------------------------------------------------------- - -# Commands may need to know the format version. -set(CMAKE_IMPORT_FILE_VERSION 1) - -set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) - -if(MSVC) - if(MSVC_TOOLSET_VERSION) - set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") - else() - if( MSVC70 OR MSVC71 ) - set(MSVC_PREFIX "vc70") - elseif( MSVC80 ) - set(MSVC_PREFIX "vc80") - elseif( MSVC90 ) - set(MSVC_PREFIX "vc90") - elseif( MSVC10 ) - set(MSVC_PREFIX "vc100") - elseif( MSVC11 ) - set(MSVC_PREFIX "vc110") - elseif( MSVC12 ) - set(MSVC_PREFIX "vc120") - elseif( MSVC_VERSION LESS 1910) - set(MSVC_PREFIX "vc140") - elseif( MSVC_VERSION LESS 1920) - set(MSVC_PREFIX "vc141") - elseif( MSVC_VERSION LESS 1930) - set(MSVC_PREFIX "vc142") - else() - set(MSVC_PREFIX "vc150") - endif() - endif() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - - file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX) - - if(ASSIMP_BUILD_SHARED_LIBS) - set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@") - set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@") - - # Import target "assimp::assimp" for configuration "Release" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}" - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) - else() - set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@") - - # Import target "assimp::assimp" for configuration "Release" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") - endif() - -else() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) - if(ASSIMP_BUILD_SHARED_LIBS) - if(WIN32) - # Handle MinGW compiler. - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") - elseif(APPLE) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") - else() - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") - endif() - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_SONAME_RELEASE "${sharedLibraryName}" - - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) - else() - set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@") - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) - endif() -endif() - -# Commands beyond this point should not need to know the version. -set(CMAKE_IMPORT_FILE_VERSION) - -get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH) - -set( ASSIMP_CXX_FLAGS ) # dynamically linked library -set( ASSIMP_LINK_FLAGS "" ) -set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") -set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") -if(ASSIMP_BUILD_SHARED_LIBS) - set( ASSIMP_LIBRARIES ${sharedLibraryName}) -else() - set( ASSIMP_LIBRARIES ${staticLibraryName}) -endif() - -# for compatibility with pkg-config -set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") -set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}") - -MARK_AS_ADVANCED( - ASSIMP_ROOT_DIR - ASSIMP_CXX_FLAGS - ASSIMP_LINK_FLAGS - ASSIMP_INCLUDE_DIRS - ASSIMP_LIBRARIES - ASSIMP_CFLAGS_OTHER - ASSIMP_LDFLAGS_OTHER - ASSIMP_LIBRARY_SUFFIX - ASSIMP_BUILD_SHARED_LIBS -) diff --git a/assimpTargets.cmake.in b/assimpTargets.cmake.in deleted file mode 100644 index b1c618c3a..000000000 --- a/assimpTargets.cmake.in +++ /dev/null @@ -1,104 +0,0 @@ -# Generated by CMake - -if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) - message(FATAL_ERROR "CMake >= 2.6.0 required") -endif() -cmake_policy(PUSH) -cmake_policy(VERSION 2.6) -# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function -cmake_policy(SET CMP0012 NEW) - -#---------------------------------------------------------------- -# Generated CMake target import file. -#---------------------------------------------------------------- - -# Commands may need to know the format version. -set(CMAKE_IMPORT_FILE_VERSION 1) - -# Protect against multiple inclusion, which would fail when already imported targets are added once more. -set(_targetsDefined) -set(_targetsNotDefined) -set(_expectedTargets) -foreach(_expectedTarget assimp::assimp) - list(APPEND _expectedTargets ${_expectedTarget}) - if(NOT TARGET ${_expectedTarget}) - list(APPEND _targetsNotDefined ${_expectedTarget}) - endif() - if(TARGET ${_expectedTarget}) - list(APPEND _targetsDefined ${_expectedTarget}) - endif() -endforeach() -if("${_targetsDefined}" STREQUAL "${_expectedTargets}") - unset(_targetsDefined) - unset(_targetsNotDefined) - unset(_expectedTargets) - set(CMAKE_IMPORT_FILE_VERSION) - cmake_policy(POP) - return() -endif() -if(NOT "${_targetsDefined}" STREQUAL "") - message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") -endif() -unset(_targetsDefined) -unset(_targetsNotDefined) -unset(_expectedTargets) - - -# Compute the installation prefix relative to this file. -get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) -get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) -get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) -get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) -if(_IMPORT_PREFIX STREQUAL "/") - set(_IMPORT_PREFIX "") -endif() - -# Create imported target assimp::assimp -add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED) - -set_target_properties(assimp::assimp PROPERTIES - COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION" - INTERFACE_assimp_MAJOR_VERSION "1" - INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include" - #INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine" -) - -if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") -endif() - -# Load information for each installed configuration. -get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -file(GLOB CONFIG_FILES "${_DIR}/assimpTargets-*.cmake") -foreach(f ${CONFIG_FILES}) - include(${f}) -endforeach() - -# Cleanup temporary variables. -set(_IMPORT_PREFIX) - -# Loop over all imported files and verify that they actually exist -foreach(target ${_IMPORT_CHECK_TARGETS} ) - foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) - if(NOT EXISTS "${file}" ) - message(FATAL_ERROR "The imported target \"${target}\" references the file - \"${file}\" -but this file does not exist. Possible reasons include: -* The file was deleted, renamed, or moved to another location. -* An install or uninstall procedure did not complete successfully. -* The installation package was faulty and contained - \"${CMAKE_CURRENT_LIST_FILE}\" -but not all the files it references. -") - endif() - endforeach() - unset(_IMPORT_CHECK_FILES_FOR_${target}) -endforeach() -unset(_IMPORT_CHECK_TARGETS) - -# This file does not depend on other imported targets which have -# been exported from the same project but in a separate export set. - -# Commands beyond this point should not need to know the version. -set(CMAKE_IMPORT_FILE_VERSION) -cmake_policy(POP) diff --git a/cmake-modules/FindRT.cmake b/cmake-modules/FindRT.cmake index 17d5df81d..c397acabd 100644 --- a/cmake-modules/FindRT.cmake +++ b/cmake-modules/FindRT.cmake @@ -16,5 +16,5 @@ set(RT_LIBRARIES ${RT_LIBRARY}) # handle the QUIETLY and REQUIRED arguments and set # RT_FOUND to TRUE if all listed variables are TRUE include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY) +find_package_handle_standard_args(RT DEFAULT_MSG RT_LIBRARY) mark_as_advanced(RT_LIBRARY) diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake index 887557a58..6d9cc2401 100644 --- a/cmake/HunterGate.cmake +++ b/cmake/HunterGate.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2018, Ruslan Baratov +# Copyright (c) 2013-2019, Ruslan Baratov # All rights reserved. # # 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_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) if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) @@ -79,9 +79,9 @@ function(hunter_gate_status_debug) endif() endfunction() -function(hunter_gate_wiki wiki_page) - message("------------------------------ WIKI -------------------------------") - message(" ${HUNTER_WIKI}/${wiki_page}") +function(hunter_gate_error_page error_page) + message("------------------------------ ERROR ------------------------------") + message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") message("-------------------------------------------------------------------") message("") message(FATAL_ERROR "") @@ -94,14 +94,13 @@ function(hunter_gate_internal_error) endforeach() message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("") - hunter_gate_wiki("error.internal") + hunter_gate_error_page("error.internal") endfunction() function(hunter_gate_fatal_error) - cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") - string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) - if(have_no_wiki) - hunter_gate_internal_error("Expected wiki") + cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") + if("${hunter_ERROR_PAGE}" STREQUAL "") + hunter_gate_internal_error("Expected ERROR_PAGE") endif() message("") foreach(x ${hunter_UNPARSED_ARGUMENTS}) @@ -109,11 +108,11 @@ function(hunter_gate_fatal_error) endforeach() message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("") - hunter_gate_wiki("${hunter_WIKI}") + hunter_gate_error_page("${hunter_ERROR_PAGE}") endfunction() 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() function(hunter_gate_self root version sha1 result) @@ -195,7 +194,7 @@ function(hunter_gate_detect_root) hunter_gate_fatal_error( "Can't detect HUNTER_ROOT" - WIKI "error.detect.hunter.root" + ERROR_PAGE "error.detect.hunter.root" ) endfunction() @@ -214,7 +213,7 @@ function(hunter_gate_download dir) "Settings:" " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" - WIKI "error.run.install" + ERROR_PAGE "error.run.install" ) endif() string(COMPARE EQUAL "${dir}" "" is_bad) @@ -400,7 +399,7 @@ macro(HunterGate) hunter_gate_fatal_error( "Please set HunterGate *before* 'project' command. " "Detected project: ${PROJECT_NAME}" - WIKI "error.huntergate.before.project" + ERROR_PAGE "error.huntergate.before.project" ) endif() @@ -470,7 +469,7 @@ macro(HunterGate) "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" "(Use at your own risk!)" - WIKI "error.spaces.in.hunter.root" + ERROR_PAGE "error.spaces.in.hunter.root" ) endif() endif() diff --git a/cmake/assimp-hunter-config.cmake.in b/cmake/assimp-hunter-config.cmake.in index 34762ac54..b5283f4fb 100644 --- a/cmake/assimp-hunter-config.cmake.in +++ b/cmake/assimp-hunter-config.cmake.in @@ -2,13 +2,13 @@ find_package(RapidJSON CONFIG REQUIRED) find_package(ZLIB CONFIG REQUIRED) -find_package(utf8 CONFIG REQUIRED) -find_package(irrXML CONFIG REQUIRED) +find_package(utf8cpp CONFIG REQUIRED) find_package(minizip CONFIG REQUIRED) find_package(openddlparser CONFIG REQUIRED) find_package(poly2tri CONFIG REQUIRED) find_package(polyclipping CONFIG REQUIRED) find_package(zip CONFIG REQUIRED) +find_package(pugixml CONFIG REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") check_required_components("@PROJECT_NAME@") diff --git a/cmake/assimp-plain-config.cmake.in b/cmake/assimp-plain-config.cmake.in new file mode 100644 index 000000000..6551dcb68 --- /dev/null +++ b/cmake/assimp-plain-config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") + +set(ASSIMP_ROOT_DIR ${PACKAGE_PREFIX_DIR}) +set(ASSIMP_LIBRARIES assimp::assimp) +set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) +get_property(ASSIMP_INCLUDE_DIRS TARGET assimp::assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +set(ASSIMP_LIBRARY_DIRS "") diff --git a/code/3MF/D3MFImporter.cpp b/code/3MF/D3MFImporter.cpp deleted file mode 100644 index 2f30c4fc0..000000000 --- a/code/3MF/D3MFImporter.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* -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. - ----------------------------------------------------------------------- -*/ - -#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER - -#include "D3MFImporter.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "D3MFOpcPackage.h" -#include -#include "3MFXmlTags.h" -#include - -#include - -namespace Assimp { -namespace D3MF { - -class XmlSerializer { -public: - using MatArray = std::vector; - using MatId2MatArray = std::map>; - - XmlSerializer(XmlReader* xmlReader) - : mMeshes() - , mMatArray() - , mActiveMatGroup( 99999999 ) - , mMatId2MatArray() - , xmlReader(xmlReader){ - // empty - } - - ~XmlSerializer() { - // empty - } - - void ImportXml(aiScene* scene) { - if ( nullptr == scene ) { - return; - } - - scene->mRootNode = new aiNode(); - std::vector children; - - std::string nodeName; - while(ReadToEndElement(D3MF::XmlTag::model)) { - nodeName = xmlReader->getNodeName(); - if( nodeName == D3MF::XmlTag::object) { - children.push_back(ReadObject(scene)); - } else if( nodeName == D3MF::XmlTag::build) { - // - } else if ( nodeName == D3MF::XmlTag::basematerials ) { - ReadBaseMaterials(); - } else if ( nodeName == D3MF::XmlTag::meta ) { - ReadMetadata(); - } - } - - if ( scene->mRootNode->mName.length == 0 ) { - scene->mRootNode->mName.Set( "3MF" ); - } - - // import the metadata - if ( !mMetaData.empty() ) { - const size_t numMeta( mMetaData.size() ); - scene->mMetaData = aiMetadata::Alloc(static_cast( numMeta ) ); - for ( size_t i = 0; i < numMeta; ++i ) { - aiString val( mMetaData[ i ].value ); - scene->mMetaData->Set(static_cast( i ), mMetaData[ i ].name, val ); - } - } - - // import the meshes - scene->mNumMeshes = static_cast( mMeshes.size()); - scene->mMeshes = new aiMesh*[scene->mNumMeshes](); - std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes); - - // import the materials - scene->mNumMaterials = static_cast( mMatArray.size() ); - if ( 0 != scene->mNumMaterials ) { - scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ]; - std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials ); - } - - // create the scenegraph - scene->mRootNode->mNumChildren = static_cast(children.size()); - scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren](); - std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); - } - -private: - aiNode* ReadObject(aiScene* scene) { - std::unique_ptr node(new aiNode()); - - std::vector meshIds; - - const char *attrib( nullptr ); - std::string name, type; - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() ); - if ( nullptr != attrib ) { - name = attrib; - } - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() ); - if ( nullptr != attrib ) { - type = attrib; - } - - node->mParent = scene->mRootNode; - node->mName.Set(name); - - size_t meshIdx = mMeshes.size(); - - while(ReadToEndElement(D3MF::XmlTag::object)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) { - auto mesh = ReadMesh(); - - mesh->mName.Set(name); - mMeshes.push_back(mesh); - meshIds.push_back(static_cast(meshIdx)); - ++meshIdx; - } - } - - node->mNumMeshes = static_cast(meshIds.size()); - - node->mMeshes = new unsigned int[node->mNumMeshes]; - - std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); - - return node.release(); - } - - aiMesh *ReadMesh() { - aiMesh* mesh = new aiMesh(); - while(ReadToEndElement(D3MF::XmlTag::mesh)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) { - ImportVertices(mesh); - } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) { - ImportTriangles(mesh); - } - } - - return mesh; - } - - void ReadMetadata() { - const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() ); - xmlReader->read(); - const std::string value = xmlReader->getNodeData(); - - if ( name.empty() ) { - return; - } - - MetaEntry entry; - entry.name = name; - entry.value = value; - mMetaData.push_back( entry ); - } - - void ImportVertices(aiMesh* mesh) { - std::vector vertices; - while(ReadToEndElement(D3MF::XmlTag::vertices)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) { - vertices.push_back(ReadVertex()); - } - } - mesh->mNumVertices = static_cast(vertices.size()); - mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - - std::copy(vertices.begin(), vertices.end(), mesh->mVertices); - } - - aiVector3D ReadVertex() { - aiVector3D vertex; - - vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); - vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr); - vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr); - - return vertex; - } - - void ImportTriangles(aiMesh* mesh) { - std::vector faces; - - while(ReadToEndElement(D3MF::XmlTag::triangles)) { - const std::string nodeName( xmlReader->getNodeName() ); - if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) { - faces.push_back(ReadTriangle()); - const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) ); - if ( nullptr != pidToken ) { - int matIdx( std::atoi( pidToken ) ); - mesh->mMaterialIndex = matIdx; - } - } - } - - mesh->mNumFaces = static_cast(faces.size()); - mesh->mFaces = new aiFace[mesh->mNumFaces]; - mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - std::copy(faces.begin(), faces.end(), mesh->mFaces); - } - - aiFace ReadTriangle() { - aiFace face; - - face.mNumIndices = 3; - face.mIndices = new unsigned int[face.mNumIndices]; - face.mIndices[0] = static_cast(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str()))); - face.mIndices[1] = static_cast(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str()))); - face.mIndices[2] = static_cast(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str()))); - - return face; - } - - void ReadBaseMaterials() { - std::vector MatIdArray; - const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) ); - if ( nullptr != baseMaterialId ) { - unsigned int id = std::atoi( baseMaterialId ); - const size_t newMatIdx( mMatArray.size() ); - if ( id != mActiveMatGroup ) { - mActiveMatGroup = id; - MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) ); - if ( mMatId2MatArray.end() == it ) { - MatIdArray.clear(); - mMatId2MatArray[ id ] = MatIdArray; - } else { - MatIdArray = it->second; - } - } - MatIdArray.push_back( static_cast( newMatIdx ) ); - mMatId2MatArray[ mActiveMatGroup ] = MatIdArray; - } - - while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) { - mMatArray.push_back( readMaterialDef() ); - } - } - - bool parseColor( const char *color, aiColor4D &diffuse ) { - if ( nullptr == color ) { - return false; - } - - //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1) - const size_t len( strlen( color ) ); - if ( 9 != len && 7 != len) { - return false; - } - - const char *buf( color ); - if ( '#' != *buf ) { - return false; - } - ++buf; - char comp[ 3 ] = { 0,0,'\0' }; - - comp[ 0 ] = *buf; - ++buf; - comp[ 1 ] = *buf; - ++buf; - diffuse.r = static_cast( strtol( comp, NULL, 16 ) ) / ai_real(255.0); - - - comp[ 0 ] = *buf; - ++buf; - comp[ 1 ] = *buf; - ++buf; - diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0); - - comp[ 0 ] = *buf; - ++buf; - comp[ 1 ] = *buf; - ++buf; - diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0); - - if(7 == len) - return true; - comp[ 0 ] = *buf; - ++buf; - comp[ 1 ] = *buf; - ++buf; - diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0); - - return true; - } - - void assignDiffuseColor( aiMaterial *mat ) { - const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() ); - aiColor4D diffuse; - if ( parseColor( color, diffuse ) ) { - mat->AddProperty( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); - } - - } - aiMaterial *readMaterialDef() { - aiMaterial *mat( nullptr ); - const char *name( nullptr ); - const std::string nodeName( xmlReader->getNodeName() ); - if ( nodeName == D3MF::XmlTag::basematerials_base ) { - name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() ); - std::string stdMatName; - aiString matName; - std::string strId( to_string( mActiveMatGroup ) ); - stdMatName += "id"; - stdMatName += strId; - stdMatName += "_"; - if ( nullptr != name ) { - stdMatName += std::string( name ); - } else { - stdMatName += "basemat"; - } - matName.Set( stdMatName ); - - mat = new aiMaterial; - mat->AddProperty( &matName, AI_MATKEY_NAME ); - - assignDiffuseColor( mat ); - } - - return mat; - } - -private: - bool ReadToStartElement(const std::string& startTag) { - while(xmlReader->read()) { - const std::string &nodeName( xmlReader->getNodeName() ); - if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) { - return true; - } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) { - return false; - } - } - - return false; - } - - bool ReadToEndElement(const std::string& closeTag) { - while(xmlReader->read()) { - const std::string &nodeName( xmlReader->getNodeName() ); - if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) { - return true; - } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) { - return false; - } - } - ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag"); - - return false; - } - -private: - struct MetaEntry { - std::string name; - std::string value; - }; - std::vector mMetaData; - std::vector mMeshes; - MatArray mMatArray; - unsigned int mActiveMatGroup; - MatId2MatArray mMatId2MatArray; - XmlReader* xmlReader; -}; - -} //namespace D3MF - -static const aiImporterDesc desc = { - "3mf Importer", - "", - "", - "http://3mf.io/", - aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour, - 0, - 0, - 0, - 0, - "3mf" -}; - -D3MFImporter::D3MFImporter() -: BaseImporter() { - // empty -} - -D3MFImporter::~D3MFImporter() { - // empty -} - -bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { - const std::string extension( GetExtension( filename ) ); - if(extension == desc.mFileExtensions ) { - return true; - } else if ( !extension.length() || checkSig ) { - if ( nullptr == pIOHandler ) { - return false; - } - if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) { - return false; - } - D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); - return opcPackage.validate(); - } - - return false; -} - -void D3MFImporter::SetupProperties(const Importer * /*pImp*/) { - // empty -} - -const aiImporterDesc *D3MFImporter::GetInfo() const { - return &desc; -} - -void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) { - D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); - - std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); - std::unique_ptr xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); - - D3MF::XmlSerializer xmlSerializer(xmlReader.get()); - - xmlSerializer.ImportXml(pScene); -} - -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_3MF_IMPORTER diff --git a/code/AMF/AMFImporter.cpp b/code/AMF/AMFImporter.cpp deleted file mode 100644 index df4324d4d..000000000 --- a/code/AMF/AMFImporter.cpp +++ /dev/null @@ -1,705 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AMFImporter.cpp -/// \brief AMF-format files importer for Assimp: main algorithm implementation. -/// \date 2016 -/// \author smal.root@gmail.com - -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER - -// Header files, Assimp. -#include "AMFImporter.hpp" -#include "AMFImporter_Macro.hpp" - -#include -#include - -// Header files, stdlib. -#include - -namespace Assimp -{ - -/// \var aiImporterDesc AMFImporter::Description -/// Conastant which hold importer description -const aiImporterDesc AMFImporter::Description = { - "Additive manufacturing file format(AMF) Importer", - "smalcom", - "", - "See documentation in source code. Chapter: Limitations.", - aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, - 0, - 0, - 0, - 0, - "amf" -}; - -void AMFImporter::Clear() -{ - mNodeElement_Cur = nullptr; - mUnit.clear(); - mMaterial_Converted.clear(); - mTexture_Converted.clear(); - // Delete all elements - if(!mNodeElement_List.empty()) - { - for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; } - - mNodeElement_List.clear(); - } -} - -AMFImporter::~AMFImporter() -{ - if(mReader != nullptr) delete mReader; - // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. - Clear(); -} - -/*********************************************************************************************************************************************/ -/************************************************************ Functions: find set ************************************************************/ -/*********************************************************************************************************************************************/ - -bool AMFImporter::Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const -{ - for(CAMFImporter_NodeElement* ne: mNodeElement_List) - { - if((ne->ID == pID) && (ne->Type == pType)) - { - if(pNodeElement != nullptr) *pNodeElement = ne; - - return true; - } - }// for(CAMFImporter_NodeElement* ne: mNodeElement_List) - - return false; -} - -bool AMFImporter::Find_ConvertedNode(const std::string& pID, std::list& pNodeList, aiNode** pNode) const -{ -aiString node_name(pID.c_str()); - - for(aiNode* node: pNodeList) - { - if(node->mName == node_name) - { - if(pNode != nullptr) *pNode = node; - - return true; - } - }// for(aiNode* node: pNodeList) - - return false; -} - -bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const -{ - for(const SPP_Material& mat: mMaterial_Converted) - { - if(mat.ID == pID) - { - if(pConvertedMaterial != nullptr) *pConvertedMaterial = &mat; - - return true; - } - }// for(const SPP_Material& mat: mMaterial_Converted) - - return false; -} - -/*********************************************************************************************************************************************/ -/************************************************************ Functions: throw set ***********************************************************/ -/*********************************************************************************************************************************************/ - -void AMFImporter::Throw_CloseNotFound(const std::string& pNode) -{ - throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt."); -} - -void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName) -{ - throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\"."); -} - -void AMFImporter::Throw_IncorrectAttrValue(const std::string& pAttrName) -{ - throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value."); -} - -void AMFImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription) -{ - throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription); -} - -void AMFImporter::Throw_ID_NotFound(const std::string& pID) const -{ - throw DeadlyImportError("Not found node with name \"" + pID + "\"."); -} - -/*********************************************************************************************************************************************/ -/************************************************************* Functions: XML set ************************************************************/ -/*********************************************************************************************************************************************/ - -void AMFImporter::XML_CheckNode_MustHaveChildren() -{ - if(mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children."); -} - -void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) -{ - static const size_t Uns_Skip_Len = 3; - const char* Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" }; - - static bool skipped_before[Uns_Skip_Len] = { false, false, false }; - - std::string nn(mReader->getNodeName()); - bool found = false; - bool close_found = false; - size_t sk_idx; - - for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) - { - if(nn != Uns_Skip[sk_idx]) continue; - - found = true; - if(mReader->isEmptyElement()) - { - close_found = true; - - goto casu_cres; - } - - while(mReader->read()) - { - if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) - { - close_found = true; - - goto casu_cres; - } - } - }// for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) - -casu_cres: - - if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); - if(!close_found) Throw_CloseNotFound(nn); - - if(!skipped_before[sk_idx]) - { - skipped_before[sk_idx] = true; - ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, "."); - } -} - -bool AMFImporter::XML_SearchNode(const std::string& pNodeName) -{ - while(mReader->read()) - { - if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true; - } - - return false; -} - -bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) -{ - std::string val(mReader->getAttributeValue(pAttrIdx)); - - if((val == "false") || (val == "0")) - return false; - else if((val == "true") || (val == "1")) - return true; - else - throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\""); -} - -float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) -{ - std::string val; - float tvalf; - - ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val); - fast_atoreal_move(val.c_str(), tvalf, false); - - return tvalf; -} - -uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) -{ - return strtoul10(mReader->getAttributeValue(pAttrIdx)); -} - -float AMFImporter::XML_ReadNode_GetVal_AsFloat() -{ - std::string val; - float tvalf; - - if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt."); - if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt."); - - ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val); - fast_atoreal_move(val.c_str(), tvalf, false); - - return tvalf; -} - -uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32() -{ - if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt."); - if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt."); - - return strtoul10(mReader->getNodeData()); -} - -void AMFImporter::XML_ReadNode_GetVal_AsString(std::string& pValue) -{ - if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt."); - if(mReader->getNodeType() != irr::io::EXN_TEXT) - throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt."); - - pValue = mReader->getNodeData(); -} - -/*********************************************************************************************************************************************/ -/************************************************************ Functions: parse set ***********************************************************/ -/*********************************************************************************************************************************************/ - -void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode) -{ - mNodeElement_Cur->Child.push_back(pNode);// add new element to current element child list. - mNodeElement_Cur = pNode;// switch current element to new one. -} - -void AMFImporter::ParseHelper_Node_Exit() -{ - // check if we can walk up. - if(mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent; -} - -void AMFImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString) -{ - size_t instr_len; - - pOutString.clear(); - instr_len = strlen(pInStr); - if(!instr_len) return; - - pOutString.reserve(instr_len * 3 / 2); - // check and correct floats in format ".x". Must be "x.y". - if(pInStr[0] == '.') pOutString.push_back('0'); - - pOutString.push_back(pInStr[0]); - for(size_t ci = 1; ci < instr_len; ci++) - { - if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) - { - pOutString.push_back('0'); - pOutString.push_back('.'); - } - else - { - pOutString.push_back(pInStr[ci]); - } - } -} - -static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) -{ - return (isalnum(pChar) || (pChar == '+') || (pChar == '/')); -} - -void AMFImporter::ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector& pOutputData) const -{ - // With help from - // René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html - const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - uint8_t tidx = 0; - uint8_t arr4[4], arr3[3]; - - // check input data - if(pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four."); - // prepare output place - pOutputData.clear(); - pOutputData.reserve(pInputBase64.size() / 4 * 3); - - for(size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--) - { - if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) - { - arr4[tidx++] = pInputBase64[in_idx++]; - if(tidx == 4) - { - for(tidx = 0; tidx < 4; tidx++) arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]); - - arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); - arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2); - arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3]; - for(tidx = 0; tidx < 3; tidx++) pOutputData.push_back(arr3[tidx]); - - tidx = 0; - }// if(tidx == 4) - }// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) - else - { - in_idx++; - }// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else - } - - if(tidx) - { - for(uint8_t i = tidx; i < 4; i++) arr4[i] = 0; - for(uint8_t i = 0; i < 4; i++) arr4[i] = (uint8_t)(base64_chars.find(arr4[i])); - - arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); - arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2); - arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3]; - for(uint8_t i = 0; i < (tidx - 1); i++) pOutputData.push_back(arr3[i]); - } -} - -void AMFImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler) -{ - irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader. - std::unique_ptr file(pIOHandler->Open(pFile, "rb")); - - // Check whether we can read from the file - if(file.get() == NULL) throw DeadlyImportError("Failed to open AMF file " + pFile + "."); - - // generate a XML reader for it - std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); - mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); - if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); - // - // start reading - // search for root tag - if(XML_SearchNode("amf")) - ParseNode_Root(); - else - throw DeadlyImportError("Root node \"amf\" not found."); - - delete mReader; - // restore old XMLreader - mReader = OldReader; -} - -// -// -// Root XML element. -// Multi elements - No. -void AMFImporter::ParseNode_Root() -{ - std::string unit, version; - CAMFImporter_NodeElement *ne( nullptr ); - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND_WSKIP; - - // Check attributes - if(!mUnit.empty()) - { - if((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit"); - } - - // create root node element. - ne = new CAMFImporter_NodeElement_Root(nullptr); - mNodeElement_Cur = ne;// set first "current" element - // and assign attribute's values - ((CAMFImporter_NodeElement_Root*)ne)->Unit = unit; - ((CAMFImporter_NodeElement_Root*)ne)->Version = version; - - // Check for child nodes - if(!mReader->isEmptyElement()) - { - MACRO_NODECHECK_LOOPBEGIN("amf"); - if(XML_CheckNode_NameEqual("object")) { ParseNode_Object(); continue; } - if(XML_CheckNode_NameEqual("material")) { ParseNode_Material(); continue; } - if(XML_CheckNode_NameEqual("texture")) { ParseNode_Texture(); continue; } - if(XML_CheckNode_NameEqual("constellation")) { ParseNode_Constellation(); continue; } - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("amf"); - mNodeElement_Cur = ne;// force restore "current" element - }// if(!mReader->isEmptyElement()) - - mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph. -} - -// -// -// A collection of objects or constellations with specific relative locations. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Constellation() -{ - std::string id; - CAMFImporter_NodeElement* ne( nullptr ); - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // create and if needed - define new grouping object. - ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur); - - CAMFImporter_NodeElement_Constellation& als = *((CAMFImporter_NodeElement_Constellation*)ne);// alias for convenience - - if(!id.empty()) als.ID = id; - // Check for child nodes - if(!mReader->isEmptyElement()) - { - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("constellation"); - if(XML_CheckNode_NameEqual("instance")) { ParseNode_Instance(); continue; } - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("constellation"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// A collection of objects or constellations with specific relative locations. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Instance() -{ - std::string objectid; - CAMFImporter_NodeElement* ne( nullptr ); - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // used object id must be defined, check that. - if(objectid.empty()) throw DeadlyImportError("\"objectid\" in must be defined."); - // create and define new grouping object. - ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur); - - CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);// alias for convenience - - als.ObjectID = objectid; - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool read_flag[6] = { false, false, false, false, false, false }; - - als.Delta.Set(0, 0, 0); - als.Rotation.Set(0, 0, 0); - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("instance"); - MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x); - MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y); - MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z); - MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x); - MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y); - MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z); - MACRO_NODECHECK_LOOPEND("instance"); - ParseHelper_Node_Exit(); - // also convert degrees to radians. - als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f; - als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f; - als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f; - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// An object definition. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Object() -{ - std::string id; - CAMFImporter_NodeElement* ne( nullptr ); - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // create and if needed - define new geometry object. - ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur); - - CAMFImporter_NodeElement_Object& als = *((CAMFImporter_NodeElement_Object*)ne);// alias for convenience - - if(!id.empty()) als.ID = id; - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool col_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("object"); - if(XML_CheckNode_NameEqual("color")) - { - // Check if color already defined for object. - if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("mesh")) { ParseNode_Mesh(); continue; } - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("object"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// Specify additional information about an entity. -// Multi elements - Yes. -// Parent element - , , , , . -// -// Reserved types are: -// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user. -// "Description" - A description of the content of the entity -// "URL" - A link to an external resource relating to the entity -// "Author" - Specifies the name(s) of the author(s) of the entity -// "Company" - Specifying the company generating the entity -// "CAD" - specifies the name of the originating CAD software and version -// "Revision" - specifies the revision of the entity -// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system -// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only) -void AMFImporter::ParseNode_Metadata() -{ - std::string type, value; - CAMFImporter_NodeElement* ne( nullptr ); - - // read attribute - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - // and value of node. - value = mReader->getNodeData(); - // Create node element and assign read data. - ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur); - ((CAMFImporter_NodeElement_Metadata*)ne)->Type = type; - ((CAMFImporter_NodeElement_Metadata*)ne)->Value = value; - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -/*********************************************************************************************************************************************/ -/******************************************************** Functions: BaseImporter set ********************************************************/ -/*********************************************************************************************************************************************/ - -bool AMFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const -{ - const std::string extension = GetExtension(pFile); - - if ( extension == "amf" ) { - return true; - } - - if(!extension.length() || pCheckSig) - { - const char* tokens[] = { "& pExtensionList) -{ - pExtensionList.insert("amf"); -} - -const aiImporterDesc* AMFImporter::GetInfo () const -{ - return &Description; -} - -void AMFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) -{ - Clear();// delete old graph. - ParseFile(pFile, pIOHandler); - Postprocess_BuildScene(pScene); - // scene graph is ready, exit. -} - -}// namespace Assimp - -#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/AMF/AMFImporter.hpp b/code/AMF/AMFImporter.hpp deleted file mode 100644 index 5994717b8..000000000 --- a/code/AMF/AMFImporter.hpp +++ /dev/null @@ -1,432 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AMFImporter.hpp -/// \brief AMF-format files importer for Assimp. -/// \date 2016 -/// \author smal.root@gmail.com -// Thanks to acorn89 for support. - -#pragma once -#ifndef INCLUDED_AI_AMF_IMPORTER_H -#define INCLUDED_AI_AMF_IMPORTER_H - -#include "AMFImporter_Node.hpp" - -// Header files, Assimp. -#include -#include -#include "assimp/types.h" -#include -#include - -// Header files, stdlib. -#include - -namespace Assimp { - -/// \class AMFImporter -/// Class that holding scene graph which include: geometry, metadata, materials etc. -/// -/// Implementing features. -/// -/// Limitations. -/// -/// 1. When for texture mapping used set of source textures (r, g, b, a) not only one then attribute "tiled" for all set will be true if it true in any of -/// source textures. -/// Example. Triangle use for texture mapping three textures. Two of them has "tiled" set to false and one - set to true. In scene all three textures -/// will be tiled. -/// -/// Unsupported features: -/// 1. Node , formulas in and . For implementing this feature can be used expression parser "muParser" like in project -/// "amf_tools". -/// 2. Attribute "profile" in node . -/// 3. Curved geometry: , and children nodes of them. -/// 4. Attributes: "unit" and "version" in read but do nothing. -/// 5. stored only for root node . -/// 6. Color averaging of vertices for which 's set different colors. -/// -/// Supported nodes: -/// General: -/// ; ; and children , , , , , ; ; -/// -/// Geometry: -/// ; ; ; ; and children , , ; ; and children , , ; -/// -/// Material: -/// and children , , , ; ; ; -/// two variants of texture coordinates: -/// new - and children , , , , , -/// old - and children , , , , , -/// -class AMFImporter : public BaseImporter { -private: - struct SPP_Material;// forward declaration - - /// \struct SPP_Composite - /// Data type for post-processing step. More suitable container for part of material's composition. - struct SPP_Composite { - SPP_Material* Material;///< Pointer to material - part of composition. - std::string Formula;///< Formula for calculating ratio of \ref Material. - }; - - /// \struct SPP_Material - /// Data type for post-processing step. More suitable container for material. - struct SPP_Material { - std::string ID;///< Material ID. - std::list Metadata;///< Metadata of material. - CAMFImporter_NodeElement_Color* Color;///< Color of material. - std::list Composition;///< List of child materials if current material is composition of few another. - - /// Return color calculated for specified coordinate. - /// \param [in] pX - "x" coordinate. - /// \param [in] pY - "y" coordinate. - /// \param [in] pZ - "z" coordinate. - /// \return calculated color. - aiColor4D GetColor(const float pX, const float pY, const float pZ) const; - }; - - /// Data type for post-processing step. More suitable container for texture. - struct SPP_Texture { - std::string ID; - size_t Width, Height, Depth; - bool Tiled; - char FormatHint[9];// 8 for string + 1 for terminator. - uint8_t *Data; - }; - - /// Data type for post-processing step. Contain face data. - struct SComplexFace { - aiFace Face;///< Face vertices. - const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face. - const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. - }; - - /// Clear all temporary data. - void Clear(); - - /***********************************************/ - /************* Functions: find set *************/ - /***********************************************/ - - /// Find specified node element in node elements list ( \ref mNodeElement_List). - /// \param [in] pID - ID(name) of requested node element. - /// \param [in] pType - type of node element. - /// \param [out] pNode - pointer to pointer to item found. - /// \return true - if the node element is found, else - false. - bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const; - - /// Find requested aiNode in node list. - /// \param [in] pID - ID(name) of requested node. - /// \param [in] pNodeList - list of nodes where to find the node. - /// \param [out] pNode - pointer to pointer to item found. - /// \return true - if the node is found, else - false. - bool Find_ConvertedNode(const std::string& pID, std::list& pNodeList, aiNode** pNode) const; - - /// Find material in list for converted materials. Use at postprocessing step. - /// \param [in] pID - material ID. - /// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material). - /// \return true - if the material is found, else - false. - bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const; - - /// Find texture in list of converted textures. Use at postprocessing step, - /// \param [in] pID_R - ID of source "red" texture. - /// \param [in] pID_G - ID of source "green" texture. - /// \param [in] pID_B - ID of source "blue" texture. - /// \param [in] pID_A - ID of source "alpha" texture. Use empty string to find RGB-texture. - /// \param [out] pConvertedTextureIndex - pointer where index in list of found texture will be written. If equivalent to nullptr then nothing will be - /// written. - /// \return true - if the texture is found, else - false. - bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A, - uint32_t* pConvertedTextureIndex = nullptr) const; - - - /// Get data stored in and place it to arrays. - /// \param [in] pNodeElement - reference to node element which kept data. - /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in . - /// \param [in] pVertexColorArray - reference to vertices colors for all & pVertexCoordinateArray, - std::vector& pVertexColorArray) const; - - /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new - /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it - /// to converted textures list. - /// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified. - /// \param [in] pID_R - ID of source "red" texture. - /// \param [in] pID_G - ID of source "green" texture. - /// \param [in] pID_B - ID of source "blue" texture. - /// \param [in] pID_A - ID of source "alpha" texture. - /// \return index of the texture in array of the converted textures. - size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A); - - /// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc). - /// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after - /// processing. - /// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing. - void PostprocessHelper_SplitFacesByTextureID(std::list& pInputList, std::list >& pOutputList_Separated); - - /// Check if child elements of node element is metadata and add it to scene node. - /// \param [in] pMetadataList - reference to list with collected metadata. - /// \param [out] pSceneNode - scene node in which metadata will be added. - void Postprocess_AddMetadata(const std::list& pMetadataList, aiNode& pSceneNode) const; - - /// To create aiMesh and aiNode for it from . - /// \param [in] pNodeElement - reference to node element which kept data. - /// \param [out] pMeshList - reference to a list with all aiMesh of the scene. - /// \param [out] pSceneNode - pointer to place where new aiNode will be created. - void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list& pMeshList, aiNode** pSceneNode); - - /// Create mesh for every in . - /// \param [in] pNodeElement - reference to node element which kept data. - /// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all 's. - /// \param [in] pVertexColorArray - reference to vertices colors for all 's. If color for vertex is not set then corresponding member of array - /// contain nullptr. - /// \param [in] pObjectColor - pointer to colors for . If color is not set then argument contain nullptr. - /// \param [in] pMaterialList - reference to a list with defined materials. - /// \param [out] pMeshList - reference to a list with all aiMesh of the scene. - /// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's. - void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector& pVertexCoordinateArray, - const std::vector& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor, - std::list& pMeshList, aiNode& pSceneNode); - - /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material. - /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material. - void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial); - - /// Create and add to aiNode's list new part of scene graph defined by . - /// \param [in] pConstellation - reference to node. - /// \param [out] pNodeList - reference to aiNode's list. - void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list& pNodeList) const; - - /// Build Assimp scene graph in aiScene from collected data. - /// \param [out] pScene - pointer to aiScene where tree will be built. - void Postprocess_BuildScene(aiScene* pScene); - - - /// Call that function when close tag of node not found and exception must be raised. - /// E.g.: - /// - /// - /// - /// \throw DeadlyImportError. - /// \param [in] pNode - node name in which exception happened. - void Throw_CloseNotFound(const std::string& pNode); - - /// Call that function when attribute name is incorrect and exception must be raised. - /// \param [in] pAttrName - attribute name. - /// \throw DeadlyImportError. - void Throw_IncorrectAttr(const std::string& pAttrName); - - /// Call that function when attribute value is incorrect and exception must be raised. - /// \param [in] pAttrName - attribute name. - /// \throw DeadlyImportError. - void Throw_IncorrectAttrValue(const std::string& pAttrName); - - /// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised. - /// E.g.: - /// - /// ... - /// ... - /// - /// \throw DeadlyImportError. - /// \param [in] pNodeType - type of node which defined one more time. - /// \param [in] pDescription - message about error. E.g. what the node defined while exception raised. - void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription); - - /// Call that function when referenced element ID are not found in graph and exception must be raised. - /// \param [in] pID - ID of of element which not found. - /// \throw DeadlyImportError. - void Throw_ID_NotFound(const std::string& pID) const; - - /// Check if current node have children: .... If not then exception will throwed. - void XML_CheckNode_MustHaveChildren(); - - /// Check if current node name is equal to pNodeName. - /// \param [in] pNodeName - name for checking. - /// return true if current node name is equal to pNodeName, else - false. - bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; } - - /// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node. - /// \param [in] pParentNodeName - parent node name. Used for reporting. - void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName); - - /// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end. - /// \param [in] pNodeName - requested node name. - /// return true - if node is found, else - false. - bool XML_SearchNode(const std::string& pNodeName); - - /// Read attribute value. - /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). - /// \return read data. - bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx); - - /// Read attribute value. - /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). - /// \return read data. - float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx); - - /// Read attribute value. - /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). - /// \return read data. - uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx); - - /// Read node value. - /// \return read data. - float XML_ReadNode_GetVal_AsFloat(); - - /// Read node value. - /// \return read data. - uint32_t XML_ReadNode_GetVal_AsU32(); - - /// Read node value. - /// \return read data. - void XML_ReadNode_GetVal_AsString(std::string& pValue); - - /// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called. - /// \param [in] pNode - new current node. - void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode); - - /// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin. - void ParseHelper_Node_Exit(); - - /// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it - /// must be converted to right form - "0.xxx". - /// \param [in] pInStr - pointer to input string which can contain incorrect form of values. - /// \param [out[ pOutString - output string with right form of values. - void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString); - - /// Decode Base64-encoded data. - /// \param [in] pInputBase64 - reference to input Base64-encoded string. - /// \param [out] pOutputData - reference to output array for decoded data. - void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector& pOutputData) const; - - /// Parse node of the file. - void ParseNode_Root(); - - /// Parse node of the file. - void ParseNode_Constellation(); - - /// Parse node of the file. - void ParseNode_Instance(); - - /// Parse node of the file. - void ParseNode_Material(); - - /// Parse node. - void ParseNode_Metadata(); - - /// Parse node of the file. - void ParseNode_Object(); - - /// Parse node of the file. - void ParseNode_Texture(); - - /// Parse node of the file. - void ParseNode_Coordinates(); - - /// Parse node of the file. - void ParseNode_Edge(); - - /// Parse node of the file. - void ParseNode_Mesh(); - - /// Parse node of the file. - void ParseNode_Triangle(); - - /// Parse node of the file. - void ParseNode_Vertex(); - - /// Parse node of the file. - void ParseNode_Vertices(); - - /// Parse node of the file. - void ParseNode_Volume(); - - /// Parse node of the file. - void ParseNode_Color(); - - /// Parse of node of the file. - /// \param [in] pUseOldName - if true then use old name of node(and children) - , instead of new name - . - void ParseNode_TexMap(const bool pUseOldName = false); - -public: - /// Default constructor. - AMFImporter() AI_NO_EXCEPT - : mNodeElement_Cur(nullptr) - , mReader(nullptr) { - // empty - } - - /// Default destructor. - ~AMFImporter(); - - /// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph. - /// Also exception can be thrown if trouble will found. - /// \param [in] pFile - name of file to be parsed. - /// \param [in] pIOHandler - pointer to IO helper object. - void ParseFile(const std::string& pFile, IOSystem* pIOHandler); - - bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const; - void GetExtensionList(std::set& pExtensionList); - void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); - const aiImporterDesc* GetInfo ()const; - - AMFImporter(const AMFImporter& pScene) = delete; - AMFImporter& operator=(const AMFImporter& pScene) = delete; - -private: - static const aiImporterDesc Description; - - CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element. - std::list mNodeElement_List;///< All elements of scene graph. - irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object - std::string mUnit; - std::list mMaterial_Converted;///< List of converted materials for postprocessing step. - std::list mTexture_Converted;///< List of converted textures for postprocessing step. - -}; - -}// namespace Assimp - -#endif // INCLUDED_AI_AMF_IMPORTER_H diff --git a/code/AMF/AMFImporter_Geometry.cpp b/code/AMF/AMFImporter_Geometry.cpp deleted file mode 100644 index e9a50b656..000000000 --- a/code/AMF/AMFImporter_Geometry.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AMFImporter_Geometry.cpp -/// \brief Parsing data from geometry nodes. -/// \date 2016 -/// \author smal.root@gmail.com - -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER - -#include "AMFImporter.hpp" -#include "AMFImporter_Macro.hpp" - -namespace Assimp -{ - -// -// -// A 3D mesh hull. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Mesh() -{ -CAMFImporter_NodeElement* ne; - - // create new mesh object. - ne = new CAMFImporter_NodeElement_Mesh(mNodeElement_Cur); - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool vert_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("mesh"); - if(XML_CheckNode_NameEqual("vertices")) - { - // Check if data already defined. - if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for ."); - // read data and set flag about it - ParseNode_Vertices(); - vert_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; } - MACRO_NODECHECK_LOOPEND("mesh"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// The list of vertices to be used in defining triangles. -// Multi elements - No. -// Parent element - . -void AMFImporter::ParseNode_Vertices() -{ -CAMFImporter_NodeElement* ne; - - // create new mesh object. - ne = new CAMFImporter_NodeElement_Vertices(mNodeElement_Cur); - // Check for child nodes - if(!mReader->isEmptyElement()) - { - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("vertices"); - if(XML_CheckNode_NameEqual("vertex")) { ParseNode_Vertex(); continue; } - MACRO_NODECHECK_LOOPEND("vertices"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// A vertex to be referenced in triangles. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Vertex() -{ -CAMFImporter_NodeElement* ne; - - // create new mesh object. - ne = new CAMFImporter_NodeElement_Vertex(mNodeElement_Cur); - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool col_read = false; - bool coord_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("vertex"); - if(XML_CheckNode_NameEqual("color")) - { - // Check if data already defined. - if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("coordinates")) - { - // Check if data already defined. - if(coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for ."); - // read data and set flag about it - ParseNode_Coordinates(); - coord_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("vertex"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// Specifies the 3D location of this vertex. -// Multi elements - No. -// Parent element - . -// -// Children elements: -// , , -// Multi elements - No. -// X, Y, or Z coordinate, respectively, of a vertex position in space. -void AMFImporter::ParseNode_Coordinates() -{ -CAMFImporter_NodeElement* ne; - - // create new color object. - ne = new CAMFImporter_NodeElement_Coordinates(mNodeElement_Cur); - - CAMFImporter_NodeElement_Coordinates& als = *((CAMFImporter_NodeElement_Coordinates*)ne);// alias for convenience - - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool read_flag[3] = { false, false, false }; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("coordinates"); - MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x); - MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y); - MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z); - MACRO_NODECHECK_LOOPEND("coordinates"); - ParseHelper_Node_Exit(); - // check that all components was defined - if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined."); - - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// Defines a volume from the established vertex list. -// Multi elements - Yes. -// Parent element - . -void AMFImporter::ParseNode_Volume() -{ -std::string materialid; -std::string type; -CAMFImporter_NodeElement* ne; - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // create new object. - ne = new CAMFImporter_NodeElement_Volume(mNodeElement_Cur); - // and assign read data - ((CAMFImporter_NodeElement_Volume*)ne)->MaterialID = materialid; - ((CAMFImporter_NodeElement_Volume*)ne)->Type = type; - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool col_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("volume"); - if(XML_CheckNode_NameEqual("color")) - { - // Check if data already defined. - if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("triangle")) { ParseNode_Triangle(); continue; } - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("volume"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -// -// -// Defines a 3D triangle from three vertices, according to the right-hand rule (counter-clockwise when looking from the outside). -// Multi elements - Yes. -// Parent element - . -// -// Children elements: -// , , -// Multi elements - No. -// Index of the desired vertices in a triangle or edge. -void AMFImporter::ParseNode_Triangle() -{ -CAMFImporter_NodeElement* ne; - - // create new color object. - ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur); - - CAMFImporter_NodeElement_Triangle& als = *((CAMFImporter_NodeElement_Triangle*)ne);// alias for convenience - - // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool col_read = false, tex_read = false; - bool read_flag[3] = { false, false, false }; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("triangle"); - if(XML_CheckNode_NameEqual("color")) - { - // Check if data already defined. - if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("texmap"))// new name of node: "texmap". - { - // Check if data already defined. - if(tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for ."); - // read data and set flag about it - ParseNode_TexMap(); - tex_read = true; - - continue; - } - else if(XML_CheckNode_NameEqual("map"))// old name of node: "map". - { - // Check if data already defined. - if(tex_read) Throw_MoreThanOnceDefined("map", "Only one texture coordinate can be defined for ."); - // read data and set flag about it - ParseNode_TexMap(true); - tex_read = true; - - continue; - } - - MACRO_NODECHECK_READCOMP_U32("v1", read_flag[0], als.V[0]); - MACRO_NODECHECK_READCOMP_U32("v2", read_flag[1], als.V[1]); - MACRO_NODECHECK_READCOMP_U32("v3", read_flag[2], als.V[2]); - MACRO_NODECHECK_LOOPEND("triangle"); - ParseHelper_Node_Exit(); - // check that all components was defined - if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined."); - - }// if(!mReader->isEmptyElement()) - else - { - mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. -} - -}// namespace Assimp - -#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/AMF/AMFImporter_Node.hpp b/code/AMF/AMFImporter_Node.hpp deleted file mode 100644 index b7b7836f3..000000000 --- a/code/AMF/AMFImporter_Node.hpp +++ /dev/null @@ -1,340 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AMFImporter_Node.hpp -/// \brief Elements of scene graph. -/// \date 2016 -/// \author smal.root@gmail.com - -#pragma once -#ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H -#define INCLUDED_AI_AMF_IMPORTER_NODE_H - -// Header files, stdlib. -#include -#include -#include - -// Header files, Assimp. -#include "assimp/types.h" -#include "assimp/scene.h" - -/// \class CAMFImporter_NodeElement -/// Base class for elements of nodes. -class CAMFImporter_NodeElement { -public: - /// Define what data type contain node element. - enum EType { - ENET_Color, ///< Color element: . - ENET_Constellation,///< Grouping element: . - ENET_Coordinates, ///< Coordinates element: . - ENET_Edge, ///< Edge element: . - ENET_Instance, ///< Grouping element: . - ENET_Material, ///< Material element: . - ENET_Metadata, ///< Metadata element: . - ENET_Mesh, ///< Metadata element: . - ENET_Object, ///< Element which hold object: . - ENET_Root, ///< Root element: . - ENET_Triangle, ///< Triangle element: . - ENET_TexMap, ///< Texture coordinates element: or . - ENET_Texture, ///< Texture element: . - ENET_Vertex, ///< Vertex element: . - ENET_Vertices, ///< Vertex element: . - ENET_Volume, ///< Volume element: . - - ENET_Invalid ///< Element has invalid type and possible contain invalid data. - }; - - const EType Type;///< Type of element. - std::string ID;///< ID of element. - CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root. - std::list Child;///< Child elements. - -public: /// Destructor, virtual.. - virtual ~CAMFImporter_NodeElement() { - // empty - } - - /// Disabled copy constructor and co. - CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete; - CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete; - CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete; - CAMFImporter_NodeElement() = delete; - -protected: - /// In constructor inheritor must set element type. - /// \param [in] pType - element type. - /// \param [in] pParent - parent element. - CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent) - : Type(pType) - , ID() - , Parent(pParent) - , Child() { - // empty - } -};// class IAMFImporter_NodeElement - -/// \struct CAMFImporter_NodeElement_Constellation -/// A collection of objects or constellations with specific relative locations. -struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement { - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Constellation, pParent) - {} - -};// struct CAMFImporter_NodeElement_Constellation - -/// \struct CAMFImporter_NodeElement_Instance -/// Part of constellation. -struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement { - - std::string ObjectID;///< ID of object for instantiation. - /// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to - /// create an instance of the object in the current constellation. - aiVector3D Delta; - - /// \var Rotation - The rotation, in degrees, to rotate the referenced object about its x, y, and z axes, respectively, to create an - /// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z. - aiVector3D Rotation; - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Instance, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Metadata -/// Structure that define metadata node. -struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement { - - std::string Type;///< Type of "Value". - std::string Value;///< Value. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Metadata, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Root -/// Structure that define root node. -struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement { - - std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron". - std::string Version;///< Version of format. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Root, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Color -/// Structure that define object node. -struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement { - bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. - std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA. - aiColor4D Color; ///< Constant color. - std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b.. - - /// @brief Constructor. - /// @param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Color, pParent) - , Composed( false ) - , Color() - , Profile() { - // empty - } -}; - -/// \struct CAMFImporter_NodeElement_Material -/// Structure that define material node. -struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement { - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Material, pParent) - {} - -}; - -/// \struct CAMFImporter_NodeElement_Object -/// Structure that define object node. -struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement { - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Object, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Mesh -/// Structure that define mesh node. -struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement { - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Mesh, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Vertex -/// Structure that define vertex node. -struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement { - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Vertex, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Edge -/// Structure that define edge node. -struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement { - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Edge, pParent) - {} - -}; - -/// \struct CAMFImporter_NodeElement_Vertices -/// Structure that define vertices node. -struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement { - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Vertices, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Volume -/// Structure that define volume node. -struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement { - std::string MaterialID;///< Which material to use. - std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Volume, pParent) - {} -}; - -/// \struct CAMFImporter_NodeElement_Coordinates -/// Structure that define coordinates node. -struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement -{ - aiVector3D Coordinate;///< Coordinate. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Coordinates, pParent) - {} - -}; - -/// \struct CAMFImporter_NodeElement_TexMap -/// Structure that define texture coordinates node. -struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement { - aiVector3D TextureCoordinate[3];///< Texture coordinates. - std::string TextureID_R;///< Texture ID for red color component. - std::string TextureID_G;///< Texture ID for green color component. - std::string TextureID_B;///< Texture ID for blue color component. - std::string TextureID_A;///< Texture ID for alpha color component. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_TexMap, pParent) - , TextureCoordinate{} - , TextureID_R() - , TextureID_G() - , TextureID_B() - , TextureID_A() { - // empty - } -}; - -/// \struct CAMFImporter_NodeElement_Triangle -/// Structure that define triangle node. -struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement { - size_t V[3];///< Triangle vertices. - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Triangle, pParent) { - // empty - } -}; - -/// Structure that define texture node. -struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement { - size_t Width, Height, Depth;///< Size of the texture. - std::vector Data;///< Data of the texture. - bool Tiled; - - /// Constructor. - /// \param [in] pParent - pointer to parent node. - CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Texture, pParent) - , Width( 0 ) - , Height( 0 ) - , Depth( 0 ) - , Data() - , Tiled( false ){ - // empty - } -}; - -#endif // INCLUDED_AI_AMF_IMPORTER_NODE_H diff --git a/code/AMF/AMFImporter_Postprocess.cpp b/code/AMF/AMFImporter_Postprocess.cpp deleted file mode 100644 index 273b8e0c4..000000000 --- a/code/AMF/AMFImporter_Postprocess.cpp +++ /dev/null @@ -1,978 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 AMFImporter_Postprocess.cpp -/// \brief Convert built scenegraph and objects to Assimp scenegraph. -/// \date 2016 -/// \author smal.root@gmail.com - -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER - -#include "AMFImporter.hpp" - -// Header files, Assimp. -#include -#include -#include - -// Header files, stdlib. -#include - -namespace Assimp -{ - -aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const -{ - aiColor4D tcol; - - // Check if stored data are supported. - if(!Composition.empty()) - { - throw DeadlyImportError("IME. GetColor for composition"); - } - else if(Color->Composed) - { - throw DeadlyImportError("IME. GetColor, composed color"); - } - else - { - tcol = Color->Color; - } - - // Check if default color must be used - if((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) - { - tcol.r = 0.5f; - tcol.g = 0.5f; - tcol.b = 0.5f; - tcol.a = 1; - } - - return tcol; -} - -void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector& pVertexCoordinateArray, - std::vector& pVertexColorArray) const -{ - CAMFImporter_NodeElement_Vertices* vn = nullptr; - size_t col_idx; - - // All data stored in "vertices", search for it. - for(CAMFImporter_NodeElement* ne_child: pNodeElement.Child) - { - if(ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices*)ne_child; - } - - // If "vertices" not found then no work for us. - if(vn == nullptr) return; - - pVertexCoordinateArray.reserve(vn->Child.size());// all coordinates stored as child and we need to reserve space for future push_back's. - pVertexColorArray.resize(vn->Child.size());// colors count equal vertices count. - col_idx = 0; - // Inside vertices collect all data and place to arrays - for(CAMFImporter_NodeElement* vn_child: vn->Child) - { - // vertices, colors - if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) - { - // by default clear color for current vertex - pVertexColorArray[col_idx] = nullptr; - - for(CAMFImporter_NodeElement* vtx: vn_child->Child) - { - if(vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates) - { - pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates*)vtx)->Coordinate); - - continue; - } - - if(vtx->Type == CAMFImporter_NodeElement::ENET_Color) - { - pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color*)vtx; - - continue; - } - }// for(CAMFImporter_NodeElement* vtx: vn_child->Child) - - col_idx++; - }// if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) - }// for(CAMFImporter_NodeElement* vn_child: vn->Child) -} - -size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, - const std::string& pID_A) -{ - size_t TextureConverted_Index; - std::string TextureConverted_ID; - - // check input data - if(pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty()) - throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined."); - - // Create ID - TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A; - // Check if texture specified by set of IDs is converted already. - TextureConverted_Index = 0; - for(const SPP_Texture& tex_convd: mTexture_Converted) - { - if ( tex_convd.ID == TextureConverted_ID ) { - return TextureConverted_Index; - } else { - ++TextureConverted_Index; - } - } - - // - // Converted texture not found, create it. - // - CAMFImporter_NodeElement_Texture* src_texture[4]{nullptr}; - std::vector src_texture_4check; - SPP_Texture converted_texture; - - {// find all specified source textures - CAMFImporter_NodeElement* t_tex; - - // R - if(!pID_R.empty()) - { - if(!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R); - - src_texture[0] = (CAMFImporter_NodeElement_Texture*)t_tex; - src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex); - } - else - { - src_texture[0] = nullptr; - } - - // G - if(!pID_G.empty()) - { - if(!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G); - - src_texture[1] = (CAMFImporter_NodeElement_Texture*)t_tex; - src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex); - } - else - { - src_texture[1] = nullptr; - } - - // B - if(!pID_B.empty()) - { - if(!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B); - - src_texture[2] = (CAMFImporter_NodeElement_Texture*)t_tex; - src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex); - } - else - { - src_texture[2] = nullptr; - } - - // A - if(!pID_A.empty()) - { - if(!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A); - - src_texture[3] = (CAMFImporter_NodeElement_Texture*)t_tex; - src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex); - } - else - { - src_texture[3] = nullptr; - } - }// END: find all specified source textures - - // check that all textures has same size - if(src_texture_4check.size() > 1) - { - for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++) - { - if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) || - (src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth)) - { - throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size."); - } - } - }// if(src_texture_4check.size() > 1) - - // set texture attributes - converted_texture.Width = src_texture_4check[0]->Width; - converted_texture.Height = src_texture_4check[0]->Height; - converted_texture.Depth = src_texture_4check[0]->Depth; - // if one of source texture is tiled then converted texture is tiled too. - converted_texture.Tiled = false; - for(uint8_t i = 0; i < src_texture_4check.size(); i++) converted_texture.Tiled |= src_texture_4check[i]->Tiled; - - // Create format hint. - strcpy(converted_texture.FormatHint, "rgba0000");// copy initial string. - if(!pID_R.empty()) converted_texture.FormatHint[4] = '8'; - if(!pID_G.empty()) converted_texture.FormatHint[5] = '8'; - if(!pID_B.empty()) converted_texture.FormatHint[6] = '8'; - if(!pID_A.empty()) converted_texture.FormatHint[7] = '8'; - - // - // Сopy data of textures. - // - size_t tex_size = 0; - size_t step = 0; - size_t off_g = 0; - size_t off_b = 0; - - // Calculate size of the target array and rule how data will be copied. - if(!pID_R.empty() && nullptr != src_texture[ 0 ] ) { - tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++; - } - if(!pID_G.empty() && nullptr != src_texture[ 1 ] ) { - tex_size += src_texture[1]->Data.size(); step++, off_b++; - } - if(!pID_B.empty() && nullptr != src_texture[ 2 ] ) { - tex_size += src_texture[2]->Data.size(); step++; - } - if(!pID_A.empty() && nullptr != src_texture[ 3 ] ) { - tex_size += src_texture[3]->Data.size(); step++; - } - - // Create target array. - converted_texture.Data = new uint8_t[tex_size]; - // And copy data - auto CopyTextureData = [&](const std::string& pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void - { - if(!pID.empty()) - { - for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) { - CAMFImporter_NodeElement_Texture* tex = src_texture[pSrcTexNum]; - ai_assert(tex); - converted_texture.Data[idx_target] = tex->Data.at(idx_src); - } - } - };// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void - - CopyTextureData(pID_R, 0, step, 0); - CopyTextureData(pID_G, off_g, step, 1); - CopyTextureData(pID_B, off_b, step, 2); - CopyTextureData(pID_A, step - 1, step, 3); - - // Store new converted texture ID - converted_texture.ID = TextureConverted_ID; - // Store new converted texture - mTexture_Converted.push_back(converted_texture); - - return TextureConverted_Index; -} - -void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list& pInputList, std::list >& pOutputList_Separated) -{ - auto texmap_is_equal = [](const CAMFImporter_NodeElement_TexMap* pTexMap1, const CAMFImporter_NodeElement_TexMap* pTexMap2) -> bool - { - if((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true; - if(pTexMap1 == nullptr) return false; - if(pTexMap2 == nullptr) return false; - - if(pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false; - if(pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false; - if(pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false; - if(pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false; - - return true; - }; - - pOutputList_Separated.clear(); - if(pInputList.empty()) return; - - do - { - SComplexFace face_start = pInputList.front(); - std::list face_list_cur; - - for(std::list::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;) - { - if(texmap_is_equal(face_start.TexMap, it->TexMap)) - { - auto it_old = it; - - ++it; - face_list_cur.push_back(*it_old); - pInputList.erase(it_old); - } - else - { - ++it; - } - } - - if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur); - - } while(!pInputList.empty()); -} - -void AMFImporter::Postprocess_AddMetadata(const std::list& metadataList, aiNode& sceneNode) const -{ - if ( !metadataList.empty() ) - { - if(sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong."); - - // copy collected metadata to output node. - sceneNode.mMetaData = aiMetadata::Alloc( static_cast(metadataList.size()) ); - size_t meta_idx( 0 ); - - for(const CAMFImporter_NodeElement_Metadata& metadata: metadataList) - { - sceneNode.mMetaData->Set(static_cast(meta_idx++), metadata.Type, aiString(metadata.Value)); - } - }// if(!metadataList.empty()) -} - -void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list& pMeshList, aiNode** pSceneNode) -{ -CAMFImporter_NodeElement_Color* object_color = nullptr; - - // create new aiNode and set name as has. - *pSceneNode = new aiNode; - (*pSceneNode)->mName = pNodeElement.ID; - // read mesh and color - for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) - { - std::vector vertex_arr; - std::vector color_arr; - - // color for object - if(ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color*)ne_child; - - if(ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) - { - // Create arrays from children of mesh: vertices. - PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr); - // Use this arrays as a source when creating every aiMesh - Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode); - } - }// for(const CAMFImporter_NodeElement* ne_child: pNodeElement) -} - -void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector& pVertexCoordinateArray, - const std::vector& pVertexColorArray, - const CAMFImporter_NodeElement_Color* pObjectColor, std::list& pMeshList, aiNode& pSceneNode) -{ -std::list mesh_idx; - - // all data stored in "volume", search for it. - for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) - { - const CAMFImporter_NodeElement_Color* ne_volume_color = nullptr; - const SPP_Material* cur_mat = nullptr; - - if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) - { - /******************* Get faces *******************/ - const CAMFImporter_NodeElement_Volume* ne_volume = reinterpret_cast(ne_child); - - std::list complex_faces_list;// List of the faces of the volume. - std::list > complex_faces_toplist;// List of the face list for every mesh. - - // check if volume use material - if(!ne_volume->MaterialID.empty()) - { - if(!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID); - } - - // inside "volume" collect all data and place to arrays or create new objects - for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child) - { - // color for volume - if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color) - { - ne_volume_color = reinterpret_cast(ne_volume_child); - } - else if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle)// triangles, triangles colors - { - const CAMFImporter_NodeElement_Triangle& tri_al = *reinterpret_cast(ne_volume_child); - - SComplexFace complex_face; - - // initialize pointers - complex_face.Color = nullptr; - complex_face.TexMap = nullptr; - // get data from triangle children: color, texture coordinates. - if(tri_al.Child.size()) - { - for(const CAMFImporter_NodeElement* ne_triangle_child: tri_al.Child) - { - if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color) - complex_face.Color = reinterpret_cast(ne_triangle_child); - else if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap) - complex_face.TexMap = reinterpret_cast(ne_triangle_child); - } - }// if(tri_al.Child.size()) - - // create new face and store it. - complex_face.Face.mNumIndices = 3; - complex_face.Face.mIndices = new unsigned int[3]; - complex_face.Face.mIndices[0] = static_cast(tri_al.V[0]); - complex_face.Face.mIndices[1] = static_cast(tri_al.V[1]); - complex_face.Face.mIndices[2] = static_cast(tri_al.V[2]); - complex_faces_list.push_back(complex_face); - } - }// for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child) - - /**** Split faces list: one list per mesh ****/ - PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist); - - /***** Create mesh for every faces list ******/ - for(std::list& face_list_cur: complex_faces_toplist) - { - auto VertexIndex_GetMinimal = [](const std::list& pFaceList, const size_t* pBiggerThan) -> size_t - { - size_t rv=0; - - if(pBiggerThan != nullptr) - { - bool found = false; - - for(const SComplexFace& face: pFaceList) - { - for(size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) - { - if(face.Face.mIndices[idx_vert] > *pBiggerThan) - { - rv = face.Face.mIndices[idx_vert]; - found = true; - - break; - } - } - - if(found) break; - } - - if(!found) return *pBiggerThan; - } - else - { - rv = pFaceList.front().Face.mIndices[0]; - }// if(pBiggerThan != nullptr) else - - for(const SComplexFace& face: pFaceList) - { - for(size_t vi = 0; vi < face.Face.mNumIndices; vi++) - { - if(face.Face.mIndices[vi] < rv) - { - if(pBiggerThan != nullptr) - { - if(face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi]; - } - else - { - rv = face.Face.mIndices[vi]; - } - } - } - }// for(const SComplexFace& face: pFaceList) - - return rv; - };// auto VertexIndex_GetMinimal = [](const std::list& pFaceList, const size_t* pBiggerThan) -> size_t - - auto VertexIndex_Replace = [](std::list& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void - { - for(const SComplexFace& face: pFaceList) - { - for(size_t vi = 0; vi < face.Face.mNumIndices; vi++) - { - if(face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast(pIdx_To); - } - } - };// auto VertexIndex_Replace = [](std::list& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void - - auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D - { - // Color priorities(In descending order): - // 1. triangle color; - // 2. vertex color; - // 3. volume color; - // 4. object color; - // 5. material; - // 6. default - invisible coat. - // - // Fill vertices colors in color priority list above that's points from 1 to 6. - if((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr))// check for vertex color - { - if(pVertexColorArray[pIdx]->Composed) - throw DeadlyImportError("IME: vertex color composed"); - else - return pVertexColorArray[pIdx]->Color; - } - else if(ne_volume_color != nullptr)// check for volume color - { - if(ne_volume_color->Composed) - throw DeadlyImportError("IME: volume color composed"); - else - return ne_volume_color->Color; - } - else if(pObjectColor != nullptr)// check for object color - { - if(pObjectColor->Composed) - throw DeadlyImportError("IME: object color composed"); - else - return pObjectColor->Color; - } - else if(cur_mat != nullptr)// check for material - { - return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z); - } - else// set default color. - { - return {0, 0, 0, 0}; - }// if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else - - };// auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D - - aiMesh* tmesh = new aiMesh; - - tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;// Only triangles is supported by AMF. - // - // set geometry and colors (vertices) - // - // copy faces/triangles - tmesh->mNumFaces = static_cast(face_list_cur.size()); - tmesh->mFaces = new aiFace[tmesh->mNumFaces]; - - // Create vertices list and optimize indices. Optimisation mean following.In AMF all volumes use one big list of vertices. And one volume - // can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10. - // Do you need all this thousands of garbage? Of course no. So, optimisation step transformate sparse indices set to continuous. - size_t VertexCount_Max = tmesh->mNumFaces * 3;// 3 - triangles. - std::vector vert_arr, texcoord_arr; - std::vector col_arr; - - vert_arr.reserve(VertexCount_Max * 2);// "* 2" - see below TODO. - col_arr.reserve(VertexCount_Max * 2); - - {// fill arrays - size_t vert_idx_from, vert_idx_to; - - // first iteration. - vert_idx_to = 0; - vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr); - vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from)); - col_arr.push_back(Vertex_CalculateColor(vert_idx_from)); - if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to); - - // rest iterations - do - { - vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to); - if(vert_idx_from == vert_idx_to) break;// all indices are transferred, - - vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from)); - col_arr.push_back(Vertex_CalculateColor(vert_idx_from)); - vert_idx_to++; - if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to); - - } while(true); - }// fill arrays. END. - - // - // check if triangle colors are used and create additional faces if needed. - // - for(const SComplexFace& face_cur: face_list_cur) - { - if(face_cur.Color != nullptr) - { - aiColor4D face_color; - size_t vert_idx_new = vert_arr.size(); - - if(face_cur.Color->Composed) - throw DeadlyImportError("IME: face color composed"); - else - face_color = face_cur.Color->Color; - - for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) - { - vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind])); - col_arr.push_back(face_color); - face_cur.Face.mIndices[idx_ind] = static_cast(vert_idx_new++); - } - }// if(face_cur.Color != nullptr) - }// for(const SComplexFace& face_cur: face_list_cur) - - // - // if texture is used then copy texture coordinates too. - // - if(face_list_cur.front().TexMap != nullptr) - { - size_t idx_vert_new = vert_arr.size(); - ///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for - /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about - /// optimisation. - bool* idx_vert_used; - - idx_vert_used = new bool[VertexCount_Max * 2]; - for(size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++) idx_vert_used[i] = false; - - // This ID's will be used when set materials ID in scene. - tmesh->mMaterialIndex = static_cast(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R, - face_list_cur.front().TexMap->TextureID_G, - face_list_cur.front().TexMap->TextureID_B, - face_list_cur.front().TexMap->TextureID_A)); - texcoord_arr.resize(VertexCount_Max * 2); - for(const SComplexFace& face_cur: face_list_cur) - { - for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) - { - const size_t idx_vert = face_cur.Face.mIndices[idx_ind]; - - if(!idx_vert_used[idx_vert]) - { - texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind]; - idx_vert_used[idx_vert] = true; - } - else if(texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind]) - { - // in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture - // coordinates. - vert_arr.push_back(vert_arr.at(idx_vert)); - col_arr.push_back(col_arr.at(idx_vert)); - texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind]; - face_cur.Face.mIndices[idx_ind] = static_cast(idx_vert_new++); - } - }// for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) - }// for(const SComplexFace& face_cur: face_list_cur) - - delete [] idx_vert_used; - // shrink array - texcoord_arr.resize(idx_vert_new); - }// if(face_list_cur.front().TexMap != nullptr) - - // - // copy collected data to mesh - // - tmesh->mNumVertices = static_cast(vert_arr.size()); - tmesh->mVertices = new aiVector3D[tmesh->mNumVertices]; - tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices]; - - memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D)); - memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D)); - if(texcoord_arr.size() > 0) - { - tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices]; - memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D)); - tmesh->mNumUVComponents[0] = 2;// U and V stored in "x", "y" of aiVector3D. - } - - size_t idx_face = 0; - for(const SComplexFace& face_cur: face_list_cur) tmesh->mFaces[idx_face++] = face_cur.Face; - - // store new aiMesh - mesh_idx.push_back(static_cast(pMeshList.size())); - pMeshList.push_back(tmesh); - }// for(const std::list& face_list_cur: complex_faces_toplist) - }// if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) - }// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) - - // if meshes was created then assign new indices with current aiNode - if(!mesh_idx.empty()) - { - std::list::const_iterator mit = mesh_idx.begin(); - - pSceneNode.mNumMeshes = static_cast(mesh_idx.size()); - pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes]; - for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *mit++; - }// if(mesh_idx.size() > 0) -} - -void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial) -{ -SPP_Material new_mat; - - new_mat.ID = pMaterial.ID; - for(const CAMFImporter_NodeElement* mat_child: pMaterial.Child) - { - if(mat_child->Type == CAMFImporter_NodeElement::ENET_Color) - { - new_mat.Color = (CAMFImporter_NodeElement_Color*)mat_child; - } - else if(mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata) - { - new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata*)mat_child); - } - }// for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child) - - // place converted material to special list - mMaterial_Converted.push_back(new_mat); -} - -void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list& pNodeList) const -{ -aiNode* con_node; -std::list ch_node; - - // We will build next hierarchy: - // aiNode as parent () for set of nodes as a children - // |- aiNode for transformation ( -> , ) - aiNode for pointing to object ("objectid") - // ... - // \_ aiNode for transformation ( -> , ) - aiNode for pointing to object ("objectid") - con_node = new aiNode; - con_node->mName = pConstellation.ID; - // Walk through children and search for instances of another objects, constellations. - for(const CAMFImporter_NodeElement* ne: pConstellation.Child) - { - aiMatrix4x4 tmat; - aiNode* t_node; - aiNode* found_node; - - if(ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue; - if(ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only nodes can be in ."); - - // create alias for conveniance - CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne); - // find referenced object - if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID); - - // create node for applying transformation - t_node = new aiNode; - t_node->mParent = con_node; - // apply transformation - aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat; - aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat; - aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat; - aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat; - // create array for one child node - t_node->mNumChildren = 1; - t_node->mChildren = new aiNode*[t_node->mNumChildren]; - SceneCombiner::Copy(&t_node->mChildren[0], found_node); - t_node->mChildren[0]->mParent = t_node; - ch_node.push_back(t_node); - }// for(const CAMFImporter_NodeElement* ne: pConstellation.Child) - - // copy found aiNode's as children - if(ch_node.empty()) throw DeadlyImportError(" must have at least one ."); - - size_t ch_idx = 0; - - con_node->mNumChildren = static_cast(ch_node.size()); - con_node->mChildren = new aiNode*[con_node->mNumChildren]; - for(aiNode* node: ch_node) con_node->mChildren[ch_idx++] = node; - - // and place "root" of node to node list - pNodeList.push_back(con_node); -} - -void AMFImporter::Postprocess_BuildScene(aiScene* pScene) -{ -std::list node_list; -std::list mesh_list; -std::list meta_list; - - // - // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used. - // For building aiScene we are must to do few steps: - // 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() element - CAMFImporter_NodeElement* root_el = nullptr; - - for(CAMFImporter_NodeElement* ne: mNodeElement_List) - { - if(ne->Type != CAMFImporter_NodeElement::ENET_Root) continue; - - root_el = ne; - - break; - }// for(const CAMFImporter_NodeElement* ne: mNodeElement_List) - - // Check if root element are found. - if(root_el == nullptr) throw DeadlyImportError("Root() element not found."); - - // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in : , , , - // and . But at first we must read and because they will be used in . can be read - // at any moment. - // - // 1. - // 2. will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet - for(const CAMFImporter_NodeElement* root_child: root_el->Child) - { - if(root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material*)root_child)); - } - - // After "appearance" nodes we must read because it will be used in -> . - // - // 3. - for(const CAMFImporter_NodeElement* root_child: root_el->Child) - { - if(root_child->Type == CAMFImporter_NodeElement::ENET_Object) - { - aiNode* tnode = nullptr; - - // for mesh and node must be built: object ID assigned to aiNode name and will be used in future for - Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object*)root_child), mesh_list, &tnode); - if(tnode != nullptr) node_list.push_back(tnode); - - } - }// for(const CAMFImporter_NodeElement* root_child: root_el->Child) - - // And finally read rest of nodes. - // - for(const CAMFImporter_NodeElement* root_child: root_el->Child) - { - // 4. - if(root_child->Type == CAMFImporter_NodeElement::ENET_Constellation) - { - // and at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's. - Postprocess_BuildConstellation(*((CAMFImporter_NodeElement_Constellation*)root_child), node_list); - } - - // 5, - if(root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata*)root_child); - }// for(const CAMFImporter_NodeElement* root_child: root_el->Child) - - // at now we can add collected metadata to root node - Postprocess_AddMetadata(meta_list, *pScene->mRootNode); - // - // Check constellation children - // - // As said in specification: - // "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing." - // What that means? For example: if some object is used in constellation then you must show only constellation but not original object. - // And at this step we are checking that relations. -nl_clean_loop: - - if(node_list.size() > 1) - { - // walk through all nodes - for(std::list::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) - { - // and try to find them in another top nodes. - std::list::const_iterator next_it = nl_it; - - ++next_it; - for(; next_it != node_list.end(); ++next_it) - { - if((*next_it)->FindNode((*nl_it)->mName) != nullptr) - { - // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop. - node_list.erase(nl_it); - - goto nl_clean_loop; - } - }// for(; next_it != node_list.end(); next_it++) - }// for(std::list::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++) - } - - // - // move created objects to aiScene - // - // - // Nodes - if(!node_list.empty()) - { - std::list::const_iterator nl_it = node_list.begin(); - - pScene->mRootNode->mNumChildren = static_cast(node_list.size()); - pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; - for(size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) - { - // Objects and constellation that must be showed placed at top of hierarchy in node. So all aiNode's in node_list must have - // mRootNode only as parent. - (*nl_it)->mParent = pScene->mRootNode; - pScene->mRootNode->mChildren[i] = *nl_it++; - } - }// if(node_list.size() > 0) - - // - // Meshes - if(!mesh_list.empty()) - { - std::list::const_iterator ml_it = mesh_list.begin(); - - pScene->mNumMeshes = static_cast(mesh_list.size()); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *ml_it++; - }// if(mesh_list.size() > 0) - - // - // Textures - pScene->mNumTextures = static_cast(mTexture_Converted.size()); - if(pScene->mNumTextures > 0) - { - size_t idx; - - idx = 0; - pScene->mTextures = new aiTexture*[pScene->mNumTextures]; - for(const SPP_Texture& tex_convd: mTexture_Converted) - { - pScene->mTextures[idx] = new aiTexture; - pScene->mTextures[idx]->mWidth = static_cast(tex_convd.Width); - pScene->mTextures[idx]->mHeight = static_cast(tex_convd.Height); - pScene->mTextures[idx]->pcData = (aiTexel*)tex_convd.Data; - // texture format description. - strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint); - idx++; - }// for(const SPP_Texture& tex_convd: mTexture_Converted) - - // Create materials for embedded textures. - idx = 0; - pScene->mNumMaterials = static_cast(mTexture_Converted.size()); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - for(const SPP_Texture& tex_convd: mTexture_Converted) - { - const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx)); - const int mode = aiTextureOp_Multiply; - const int repeat = tex_convd.Tiled ? 1 : 0; - - pScene->mMaterials[idx] = new aiMaterial; - pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0)); - pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0)); - pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); - pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); - idx++; - } - }// if(pScene->mNumTextures > 0) -}// END: after that walk through children of root and collect data - -}// namespace Assimp - -#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/3DS/3DSConverter.cpp b/code/AssetLib/3DS/3DSConverter.cpp similarity index 59% rename from code/3DS/3DSConverter.cpp rename to code/AssetLib/3DS/3DSConverter.cpp index 3f0e20bb0..ef37e03de 100644 --- a/code/3DS/3DSConverter.cpp +++ b/code/AssetLib/3DS/3DSConverter.cpp @@ -5,8 +5,6 @@ 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, @@ -43,17 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the 3ds importer class */ - #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "3DSLoader.h" #include "Common/TargetAnimation.h" +#include #include #include -#include -#include #include +#include using namespace Assimp; @@ -61,75 +58,66 @@ static const unsigned int NotSet = 0xcdcdcdcd; // ------------------------------------------------------------------------------------------------ // Setup final material indices, generae a default material if necessary -void Discreet3DSImporter::ReplaceDefaultMaterial() -{ +void Discreet3DSImporter::ReplaceDefaultMaterial() { // Try to find an existing material that matches the // typical default material setting: // - no textures // - diffuse color (in grey!) // NOTE: This is here to workaround the fact that some // exporters are writing a default material, too. - unsigned int idx( NotSet ); - for (unsigned int i = 0; i < mScene->mMaterials.size();++i) - { + unsigned int idx(NotSet); + for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) { std::string s = mScene->mMaterials[i].mName; - for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) { - *it = static_cast< char >( ::tolower( *it ) ); + for (std::string::iterator it = s.begin(); it != s.end(); ++it) { + *it = static_cast(::tolower(*it)); } - if (std::string::npos == s.find("default"))continue; + if (std::string::npos == s.find("default")) continue; if (mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.g || - mScene->mMaterials[i].mDiffuse.r != - mScene->mMaterials[i].mDiffuse.b)continue; + mScene->mMaterials[i].mDiffuse.g || + mScene->mMaterials[i].mDiffuse.r != + mScene->mMaterials[i].mDiffuse.b) continue; - if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || - mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || - mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || - mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || - mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || - mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) - { + if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || + mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || + mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || + mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || + mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || + mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) { continue; } idx = i; } - if ( NotSet == idx ) { - idx = ( unsigned int )mScene->mMaterials.size(); + if (NotSet == idx) { + idx = (unsigned int)mScene->mMaterials.size(); } // now iterate through all meshes and through all faces and // find all faces that are using the default material unsigned int cnt = 0; for (std::vector::iterator - i = mScene->mMeshes.begin(); - i != mScene->mMeshes.end();++i) - { + i = mScene->mMeshes.begin(); + i != mScene->mMeshes.end(); ++i) { for (std::vector::iterator - a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a) - { + a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end(); ++a) { // NOTE: The additional check seems to be necessary, // some exporters seem to generate invalid data here - if (0xcdcdcdcd == (*a)) - { + if (0xcdcdcdcd == (*a)) { (*a) = idx; ++cnt; - } - else if ( (*a) >= mScene->mMaterials.size()) - { + } else if ((*a) >= mScene->mMaterials.size()) { (*a) = idx; ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material"); ++cnt; } } } - if (cnt && idx == mScene->mMaterials.size()) - { + if (cnt && idx == mScene->mMaterials.size()) { // We need to create our own default material D3DS::Material sMat("%%%DEFAULT"); - sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); + sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f); mScene->mMaterials.push_back(sMat); ASSIMP_LOG_INFO("3DS: Generating default material"); @@ -138,22 +126,17 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() // ------------------------------------------------------------------------------------------------ // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached -void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) -{ - for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) - { +void Discreet3DSImporter::CheckIndices(D3DS::Mesh &sMesh) { + for (std::vector::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) { // check whether all indices are in range - for (unsigned int a = 0; a < 3;++a) - { - if ((*i).mIndices[a] >= sMesh.mPositions.size()) - { + for (unsigned int a = 0; a < 3; ++a) { + if ((*i).mIndices[a] >= sMesh.mPositions.size()) { ASSIMP_LOG_WARN("3DS: Vertex index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; + (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size() - 1; } - if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) - { + if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) { ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)"); - (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; + (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size() - 1; } } } @@ -161,24 +144,21 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) // ------------------------------------------------------------------------------------------------ // Generate out unique verbose format representation -void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) -{ +void Discreet3DSImporter::MakeUnique(D3DS::Mesh &sMesh) { // TODO: really necessary? I don't think. Just a waste of memory and time // to do it now in a separate buffer. // Allocate output storage - std::vector vNew (sMesh.mFaces.size() * 3); + std::vector vNew(sMesh.mFaces.size() * 3); std::vector vNew2; if (sMesh.mTexCoords.size()) vNew2.resize(sMesh.mFaces.size() * 3); - for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) - { - D3DS::Face& face = sMesh.mFaces[i]; + for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) { + D3DS::Face &face = sMesh.mFaces[i]; // Positions - for (unsigned int a = 0; a < 3;++a,++base) - { + for (unsigned int a = 0; a < 3; ++a, ++base) { vNew[base] = sMesh.mPositions[face.mIndices[a]]; if (sMesh.mTexCoords.size()) vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; @@ -192,26 +172,24 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) // ------------------------------------------------------------------------------------------------ // Convert a 3DS texture to texture keys in an aiMaterial -void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) -{ +void CopyTexture(aiMaterial &mat, D3DS::Texture &texture, aiTextureType type) { // Setup the texture name aiString tex; - tex.Set( texture.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + tex.Set(texture.mMapName); + mat.AddProperty(&tex, AI_MATKEY_TEXTURE(type, 0)); // Setup the texture blend factor if (is_not_qnan(texture.mTextureBlend)) - mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + mat.AddProperty(&texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type, 0)); // Setup the texture mapping mode int mapMode = static_cast(texture.mMapMode); - mat.AddProperty(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); - mat.AddProperty(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); + mat.AddProperty(&mapMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0)); + mat.AddProperty(&mapMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0)); // Mirroring - double the scaling values // FIXME: this is not really correct ... - if (texture.mMapMode == aiTextureMapMode_Mirror) - { + if (texture.mMapMode == aiTextureMapMode_Mirror) { texture.mScaleU *= 2.0; texture.mScaleV *= 2.0; texture.mOffsetU /= 2.0; @@ -219,21 +197,19 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) } // Setup texture UV transformations - mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); + mat.AddProperty(&texture.mOffsetU, 5, AI_MATKEY_UVTRANSFORM(type, 0)); } // ------------------------------------------------------------------------------------------------ // Convert a 3DS material to an aiMaterial -void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, - aiMaterial& mat) -{ +void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat, + aiMaterial &mat) { // NOTE: Pass the background image to the viewer by bypassing the // material system. This is an evil hack, never do it again! - if (0 != mBackgroundImage.length() && bHasBG) - { + if (0 != mBackgroundImage.length() && bHasBG) { aiString tex; - tex.Set( mBackgroundImage); - mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); + tex.Set(mBackgroundImage); + mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); // Be sure this is only done for the first material mBackgroundImage = std::string(""); @@ -245,143 +221,138 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, oldMat.mAmbient.b += mClrAmbient.b; aiString name; - name.Set( oldMat.mName); - mat.AddProperty( &name, AI_MATKEY_NAME); + name.Set(oldMat.mName); + mat.AddProperty(&name, AI_MATKEY_NAME); // Material colors - mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); - mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + mat.AddProperty(&oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.AddProperty(&oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.AddProperty(&oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.AddProperty(&oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); // Phong shininess and shininess strength if (D3DS::Discreet3DS::Phong == oldMat.mShading || - D3DS::Discreet3DS::Metal == oldMat.mShading) - { - if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) - { + D3DS::Discreet3DS::Metal == oldMat.mShading) { + if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) { oldMat.mShading = D3DS::Discreet3DS::Gouraud; - } - else - { - mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); - mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); + } else { + mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); + mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); } } // Opacity - mat.AddProperty( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); + mat.AddProperty(&oldMat.mTransparency, 1, AI_MATKEY_OPACITY); // Bump height scaling - mat.AddProperty( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); + mat.AddProperty(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING); // Two sided rendering? - if (oldMat.mTwoSided) - { + if (oldMat.mTwoSided) { int i = 1; - mat.AddProperty(&i,1,AI_MATKEY_TWOSIDED); + mat.AddProperty(&i, 1, AI_MATKEY_TWOSIDED); } // Shading mode aiShadingMode eShading = aiShadingMode_NoShading; - switch (oldMat.mShading) - { - case D3DS::Discreet3DS::Flat: - eShading = aiShadingMode_Flat; break; + switch (oldMat.mShading) { + case D3DS::Discreet3DS::Flat: + eShading = aiShadingMode_Flat; + break; - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse shading - case D3DS::Discreet3DS::Wire: - { - // Set the wireframe flag - unsigned int iWire = 1; - mat.AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse shading + case D3DS::Discreet3DS::Wire: { + // Set the wireframe flag + unsigned int iWire = 1; + mat.AddProperty((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME); + } - case D3DS::Discreet3DS::Gouraud: - eShading = aiShadingMode_Gouraud; break; + case D3DS::Discreet3DS::Gouraud: + eShading = aiShadingMode_Gouraud; + break; - // assume cook-torrance shading for metals. - case D3DS::Discreet3DS::Phong : - eShading = aiShadingMode_Phong; break; + // assume cook-torrance shading for metals. + case D3DS::Discreet3DS::Phong: + eShading = aiShadingMode_Phong; + break; - case D3DS::Discreet3DS::Metal : - eShading = aiShadingMode_CookTorrance; break; + case D3DS::Discreet3DS::Metal: + eShading = aiShadingMode_CookTorrance; + break; - // FIX to workaround a warning with GCC 4 who complained - // about a missing case Blinn: here - Blinn isn't a valid - // value in the 3DS Loader, it is just needed for ASE - case D3DS::Discreet3DS::Blinn : - eShading = aiShadingMode_Blinn; break; + // FIX to workaround a warning with GCC 4 who complained + // about a missing case Blinn: here - Blinn isn't a valid + // value in the 3DS Loader, it is just needed for ASE + case D3DS::Discreet3DS::Blinn: + eShading = aiShadingMode_Blinn; + break; } int eShading_ = static_cast(eShading); mat.AddProperty(&eShading_, 1, AI_MATKEY_SHADING_MODEL); // DIFFUSE texture - if( oldMat.sTexDiffuse.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); + if (oldMat.sTexDiffuse.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexDiffuse, aiTextureType_DIFFUSE); // SPECULAR texture - if( oldMat.sTexSpecular.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); + if (oldMat.sTexSpecular.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexSpecular, aiTextureType_SPECULAR); // OPACITY texture - if( oldMat.sTexOpacity.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); + if (oldMat.sTexOpacity.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexOpacity, aiTextureType_OPACITY); // EMISSIVE texture - if( oldMat.sTexEmissive.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); + if (oldMat.sTexEmissive.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexEmissive, aiTextureType_EMISSIVE); // BUMP texture - if( oldMat.sTexBump.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); + if (oldMat.sTexBump.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexBump, aiTextureType_HEIGHT); // SHININESS texture - if( oldMat.sTexShininess.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); + if (oldMat.sTexShininess.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexShininess, aiTextureType_SHININESS); // REFLECTION texture - if( oldMat.sTexReflective.mMapName.length() > 0) - CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); + if (oldMat.sTexReflective.mMapName.length() > 0) + CopyTexture(mat, oldMat.sTexReflective, aiTextureType_REFLECTION); // Store the name of the material itself, too - if( oldMat.mName.length()) { + if (oldMat.mName.length()) { aiString tex; - tex.Set( oldMat.mName); - mat.AddProperty( &tex, AI_MATKEY_NAME); + tex.Set(oldMat.mName); + mat.AddProperty(&tex, AI_MATKEY_NAME); } } // ------------------------------------------------------------------------------------------------ // Split meshes by their materials and generate output aiMesh'es -void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) -{ - std::vector avOutMeshes; +void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) { + std::vector avOutMeshes; avOutMeshes.reserve(mScene->mMeshes.size() * 2); - unsigned int iFaceCnt = 0,num = 0; + unsigned int iFaceCnt = 0, num = 0; aiString name; // we need to split all meshes by their materials - for (std::vector::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { - std::unique_ptr< std::vector[] > aiSplit(new std::vector[mScene->mMaterials.size()]); + for (std::vector::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end(); ++i) { + std::unique_ptr[]> aiSplit(new std::vector[mScene->mMaterials.size()]); - name.length = ASSIMP_itoa10(name.data,num++); + name.length = ASSIMP_itoa10(name.data, num++); unsigned int iNum = 0; - for (std::vector::const_iterator a = (*i).mFaceMaterials.begin(); - a != (*i).mFaceMaterials.end();++a,++iNum) - { + for (std::vector::const_iterator a = (*i).mFaceMaterials.begin(); + a != (*i).mFaceMaterials.end(); ++a, ++iNum) { aiSplit[*a].push_back(iNum); } // now generate submeshes - for (unsigned int p = 0; p < mScene->mMaterials.size();++p) - { + for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) { if (aiSplit[p].empty()) { continue; } - aiMesh* meshOut = new aiMesh(); + aiMesh *meshOut = new aiMesh(); meshOut->mName = name; meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; @@ -389,36 +360,33 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) meshOut->mMaterialIndex = p; // use the color data as temporary storage - meshOut->mColors[0] = (aiColor4D*)(&*i); + meshOut->mColors[0] = (aiColor4D *)(&*i); avOutMeshes.push_back(meshOut); // convert vertices meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); - meshOut->mNumVertices = meshOut->mNumFaces*3; + meshOut->mNumVertices = meshOut->mNumFaces * 3; // allocate enough storage for faces meshOut->mFaces = new aiFace[meshOut->mNumFaces]; iFaceCnt += meshOut->mNumFaces; meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; - meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; - if ((*i).mTexCoords.size()) - { + meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; + if ((*i).mTexCoords.size()) { meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; } - for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) - { + for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) { unsigned int index = aiSplit[p][q]; - aiFace& face = meshOut->mFaces[q]; + aiFace &face = meshOut->mFaces[q]; face.mIndices = new unsigned int[3]; face.mNumIndices = 3; - for (unsigned int a = 0; a < 3;++a,++base) - { + for (unsigned int a = 0; a < 3; ++a, ++base) { unsigned int idx = (*i).mFaces[index].mIndices[a]; - meshOut->mVertices[base] = (*i).mPositions[idx]; - meshOut->mNormals [base] = (*i).mNormals[idx]; + meshOut->mVertices[base] = (*i).mPositions[idx]; + meshOut->mNormals[base] = (*i).mNormals[idx]; if ((*i).mTexCoords.size()) meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; @@ -431,8 +399,8 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) // Copy them to the output array pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); - pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); - for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { + pcOut->mMeshes = new aiMesh *[pcOut->mNumMeshes](); + for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) { pcOut->mMeshes[a] = avOutMeshes[a]; } @@ -444,47 +412,44 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) // ------------------------------------------------------------------------------------------------ // Add a node to the scenegraph and setup its final transformation -void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, - D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) -{ +void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut, + D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) { std::vector iArray; iArray.reserve(3); aiMatrix4x4 abs; // Find all meshes with the same name as the node - for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) - { - const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; - ai_assert(NULL != pcMesh); + for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) { + const D3DS::Mesh *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0]; + ai_assert(nullptr != pcMesh); if (pcIn->mName == pcMesh->mName) iArray.push_back(a); } - if (!iArray.empty()) - { + if (!iArray.empty()) { // The matrix should be identical for all meshes with the // same name. It HAS to be identical for all meshes ..... - D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); + D3DS::Mesh *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]); // Compute the inverse of the transformation matrix to move the // vertices back to their relative and local space aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; - mInv.Inverse();mInvTransposed.Transpose(); + mInv.Inverse(); + mInvTransposed.Transpose(); aiVector3D pivot = pcIn->vPivot; pcOut->mNumMeshes = (unsigned int)iArray.size(); pcOut->mMeshes = new unsigned int[iArray.size()]; - for (unsigned int i = 0;i < iArray.size();++i) { + for (unsigned int i = 0; i < iArray.size(); ++i) { const unsigned int iIndex = iArray[i]; - aiMesh* const mesh = pcSOut->mMeshes[iIndex]; + aiMesh *const mesh = pcSOut->mMeshes[iIndex]; - if (mesh->mColors[1] == NULL) - { + if (mesh->mColors[1] == nullptr) { // Transform the vertices back into their local space // fixme: consider computing normals after this, so we don't need to transform them - const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; - aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; + const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices; + aiVector3D *pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { *pvCurrent = mInv * (*pvCurrent); @@ -492,8 +457,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, } // Handle negative transformation matrix determinant -> invert vertex x - if (imesh->mMat.Determinant() < 0.0f) - { + if (imesh->mMat.Determinant() < 0.0f) { /* we *must* have normals */ for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { pvCurrent->x *= -1.f; @@ -503,17 +467,15 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, } // Handle pivot point - if (pivot.x || pivot.y || pivot.z) - { - for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { + if (pivot.x || pivot.y || pivot.z) { + for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { *pvCurrent -= pivot; } } - mesh->mColors[1] = (aiColor4D*)1; - } - else - mesh->mColors[1] = (aiColor4D*)1; + mesh->mColors[1] = (aiColor4D *)1; + } else + mesh->mColors[1] = (aiColor4D *)1; // Setup the mesh index pcOut->mMeshes[i] = iIndex; @@ -522,84 +484,81 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, // Setup the name of the node // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number - if (pcIn->mInstanceNumber > 1) - { + if (pcIn->mInstanceNumber > 1) { char tmp[12]; ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); std::string tempStr = pcIn->mName + "_inst_"; tempStr += tmp; pcOut->mName.Set(tempStr); - } - else + } else pcOut->mName.Set(pcIn->mName); // Now build the transformation matrix of the node // ROTATION - if (pcIn->aRotationKeys.size()){ + if (pcIn->aRotationKeys.size()) { // FIX to get to Assimp's quaternion conventions for (std::vector::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { (*it).mValue.w *= -1.f; } - pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); - } - else if (pcIn->aCameraRollKeys.size()) - { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), - pcOut->mTransformation); + pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix()); + } else if (pcIn->aCameraRollKeys.size()) { + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue), + pcOut->mTransformation); } // SCALING - aiMatrix4x4& m = pcOut->mTransformation; - if (pcIn->aScalingKeys.size()) - { - const aiVector3D& v = pcIn->aScalingKeys[0].mValue; - m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; - m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; - m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; + aiMatrix4x4 &m = pcOut->mTransformation; + if (pcIn->aScalingKeys.size()) { + const aiVector3D &v = pcIn->aScalingKeys[0].mValue; + m.a1 *= v.x; + m.b1 *= v.x; + m.c1 *= v.x; + m.a2 *= v.y; + m.b2 *= v.y; + m.c2 *= v.y; + m.a3 *= v.z; + m.b3 *= v.z; + m.c3 *= v.z; } // TRANSLATION - if (pcIn->aPositionKeys.size()) - { - const aiVector3D& v = pcIn->aPositionKeys[0].mValue; + if (pcIn->aPositionKeys.size()) { + const aiVector3D &v = pcIn->aPositionKeys[0].mValue; m.a4 += v.x; m.b4 += v.y; m.c4 += v.z; } // Generate animation channels for the node - if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || - pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || - pcIn->aTargetPositionKeys.size() > 1) - { - aiAnimation* anim = pcSOut->mAnimations[0]; + if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || + pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || + pcIn->aTargetPositionKeys.size() > 1) { + aiAnimation *anim = pcSOut->mAnimations[0]; ai_assert(nullptr != anim); - if (pcIn->aCameraRollKeys.size() > 1) - { - ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ..."); + if (pcIn->aCameraRollKeys.size() > 1) { + ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ..."); // Camera roll keys - in fact they're just rotations // around the camera's z axis. The angles are given // in degrees (and they're clockwise). pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); - for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) - { - aiQuatKey& q = pcIn->aRotationKeys[i]; - aiFloatKey& f = pcIn->aCameraRollKeys[i]; + for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) { + aiQuatKey &q = pcIn->aRotationKeys[i]; + aiFloatKey &f = pcIn->aCameraRollKeys[i]; - q.mTime = f.mTime; + q.mTime = f.mTime; // FIX to get to Assimp quaternion conventions - q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); + q.mValue = aiQuaternion(0.f, 0.f, AI_DEG_TO_RAD(/*-*/ f.mValue)); } } #if 0 if (pcIn->aTargetPositionKeys.size() > 1) { - ASSIMP_LOG_DEBUG("3DS: Converting target track ..."); + ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ..."); // Camera or spot light - need to convert the separate // target position channel to our representation @@ -639,102 +598,93 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, // Cameras or lights define their transformation in their parent node and in the // corresponding light or camera chunks. However, we read and process the latter // to to be able to return valid cameras/lights even if no scenegraph is given. - for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { + for (unsigned int n = 0; n < pcSOut->mNumCameras; ++n) { if (pcSOut->mCameras[n]->mName == pcOut->mName) { - pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); + pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f, 0.f, 1.f); } } - for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { + for (unsigned int n = 0; n < pcSOut->mNumLights; ++n) { if (pcSOut->mLights[n]->mName == pcOut->mName) { - pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); + pcSOut->mLights[n]->mDirection = aiVector3D(0.f, 0.f, 1.f); } } // Allocate a new node anim and setup its name - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + aiNodeAnim *nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); nda->mNodeName.Set(pcIn->mName); // POSITION keys - if (pcIn->aPositionKeys.size() > 0) - { + if (pcIn->aPositionKeys.size() > 0) { nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); + ::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0], + sizeof(aiVectorKey) * nda->mNumPositionKeys); } // ROTATION keys - if (pcIn->aRotationKeys.size() > 0) - { + if (pcIn->aRotationKeys.size() > 0) { nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; // Rotations are quaternion offsets aiQuaternion abs1; - for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) - { - const aiQuatKey& q = pcIn->aRotationKeys[n]; + for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) { + const aiQuatKey &q = pcIn->aRotationKeys[n]; abs1 = (n ? abs1 * q.mValue : q.mValue); - nda->mRotationKeys[n].mTime = q.mTime; + nda->mRotationKeys[n].mTime = q.mTime; nda->mRotationKeys[n].mValue = abs1.Normalize(); } } // SCALING keys - if (pcIn->aScalingKeys.size() > 0) - { + if (pcIn->aScalingKeys.size() > 0) { nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; - ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], - sizeof(aiVectorKey)*nda->mNumScalingKeys); + ::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0], + sizeof(aiVectorKey) * nda->mNumScalingKeys); } } // Allocate storage for children pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); - pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; + pcOut->mChildren = new aiNode *[pcIn->mChildren.size()]; // Recursively process all children const unsigned int size = static_cast(pcIn->mChildren.size()); - for (unsigned int i = 0; i < size;++i) - { + for (unsigned int i = 0; i < size; ++i) { pcOut->mChildren[i] = new aiNode(); pcOut->mChildren[i]->mParent = pcOut; - AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); + AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs); } } // ------------------------------------------------------------------------------------------------ // Find out how many node animation channels we'll have finally -void CountTracks(D3DS::Node* node, unsigned int& cnt) -{ +void CountTracks(D3DS::Node *node, unsigned int &cnt) { ////////////////////////////////////////////////////////////////////////////// // We will never generate more than one channel for a node, so // this is rather easy here. - if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || - node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || - node->aTargetPositionKeys.size() > 1) - { + if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || + node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || + node->aTargetPositionKeys.size() > 1) { ++cnt; // account for the additional channel for the camera/spotlight target position - if (node->aTargetPositionKeys.size() > 1)++cnt; + if (node->aTargetPositionKeys.size() > 1) ++cnt; } // Recursively process all children - for (unsigned int i = 0; i < node->mChildren.size();++i) - CountTracks(node->mChildren[i],cnt); + for (unsigned int i = 0; i < node->mChildren.size(); ++i) + CountTracks(node->mChildren[i], cnt); } // ------------------------------------------------------------------------------------------------ // Generate the output node graph -void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) -{ +void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) { pcOut->mRootNode = new aiNode(); - if (0 == mRootNode->mChildren.size()) - { + if (0 == mRootNode->mChildren.size()) { ////////////////////////////////////////////////////////////////////////////// // It seems the file is so messed up that it has not even a hierarchy. // generate a flat hiearachy which looks like this: @@ -748,29 +698,27 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) ASSIMP_LOG_WARN("No hierarchy information has been found in the file. "); pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + - static_cast(mScene->mCameras.size() + mScene->mLights.size()); + static_cast(mScene->mCameras.size() + mScene->mLights.size()); - pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; + pcOut->mRootNode->mChildren = new aiNode *[pcOut->mRootNode->mNumChildren]; pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); // Build dummy nodes for all meshes unsigned int a = 0; - for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) { + aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); pcNode->mParent = pcOut->mRootNode; pcNode->mMeshes = new unsigned int[1]; pcNode->mMeshes[0] = i; pcNode->mNumMeshes = 1; // Build a name for the node - pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i); + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u", i); } // Build dummy nodes for all cameras - for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) { + aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); pcNode->mParent = pcOut->mRootNode; // Build a name for the node @@ -778,75 +726,68 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) } // Build dummy nodes for all lights - for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) - { - aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); + for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) { + aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); pcNode->mParent = pcOut->mRootNode; // Build a name for the node pcNode->mName = mScene->mLights[i]->mName; } - } - else - { + } else { // First of all: find out how many scaling, rotation and translation // animation tracks we'll have afterwards unsigned int numChannel = 0; - CountTracks(mRootNode,numChannel); + CountTracks(mRootNode, numChannel); - if (numChannel) - { + if (numChannel) { // Allocate a primary animation channel pcOut->mNumAnimations = 1; - pcOut->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); + pcOut->mAnimations = new aiAnimation *[1]; + aiAnimation *anim = pcOut->mAnimations[0] = new aiAnimation(); anim->mName.Set("3DSMasterAnim"); // Allocate enough storage for all node animation channels, // but don't set the mNumChannels member - we'll use it to // index into the array - anim->mChannels = new aiNodeAnim*[numChannel]; + anim->mChannels = new aiNodeAnim *[numChannel]; } aiMatrix4x4 m; - AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); + AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode, m); } // We used the first and second vertex color set to store some temporary values so we need to cleanup here - for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) - { - pcOut->mMeshes[a]->mColors[0] = NULL; - pcOut->mMeshes[a]->mColors[1] = NULL; + for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) { + pcOut->mMeshes[a]->mColors[0] = nullptr; + pcOut->mMeshes[a]->mColors[1] = nullptr; } pcOut->mRootNode->mTransformation = aiMatrix4x4( - 1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f, - 0.f,-1.f,0.f,0.f, - 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; + 1.f, 0.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, -1.f, 0.f, 0.f, + 0.f, 0.f, 0.f, 1.f) * + pcOut->mRootNode->mTransformation; // If the root node is unnamed name it "<3DSRoot>" - if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || - (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) - { + if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") || + (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) { pcOut->mRootNode->mName.Set("<3DSRoot>"); } } // ------------------------------------------------------------------------------------------------ // Convert all meshes in the scene and generate the final output scene. -void Discreet3DSImporter::ConvertScene(aiScene* pcOut) -{ +void Discreet3DSImporter::ConvertScene(aiScene *pcOut) { // Allocate enough storage for all output materials pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); - pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; + pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials]; // ... and convert the 3DS materials to aiMaterial's - for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) - { - aiMaterial* pcNew = new aiMaterial(); - ConvertMaterial(mScene->mMaterials[i],*pcNew); + for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) { + aiMaterial *pcNew = new aiMaterial(); + ConvertMaterial(mScene->mMaterials[i], *pcNew); pcOut->mMaterials[i] = pcNew; } @@ -855,18 +796,16 @@ void Discreet3DSImporter::ConvertScene(aiScene* pcOut) // Now copy all light sources to the output scene pcOut->mNumLights = (unsigned int)mScene->mLights.size(); - if (pcOut->mNumLights) - { - pcOut->mLights = new aiLight*[pcOut->mNumLights]; - ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); + if (pcOut->mNumLights) { + pcOut->mLights = new aiLight *[pcOut->mNumLights]; + ::memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights); } // Now copy all cameras to the output scene pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); - if (pcOut->mNumCameras) - { - pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; - ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); + if (pcOut->mNumCameras) { + pcOut->mCameras = new aiCamera *[pcOut->mNumCameras]; + ::memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras); } } diff --git a/code/3DS/3DSExporter.cpp b/code/AssetLib/3DS/3DSExporter.cpp similarity index 74% rename from code/3DS/3DSExporter.cpp rename to code/AssetLib/3DS/3DSExporter.cpp index 403ca20a2..ad8e10afe 100644 --- a/code/3DS/3DSExporter.cpp +++ b/code/AssetLib/3DS/3DSExporter.cpp @@ -43,120 +43,117 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER -#include "3DS/3DSExporter.h" -#include "3DS/3DSLoader.h" -#include "3DS/3DSHelper.h" +#include "AssetLib/3DS/3DSExporter.h" +#include "AssetLib/3DS/3DSHelper.h" +#include "AssetLib/3DS/3DSLoader.h" #include "PostProcessing/SplitLargeMeshes.h" #include #include -#include #include #include +#include #include using namespace Assimp; -namespace Assimp { +namespace Assimp { using namespace D3DS; namespace { - ////////////////////////////////////////////////////////////////////////////////////// - // Scope utility to write a 3DS file chunk. - // - // Upon construction, the chunk header is written with the chunk type (flags) - // filled out, but the chunk size left empty. Upon destruction, the correct chunk - // size based on the then-position of the output stream cursor is filled in. - class ChunkWriter { - enum { - CHUNK_SIZE_NOT_SET = 0xdeadbeef - , SIZE_OFFSET = 2 - }; - public: - - ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type) - : writer(writer) - { - chunk_start_pos = writer.GetCurrentPos(); - writer.PutU2(chunk_type); - writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET); - } - - ~ChunkWriter() { - std::size_t head_pos = writer.GetCurrentPos(); - - ai_assert(head_pos > chunk_start_pos); - const std::size_t chunk_size = head_pos - chunk_start_pos; - - writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET); - writer.PutU4(static_cast(chunk_size)); - writer.SetCurrentPos(head_pos); - } - - private: - StreamWriterLE& writer; - std::size_t chunk_start_pos; +////////////////////////////////////////////////////////////////////////////////////// +// Scope utility to write a 3DS file chunk. +// +// Upon construction, the chunk header is written with the chunk type (flags) +// filled out, but the chunk size left empty. Upon destruction, the correct chunk +// size based on the then-position of the output stream cursor is filled in. +class ChunkWriter { + enum { + CHUNK_SIZE_NOT_SET = 0xdeadbeef, + SIZE_OFFSET = 2 }; - - // Return an unique name for a given |mesh| attached to |node| that - // preserves the mesh's given name if it has one. |index| is the index - // of the mesh in |aiScene::mMeshes|. - std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) { - static const std::string underscore = "_"; - char postfix[10] = {0}; - ASSIMP_itoa10(postfix, index); - - std::string result = node.mName.C_Str(); - if (mesh.mName.length > 0) { - result += underscore + mesh.mName.C_Str(); - } - return result + underscore + postfix; +public: + ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) : + writer(writer) { + chunk_start_pos = writer.GetCurrentPos(); + writer.PutU2(chunk_type); + writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET); } - // Return an unique name for a given |mat| with original position |index| - // in |aiScene::mMaterials|. The name preserves the original material - // name if possible. - std::string GetMaterialName(const aiMaterial& mat, unsigned int index) { - static const std::string underscore = "_"; - char postfix[10] = {0}; - ASSIMP_itoa10(postfix, index); + ~ChunkWriter() { + std::size_t head_pos = writer.GetCurrentPos(); - aiString mat_name; - if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) { - return mat_name.C_Str() + underscore + postfix; - } + ai_assert(head_pos > chunk_start_pos); + const std::size_t chunk_size = head_pos - chunk_start_pos; - return "Material" + underscore + postfix; + writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET); + writer.PutU4(static_cast(chunk_size)); + writer.SetCurrentPos(head_pos); } - // Collect world transformations for each node - void CollectTrafos(const aiNode* node, std::map& trafos) { - const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4(); - trafos[node] = parent * node->mTransformation; - for (unsigned int i = 0; i < node->mNumChildren; ++i) { - CollectTrafos(node->mChildren[i], trafos); - } +private: + StreamWriterLE &writer; + std::size_t chunk_start_pos; +}; + +// Return an unique name for a given |mesh| attached to |node| that +// preserves the mesh's given name if it has one. |index| is the index +// of the mesh in |aiScene::mMeshes|. +std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) { + static const std::string underscore = "_"; + char postfix[10] = { 0 }; + ASSIMP_itoa10(postfix, index); + + std::string result = node.mName.C_Str(); + if (mesh.mName.length > 0) { + result += underscore + mesh.mName.C_Str(); + } + return result + underscore + postfix; +} + +// Return an unique name for a given |mat| with original position |index| +// in |aiScene::mMaterials|. The name preserves the original material +// name if possible. +std::string GetMaterialName(const aiMaterial &mat, unsigned int index) { + static const std::string underscore = "_"; + char postfix[10] = { 0 }; + ASSIMP_itoa10(postfix, index); + + aiString mat_name; + if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) { + return mat_name.C_Str() + underscore + postfix; } - // Generate a flat list of the meshes (by index) assigned to each node - void CollectMeshes(const aiNode* node, std::multimap& meshes) { - for (unsigned int i = 0; i < node->mNumMeshes; ++i) { - meshes.insert(std::make_pair(node, node->mMeshes[i])); - } - for (unsigned int i = 0; i < node->mNumChildren; ++i) { - CollectMeshes(node->mChildren[i], meshes); - } + return "Material" + underscore + postfix; +} + +// Collect world transformations for each node +void CollectTrafos(const aiNode *node, std::map &trafos) { + const aiMatrix4x4 &parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4(); + trafos[node] = parent * node->mTransformation; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectTrafos(node->mChildren[i], trafos); } } +// Generate a flat list of the meshes (by index) assigned to each node +void CollectMeshes(const aiNode *node, std::multimap &meshes) { + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + meshes.insert(std::make_pair(node, node->mMeshes[i])); + } + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + CollectMeshes(node->mChildren[i], meshes); + } +} +} // namespace + // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp -void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) -{ - std::shared_ptr outfile (pIOSystem->Open(pFile, "wb")); - if(!outfile) { +void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { + std::shared_ptr outfile(pIOSystem->Open(pFile, "wb")); + if (!outfile) { throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile)); } @@ -167,8 +164,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen // SplitLargeMeshes can do this, but it requires the correct limit to be set // which is not possible with the current way of specifying preprocess steps // in |Exporter::ExportFormatEntry|. - aiScene* scenecopy_tmp; - SceneCombiner::CopyScene(&scenecopy_tmp,pScene); + aiScene *scenecopy_tmp; + SceneCombiner::CopyScene(&scenecopy_tmp, pScene); std::unique_ptr scenecopy(scenecopy_tmp); SplitLargeMeshesProcess_Triangle tri_splitter; @@ -186,10 +183,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen } // end of namespace Assimp // ------------------------------------------------------------------------------------------------ -Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr &outfile, const aiScene* scene) -: scene(scene) -, writer(outfile) -{ +Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr &outfile, const aiScene *scene) : + scene(scene), writer(outfile) { CollectTrafos(scene->mRootNode, trafos); CollectMeshes(scene->mRootNode, meshes); @@ -217,10 +212,8 @@ Discreet3DSExporter::~Discreet3DSExporter() { // empty } - // ------------------------------------------------------------------------------------------------ -int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level) -{ +int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) { // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec { ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO); @@ -237,7 +230,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling int16_t hierarchy_pos = static_cast(seq); if (sibling_level != -1) { - hierarchy_pos =(uint16_t) sibling_level; + hierarchy_pos = (uint16_t)sibling_level; } // Write the hierarchy position @@ -260,7 +253,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling const bool first_child = node.mNumChildren == 0 && i == 0; const unsigned int mesh_idx = node.mMeshes[i]; - const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + const aiMesh &mesh = *scene->mMeshes[mesh_idx]; ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO); { @@ -276,15 +269,14 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteMaterials() -{ +void Discreet3DSExporter::WriteMaterials() { for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); - const aiMaterial& mat = *scene->mMaterials[i]; + const aiMaterial &mat = *scene->mMaterials[i]; { ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME); - const std::string& name = GetMaterialName(mat, i); + const std::string &name = GetMaterialName(mat, i); WriteString(name); } @@ -298,12 +290,18 @@ void Discreet3DSExporter::WriteMaterials() ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); WriteColor(color); } - + if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) { ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); 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) { ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); WriteColor(color); @@ -314,7 +312,7 @@ void Discreet3DSExporter::WriteMaterials() ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING); Discreet3DS::shadetype3ds shading_mode_out; - switch(shading_mode) { + switch (shading_mode) { case aiShadingMode_Flat: case aiShadingMode_NoShading: shading_mode_out = Discreet3DS::Flat; @@ -341,8 +339,6 @@ void Discreet3DSExporter::WriteMaterials() writer.PutU2(static_cast(shading_mode_out)); } - - float f; if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) { ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS); WritePercentChunk(f); @@ -370,14 +366,13 @@ void Discreet3DSExporter::WriteMaterials() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags) -{ +void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) { aiString path; aiTextureMapMode map_mode[2] = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }; ai_real blend = 1.0; - if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) { + if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) { return; } @@ -400,8 +395,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type uint16_t val = 0; // WRAP if (map_mode[0] == aiTextureMapMode_Mirror) { val = 0x2; - } - else if (map_mode[0] == aiTextureMapMode_Decal) { + } else if (map_mode[0] == aiTextureMapMode_Decal) { val = 0x10; } writer.PutU2(val); @@ -410,8 +404,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteMeshes() -{ +void Discreet3DSExporter::WriteMeshes() { // NOTE: 3DS allows for instances. However: // i) not all importers support reading them // ii) instances are not as flexible as they are in assimp, in particular, @@ -423,25 +416,24 @@ void Discreet3DSExporter::WriteMeshes() // Furthermore, the TRIMESH is transformed into world space so that it will // appear correctly if importers don't read the scene hierarchy at all. for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) { - const aiNode& node = *(*it).first; + const aiNode &node = *(*it).first; const unsigned int mesh_idx = (*it).second; - const aiMesh& mesh = *scene->mMeshes[mesh_idx]; + const aiMesh &mesh = *scene->mMeshes[mesh_idx]; // This should not happen if the SLM step is correctly executed // before the scene is handed to the exporter ai_assert(mesh.mNumVertices <= 0xffff); ai_assert(mesh.mNumFaces <= 0xffff); - const aiMatrix4x4& trafo = trafos[&node]; + const aiMatrix4x4 &trafo = trafos[&node]; ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK); // Mesh name is tied to the node it is attached to so it can later be referenced - const std::string& name = GetMeshName(mesh, mesh_idx, node); + const std::string &name = GetMeshName(mesh, mesh_idx, node); WriteString(name); - // TRIMESH chunk ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH); @@ -452,7 +444,7 @@ void Discreet3DSExporter::WriteMeshes() const uint16_t count = static_cast(mesh.mNumVertices); writer.PutU2(count); for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { - const aiVector3D& v = trafo * mesh.mVertices[i]; + const aiVector3D &v = trafo * mesh.mVertices[i]; writer.PutF4(v.x); writer.PutF4(v.y); writer.PutF4(v.z); @@ -466,7 +458,7 @@ void Discreet3DSExporter::WriteMeshes() writer.PutU2(count); for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { - const aiVector3D& v = mesh.mTextureCoords[0][i]; + const aiVector3D &v = mesh.mTextureCoords[0][i]; writer.PutF4(v.x); writer.PutF4(v.y); } @@ -481,7 +473,7 @@ void Discreet3DSExporter::WriteMeshes() // Count triangles, discard lines and points uint16_t count = 0; for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { - const aiFace& f = mesh.mFaces[i]; + const aiFace &f = mesh.mFaces[i]; if (f.mNumIndices < 3) { continue; } @@ -492,7 +484,7 @@ void Discreet3DSExporter::WriteMeshes() writer.PutU2(count); for (unsigned int i = 0; i < mesh.mNumFaces; ++i) { - const aiFace& f = mesh.mFaces[i]; + const aiFace &f = mesh.mFaces[i]; if (f.mNumIndices < 3) { continue; } @@ -524,10 +516,9 @@ void Discreet3DSExporter::WriteMeshes() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) -{ +void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) { ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT); - const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); + const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); WriteString(name); // Because assimp splits meshes by material, only a single @@ -542,7 +533,7 @@ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteString(const std::string& s) { +void Discreet3DSExporter::WriteString(const std::string &s) { for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { writer.PutI1(*it); } @@ -550,7 +541,7 @@ void Discreet3DSExporter::WriteString(const std::string& s) { } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteString(const aiString& s) { +void Discreet3DSExporter::WriteString(const aiString &s) { for (std::size_t i = 0; i < s.length; ++i) { writer.PutI1(s.data[i]); } @@ -558,7 +549,7 @@ void Discreet3DSExporter::WriteString(const aiString& s) { } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteColor(const aiColor3D& color) { +void Discreet3DSExporter::WriteColor(const aiColor3D &color) { ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF); writer.PutF4(color.r); writer.PutF4(color.g); @@ -577,6 +568,5 @@ void Discreet3DSExporter::WritePercentChunk(double f) { writer.PutF8(f); } - #endif // ASSIMP_BUILD_NO_3DS_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/3DS/3DSExporter.h b/code/AssetLib/3DS/3DSExporter.h similarity index 100% rename from code/3DS/3DSExporter.h rename to code/AssetLib/3DS/3DSExporter.h diff --git a/code/3DS/3DSHelper.h b/code/AssetLib/3DS/3DSHelper.h similarity index 87% rename from code/3DS/3DSHelper.h rename to code/AssetLib/3DS/3DSHelper.h index 633cfbbf0..a2be07874 100644 --- a/code/3DS/3DSHelper.h +++ b/code/AssetLib/3DS/3DSHelper.h @@ -321,9 +321,10 @@ public: struct Face : public FaceWithSmoothingGroup { }; -#ifdef _WIN32 -# pragma warning(disable : 4315) -#endif +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4315) +#endif // _MSC_VER // --------------------------------------------------------------------------- /** Helper structure representing a texture */ @@ -412,6 +413,10 @@ struct Texture { #include +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + // --------------------------------------------------------------------------- /** Helper structure representing a 3ds material */ struct Material { @@ -441,30 +446,50 @@ struct Material { // empty } - Material(const Material &other) = default; - Material &operator=(const Material &other) = default; + Material(const Material &other) : + mName(other.mName), + mDiffuse(other.mDiffuse), + mSpecularExponent(other.mSpecularExponent), + mShininessStrength(other.mShininessStrength), + mSpecular(other.mSpecular), + mAmbient(other.mAmbient), + mShading(other.mShading), + mTransparency(other.mTransparency), + sTexDiffuse(other.sTexDiffuse), + sTexOpacity(other.sTexOpacity), + sTexSpecular(other.sTexSpecular), + sTexReflective(other.sTexReflective), + sTexBump(other.sTexBump), + sTexEmissive(other.sTexEmissive), + sTexShininess(other.sTexShininess), + mBumpHeight(other.mBumpHeight), + mEmissive(other.mEmissive), + sTexAmbient(other.sTexAmbient), + mTwoSided(other.mTwoSided) { + // empty + } //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it - Material(Material &&other) AI_NO_EXCEPT - : mName(std::move(other.mName)), - mDiffuse(std::move(other.mDiffuse)), - mSpecularExponent(std::move(other.mSpecularExponent)), - mShininessStrength(std::move(other.mShininessStrength)), - mSpecular(std::move(other.mSpecular)), - mAmbient(std::move(other.mAmbient)), - mShading(std::move(other.mShading)), - mTransparency(std::move(other.mTransparency)), - sTexDiffuse(std::move(other.sTexDiffuse)), - sTexOpacity(std::move(other.sTexOpacity)), - sTexSpecular(std::move(other.sTexSpecular)), - sTexReflective(std::move(other.sTexReflective)), - sTexBump(std::move(other.sTexBump)), - sTexEmissive(std::move(other.sTexEmissive)), - sTexShininess(std::move(other.sTexShininess)), - mBumpHeight(std::move(other.mBumpHeight)), - mEmissive(std::move(other.mEmissive)), - sTexAmbient(std::move(other.sTexAmbient)), - mTwoSided(std::move(other.mTwoSided)) { + Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)), + mDiffuse(std::move(other.mDiffuse)), + mSpecularExponent(std::move(other.mSpecularExponent)), + mShininessStrength(std::move(other.mShininessStrength)), + mSpecular(std::move(other.mSpecular)), + mAmbient(std::move(other.mAmbient)), + mShading(std::move(other.mShading)), + mTransparency(std::move(other.mTransparency)), + sTexDiffuse(std::move(other.sTexDiffuse)), + sTexOpacity(std::move(other.sTexOpacity)), + sTexSpecular(std::move(other.sTexSpecular)), + sTexReflective(std::move(other.sTexReflective)), + sTexBump(std::move(other.sTexBump)), + sTexEmissive(std::move(other.sTexEmissive)), + sTexShininess(std::move(other.sTexShininess)), + mBumpHeight(std::move(other.mBumpHeight)), + mEmissive(std::move(other.mEmissive)), + sTexAmbient(std::move(other.sTexAmbient)), + mTwoSided(std::move(other.mTwoSided)) { + // empty } Material &operator=(Material &&other) AI_NO_EXCEPT { @@ -593,7 +618,12 @@ struct Node { Node() = delete; explicit Node(const std::string &name) : - mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) { + mParent(nullptr), + mName(name), + mInstanceNumber(0), + mHierarchyPos(0), + mHierarchyIndex(0), + mInstanceCount(1) { aRotationKeys.reserve(20); aPositionKeys.reserve(20); aScalingKeys.reserve(20); diff --git a/code/3DS/3DSLoader.cpp b/code/AssetLib/3DS/3DSLoader.cpp similarity index 68% rename from code/3DS/3DSLoader.cpp rename to code/AssetLib/3DS/3DSLoader.cpp index 0b4a93a2b..4c24394fb 100644 --- a/code/3DS/3DSLoader.cpp +++ b/code/AssetLib/3DS/3DSLoader.cpp @@ -5,8 +5,6 @@ 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, @@ -47,15 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * http://www.the-labs.com/Blender/3DS-details.html */ - #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER #include "3DSLoader.h" -#include +#include +#include #include #include -#include -#include +#include using namespace Assimp; @@ -69,27 +66,25 @@ static const aiImporterDesc desc = { 0, 0, 0, - "3ds prj" + "3ds prj" }; - // ------------------------------------------------------------------------------------------------ // Begins a new parsing block // - Reads the current chunk and validates it // - computes its length -#define ASSIMP_3DS_BEGIN_CHUNK() \ - while (true) { \ - if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \ - return; \ - } \ - Discreet3DS::Chunk chunk; \ - ReadChunk(&chunk); \ - int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ - if(chunkSize <= 0) \ - continue; \ - const unsigned int oldReadLimit = stream->SetReadLimit( \ - stream->GetCurrentPos() + chunkSize); \ - +#define ASSIMP_3DS_BEGIN_CHUNK() \ + while (true) { \ + if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) { \ + return; \ + } \ + Discreet3DS::Chunk chunk; \ + ReadChunk(&chunk); \ + int chunkSize = chunk.Size - sizeof(Discreet3DS::Chunk); \ + if (chunkSize <= 0) \ + continue; \ + const unsigned int oldReadLimit = stream->SetReadLimit( \ + stream->GetCurrentPos() + chunkSize); // ------------------------------------------------------------------------------------------------ // End a parsing block @@ -103,15 +98,8 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -Discreet3DSImporter::Discreet3DSImporter() -: stream() -, mLastNodeIndex() -, mCurrentNode() -, mRootNode() -, mScene() -, mMasterScale() -, bHasBG() -, bIsPrj() { +Discreet3DSImporter::Discreet3DSImporter() : + stream(), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() { // empty } @@ -123,9 +111,9 @@ Discreet3DSImporter::~Discreet3DSImporter() { // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { +bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { std::string extension = GetExtension(pFile); - if(extension == "3ds" || extension == "prj") { + if (extension == "3ds" || extension == "prj") { return true; } @@ -134,35 +122,32 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle token[0] = 0x4d4d; token[1] = 0x3dc2; //token[2] = 0x3daa; - return CheckMagicToken(pIOHandler,pFile,token,2,0,2); + return CheckMagicToken(pIOHandler, pFile, token, 2, 0, 2); } return false; } // ------------------------------------------------------------------------------------------------ // Loader registry entry -const aiImporterDesc* Discreet3DSImporter::GetInfo () const -{ +const aiImporterDesc *Discreet3DSImporter::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties -void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/) -{ +void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) { // nothing to be done for the moment } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void Discreet3DSImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ - StreamReaderLE theStream(pIOHandler->Open(pFile,"rb")); +void Discreet3DSImporter::InternReadFile(const std::string &pFile, + aiScene *pScene, IOSystem *pIOHandler) { + StreamReaderLE theStream(pIOHandler->Open(pFile, "rb")); // We should have at least one chunk 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; @@ -172,16 +157,16 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, // Initialize members D3DS::Node _rootNode("UNNAMED"); - mLastNodeIndex = -1; - mCurrentNode = &_rootNode; - mRootNode = mCurrentNode; - mRootNode->mHierarchyPos = -1; + mLastNodeIndex = -1; + mCurrentNode = &_rootNode; + mRootNode = mCurrentNode; + mRootNode->mHierarchyPos = -1; mRootNode->mHierarchyIndex = -1; - mRootNode->mParent = NULL; - mMasterScale = 1.0f; - mBackgroundImage = ""; - bHasBG = false; - bIsPrj = false; + mRootNode->mParent = nullptr; + mMasterScale = 1.0f; + mBackgroundImage = ""; + bHasBG = false; + bIsPrj = false; // Parse the file ParseMainChunk(); @@ -192,15 +177,15 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, // vectors from the smoothing groups we read from the // file. for (auto &mesh : mScene->mMeshes) { - if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { - throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile); + if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { + throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile); } CheckIndices(mesh); - MakeUnique (mesh); + MakeUnique(mesh); ComputeNormalsWithSmoothingsGroups(mesh); } - // Replace all occurences of the default material with a + // Replace all occurrences of the default material with a // valid material. Generate it if no material containing // DEFAULT in its name has been found in the file ReplaceDefaultMaterial(); @@ -227,26 +212,26 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, // ------------------------------------------------------------------------------------------------ // Applies a master-scaling factor to the imported scene -void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene) -{ +void Discreet3DSImporter::ApplyMasterScale(aiScene *pScene) { // There are some 3DS files with a zero scaling factor - if (!mMasterScale)mMasterScale = 1.0f; - else mMasterScale = 1.0f / mMasterScale; + if (!mMasterScale) + mMasterScale = 1.0f; + else + mMasterScale = 1.0f / mMasterScale; // Construct an uniform scaling matrix and multiply with it pScene->mRootNode->mTransformation *= aiMatrix4x4( - mMasterScale,0.0f, 0.0f, 0.0f, - 0.0f, mMasterScale,0.0f, 0.0f, - 0.0f, 0.0f, mMasterScale,0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + mMasterScale, 0.0f, 0.0f, 0.0f, + 0.0f, mMasterScale, 0.0f, 0.0f, + 0.0f, 0.0f, mMasterScale, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); // Check whether a scaling track is assigned to the root node. } // ------------------------------------------------------------------------------------------------ // Reads a new chunk from the file -void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut) -{ +void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk *pcOut) { ai_assert(pcOut != nullptr); pcOut->Flag = stream->GetI2(); @@ -263,24 +248,21 @@ void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut) // ------------------------------------------------------------------------------------------------ // Skip a chunk -void Discreet3DSImporter::SkipChunk() -{ +void Discreet3DSImporter::SkipChunk() { Discreet3DS::Chunk psChunk; ReadChunk(&psChunk); - stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk)); + stream->IncPtr(psChunk.Size - sizeof(Discreet3DS::Chunk)); return; } // ------------------------------------------------------------------------------------------------ // Process the primary chunk of the file -void Discreet3DSImporter::ParseMainChunk() -{ +void Discreet3DSImporter::ParseMainChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_PRJ: bIsPrj = true; @@ -295,13 +277,11 @@ void Discreet3DSImporter::ParseMainChunk() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseEditorChunk() -{ +void Discreet3DSImporter::ParseEditorChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_OBJMESH: ParseObjectChunk(); @@ -314,36 +294,31 @@ void Discreet3DSImporter::ParseEditorChunk() ParseKeyframeChunk(); break; - case Discreet3DS::CHUNK_VERSION: - { + case Discreet3DS::CHUNK_VERSION: { // print the version number char buff[10]; - ASSIMP_itoa10(buff,stream->GetI2()); + ASSIMP_itoa10(buff, stream->GetI2()); ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff); - } - break; + } break; }; ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseObjectChunk() -{ +void Discreet3DSImporter::ParseObjectChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_OBJBLOCK: - { + switch (chunk.Flag) { + case Discreet3DS::CHUNK_OBJBLOCK: { unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); + const char *sz = (const char *)stream->GetPtr(); // Get the name of the geometry object - while (stream->GetI1())++cnt; - ParseChunk(sz,cnt); - } - break; + while (stream->GetI1()) + ++cnt; + ParseChunk(sz, cnt); + } break; case Discreet3DS::CHUNK_MAT_MATERIAL: @@ -356,25 +331,23 @@ void Discreet3DSImporter::ParseObjectChunk() // This is the ambient base color of the scene. // We add it to the ambient color of all materials - ParseColorChunk(&mClrAmbient,true); - if (is_qnan(mClrAmbient.r)) - { + ParseColorChunk(&mClrAmbient, true); + if (is_qnan(mClrAmbient.r)) { // We failed to read the ambient base color. ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color"); mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; } break; - case Discreet3DS::CHUNK_BIT_MAP: - { + case Discreet3DS::CHUNK_BIT_MAP: { // Specifies the background image. The string should already be // properly 0 terminated but we need to be sure unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1())++cnt; - mBackgroundImage = std::string(sz,cnt); - } - break; + const char *sz = (const char *)stream->GetPtr(); + while (stream->GetI1()) + ++cnt; + mBackgroundImage = std::string(sz, cnt); + } break; case Discreet3DS::CHUNK_BIT_MAP_EXISTS: bHasBG = true; @@ -389,8 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) -{ +void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) { ASSIMP_3DS_BEGIN_CHUNK(); // IMPLEMENTATION NOTE; @@ -399,22 +371,18 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) // to to be able to return valid cameras/lights even if no scenegraph is given. // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_TRIMESH: - { + switch (chunk.Flag) { + case Discreet3DS::CHUNK_TRIMESH: { // this starts a new triangle mesh mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num))); // Read mesh chunks ParseMeshChunk(); - } - break; + } break; - case Discreet3DS::CHUNK_LIGHT: - { + case Discreet3DS::CHUNK_LIGHT: { // This starts a new light - aiLight* light = new aiLight(); + aiLight *light = new aiLight(); mScene->mLights.push_back(light); light->mName.Set(std::string(name, num)); @@ -424,7 +392,7 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) light->mPosition.y = stream->GetF4(); light->mPosition.z = stream->GetF4(); - light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); + light->mColorDiffuse = aiColor3D(1.f, 1.f, 1.f); // Now check for further subchunks if (!bIsPrj) /* fixme */ @@ -433,19 +401,17 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) // The specular light color is identical the the diffuse light color. The ambient light color // is equal to the ambient base color of the whole scene. light->mColorSpecular = light->mColorDiffuse; - light->mColorAmbient = mClrAmbient; + light->mColorAmbient = mClrAmbient; - if (light->mType == aiLightSource_UNDEFINED) - { + if (light->mType == aiLightSource_UNDEFINED) { // It must be a point light light->mType = aiLightSource_POINT; - }} - break; + } + } break; - case Discreet3DS::CHUNK_CAMERA: - { + case Discreet3DS::CHUNK_CAMERA: { // This starts a new camera - aiCamera* camera = new aiCamera(); + aiCamera *camera = new aiCamera(); mScene->mCameras.push_back(camera); camera->mName.Set(std::string(name, num)); @@ -463,40 +429,38 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) // There are some files with lookat == position. Don't know why or whether it's ok or not. ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector"); - camera->mLookAt = aiVector3D(0.0,1.0,0.0); + camera->mLookAt = aiVector3D(0.0, 1.0, 0.0); - } - else camera->mLookAt /= len; + } else + camera->mLookAt /= len; // And finally - the camera rotation angle, in counter clockwise direction - const ai_real angle = AI_DEG_TO_RAD( stream->GetF4() ); - aiQuaternion quat(camera->mLookAt,angle); - camera->mUp = quat.GetMatrix() * aiVector3D(0.0,1.0,0.0); + const ai_real angle = AI_DEG_TO_RAD(stream->GetF4()); + aiQuaternion quat(camera->mLookAt, angle); + camera->mUp = quat.GetMatrix() * aiVector3D(0.0, 1.0, 0.0); // Read the lense angle - camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() ); - if (camera->mHorizontalFOV < 0.001f) { + camera->mHorizontalFOV = AI_DEG_TO_RAD(stream->GetF4()); + if (camera->mHorizontalFOV < 0.001f) { camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); } // Now check for further subchunks if (!bIsPrj) /* fixme */ { ParseCameraChunk(); - }} - break; + } + } break; }; ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseLightChunk() -{ +void Discreet3DSImporter::ParseLightChunk() { ASSIMP_3DS_BEGIN_CHUNK(); - aiLight* light = mScene->mLights.back(); + aiLight *light = mScene->mLights.back(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_DL_SPOTLIGHT: // Now we can be sure that the light is a spot light light->mType = aiLightSource_SPOT; @@ -508,10 +472,10 @@ void Discreet3DSImporter::ParseLightChunk() light->mDirection.Normalize(); // Now the hotspot and falloff angles - in degrees - light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() ); + light->mAngleInnerCone = AI_DEG_TO_RAD(stream->GetF4()); // FIX: the falloff angle is just an offset - light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() ); + light->mAngleOuterCone = light->mAngleInnerCone + AI_DEG_TO_RAD(stream->GetF4()); break; // intensity multiplier @@ -537,18 +501,16 @@ void Discreet3DSImporter::ParseLightChunk() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseCameraChunk() -{ +void Discreet3DSImporter::ParseCameraChunk() { ASSIMP_3DS_BEGIN_CHUNK(); - aiCamera* camera = mScene->mCameras.back(); + aiCamera *camera = mScene->mCameras.back(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { // near and far clip plane case Discreet3DS::CHUNK_CAM_RANGES: camera->mClipPlaneNear = stream->GetF4(); - camera->mClipPlaneFar = stream->GetF4(); + camera->mClipPlaneFar = stream->GetF4(); break; } @@ -556,13 +518,11 @@ void Discreet3DSImporter::ParseCameraChunk() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseKeyframeChunk() -{ +void Discreet3DSImporter::ParseKeyframeChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_TRACKCAMTGT: case Discreet3DS::CHUNK_TRACKSPOTL: case Discreet3DS::CHUNK_TRACKCAMERA: @@ -580,31 +540,30 @@ void Discreet3DSImporter::ParseKeyframeChunk() // ------------------------------------------------------------------------------------------------ // Little helper function for ParseHierarchyChunk -void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent) -{ +void Discreet3DSImporter::InverseNodeSearch(D3DS::Node *pcNode, D3DS::Node *pcCurrent) { if (!pcCurrent) { mRootNode->push_back(pcNode); return; } - if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { - if(pcCurrent->mParent) { + if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) { + if (pcCurrent->mParent) { pcCurrent->mParent->push_back(pcNode); - } - else pcCurrent->push_back(pcNode); + } else + pcCurrent->push_back(pcNode); return; } - return InverseNodeSearch(pcNode,pcCurrent->mParent); + return InverseNodeSearch(pcNode, pcCurrent->mParent); } // ------------------------------------------------------------------------------------------------ // Find a node with a specific name in the import hierarchy -D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) { +D3DS::Node *FindNode(D3DS::Node *root, const std::string &name) { if (root->mName == name) { return root; } - for (std::vector::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { + for (std::vector::iterator it = root->mChildren.begin(); it != root->mChildren.end(); ++it) { D3DS::Node *nd = FindNode(*it, name); if (nullptr != nd) { return nd; @@ -617,15 +576,13 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) { // ------------------------------------------------------------------------------------------------ // Binary predicate for std::unique() template -bool KeyUniqueCompare(const T& first, const T& second) -{ +bool KeyUniqueCompare(const T &first, const T &second) { return first.mTime == second.mTime; } // ------------------------------------------------------------------------------------------------ // Skip some additional import data. -void Discreet3DSImporter::SkipTCBInfo() -{ +void Discreet3DSImporter::SkipTCBInfo() { unsigned int flags = stream->GetI2(); if (!flags) { @@ -655,73 +612,68 @@ void Discreet3DSImporter::SkipTCBInfo() // ------------------------------------------------------------------------------------------------ // Read hierarchy and keyframe info -void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) -{ +void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_TRACKOBJNAME: // This is the name of the object to which the track applies. The chunk also // defines the position of this object in the hierarchy. { - // First of all: get the name of the object - unsigned int cnt = 0; - const char* sz = (const char*)stream->GetPtr(); + // First of all: get the name of the object + unsigned int cnt = 0; + const char *sz = (const char *)stream->GetPtr(); - while (stream->GetI1())++cnt; - std::string name = std::string(sz,cnt); + while (stream->GetI1()) + ++cnt; + std::string name = std::string(sz, cnt); - // Now find out whether we have this node already (target animation channels - // are stored with a separate object ID) - D3DS::Node* pcNode = FindNode(mRootNode,name); - int instanceNumber = 1; + // Now find out whether we have this node already (target animation channels + // are stored with a separate object ID) + D3DS::Node *pcNode = FindNode(mRootNode, name); + int instanceNumber = 1; - if ( pcNode) - { - // if the source is not a CHUNK_TRACKINFO block it won't be an object instance - if (parent != Discreet3DS::CHUNK_TRACKINFO) - { - mCurrentNode = pcNode; - break; + if (pcNode) { + // if the source is not a CHUNK_TRACKINFO block it won't be an object instance + if (parent != Discreet3DS::CHUNK_TRACKINFO) { + mCurrentNode = pcNode; + break; + } + pcNode->mInstanceCount++; + instanceNumber = pcNode->mInstanceCount; } - pcNode->mInstanceCount++; - instanceNumber = pcNode->mInstanceCount; - } - pcNode = new D3DS::Node(name); - pcNode->mInstanceNumber = instanceNumber; + pcNode = new D3DS::Node(name); + pcNode->mInstanceNumber = instanceNumber; - // There are two unknown values which we can safely ignore - stream->IncPtr(4); + // There are two unknown values which we can safely ignore + stream->IncPtr(4); - // Now read the hierarchy position of the object - uint16_t hierarchy = stream->GetI2() + 1; - pcNode->mHierarchyPos = hierarchy; - pcNode->mHierarchyIndex = mLastNodeIndex; + // Now read the hierarchy position of the object + uint16_t hierarchy = stream->GetI2() + 1; + pcNode->mHierarchyPos = hierarchy; + pcNode->mHierarchyIndex = mLastNodeIndex; - // And find a proper position in the graph for it - if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { + // And find a proper position in the graph for it + if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy) { - // add to the parent of the last touched node - mCurrentNode->mParent->push_back(pcNode); - mLastNodeIndex++; - } - else if(hierarchy >= mLastNodeIndex) { + // add to the parent of the last touched node + mCurrentNode->mParent->push_back(pcNode); + mLastNodeIndex++; + } else if (hierarchy >= mLastNodeIndex) { - // place it at the current position in the hierarchy - mCurrentNode->push_back(pcNode); - mLastNodeIndex = hierarchy; - } - else { - // need to go back to the specified position in the hierarchy. - InverseNodeSearch(pcNode,mCurrentNode); - mLastNodeIndex++; - } - // Make this node the current node - mCurrentNode = pcNode; + // place it at the current position in the hierarchy + mCurrentNode->push_back(pcNode); + mLastNodeIndex = hierarchy; + } else { + // need to go back to the specified position in the hierarchy. + InverseNodeSearch(pcNode, mCurrentNode); + mLastNodeIndex++; + } + // Make this node the current node + mCurrentNode = pcNode; } break; @@ -729,11 +681,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) // This is the "real" name of a $$$DUMMY object { - const char* sz = (const char*) stream->GetPtr(); - while (stream->GetI1()); + const char *sz = (const char *)stream->GetPtr(); + while (stream->GetI1()) + ; // If object name is DUMMY, take this one instead - if (mCurrentNode->mName == "$$$DUMMY") { + if (mCurrentNode->mName == "$$$DUMMY") { mCurrentNode->mName = std::string(sz); break; } @@ -742,8 +695,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) case Discreet3DS::CHUNK_TRACKPIVOT: - if ( Discreet3DS::CHUNK_TRACKINFO != parent) - { + if (Discreet3DS::CHUNK_TRACKINFO != parent) { ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object"); break; } @@ -754,25 +706,23 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) mCurrentNode->vPivot.z = stream->GetF4(); break; - // //////////////////////////////////////////////////////////////////// // POSITION KEYFRAME - case Discreet3DS::CHUNK_TRACKPOS: - { + case Discreet3DS::CHUNK_TRACKPOS: { stream->IncPtr(10); const unsigned int numFrames = stream->GetI4(); bool sortKeys = false; // This could also be meant as the target position for // (targeted) lights and cameras - std::vector* l; - if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { - l = & mCurrentNode->aTargetPositionKeys; - } - else l = & mCurrentNode->aPositionKeys; + std::vector *l; + if (Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) { + l = &mCurrentNode->aTargetPositionKeys; + } else + l = &mCurrentNode->aPositionKeys; l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { + for (unsigned int i = 0; i < numFrames; ++i) { const unsigned int fidx = stream->GetI4(); // Setup a new position key @@ -793,29 +743,29 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) } // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} + if (sortKeys) { + std::stable_sort(l->begin(), l->end()); + l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare), l->end()); + } + } - break; + break; // //////////////////////////////////////////////////////////////////// // CAMERA ROLL KEYFRAME - case Discreet3DS::CHUNK_TRACKROLL: - { + case Discreet3DS::CHUNK_TRACKROLL: { // roll keys are accepted for cameras only - if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { + if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object"); break; } bool sortKeys = false; - std::vector* l = &mCurrentNode->aCameraRollKeys; + std::vector *l = &mCurrentNode->aCameraRollKeys; stream->IncPtr(10); const unsigned int numFrames = stream->GetI4(); l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { + for (unsigned int i = 0; i < numFrames; ++i) { const unsigned int fidx = stream->GetI4(); // Setup a new position key @@ -835,35 +785,30 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) } // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; - + if (sortKeys) { + std::stable_sort(l->begin(), l->end()); + l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare), l->end()); + } + } break; // //////////////////////////////////////////////////////////////////// // CAMERA FOV KEYFRAME - case Discreet3DS::CHUNK_TRACKFOV: - { - ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. " - "This is not supported"); - } - break; - + case Discreet3DS::CHUNK_TRACKFOV: { + ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. " + "This is not supported"); + } break; // //////////////////////////////////////////////////////////////////// // ROTATION KEYFRAME - case Discreet3DS::CHUNK_TRACKROTATE: - { + case Discreet3DS::CHUNK_TRACKROTATE: { stream->IncPtr(10); const unsigned int numFrames = stream->GetI4(); bool sortKeys = false; - std::vector* l = &mCurrentNode->aRotationKeys; + std::vector *l = &mCurrentNode->aRotationKeys; l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { + for (unsigned int i = 0; i < numFrames; ++i) { const unsigned int fidx = stream->GetI4(); SkipTCBInfo(); @@ -881,7 +826,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) axis.y = 1.f; // Construct a rotation quaternion from the axis-angle pair - v.mValue = aiQuaternion(axis,rad); + v.mValue = aiQuaternion(axis, rad); // Check whether we'll need to sort the keys if (!l->empty() && v.mTime <= l->back().mTime) @@ -891,25 +836,24 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) l->push_back(v); } // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; + if (sortKeys) { + std::stable_sort(l->begin(), l->end()); + l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare), l->end()); + } + } break; // //////////////////////////////////////////////////////////////////// // SCALING KEYFRAME - case Discreet3DS::CHUNK_TRACKSCALE: - { + case Discreet3DS::CHUNK_TRACKSCALE: { stream->IncPtr(10); const unsigned int numFrames = stream->GetI2(); stream->IncPtr(2); bool sortKeys = false; - std::vector* l = &mCurrentNode->aScalingKeys; + std::vector *l = &mCurrentNode->aScalingKeys; l->reserve(numFrames); - for (unsigned int i = 0; i < numFrames;++i) { + for (unsigned int i = 0; i < numFrames; ++i) { const unsigned int fidx = stream->GetI4(); SkipTCBInfo(); @@ -934,11 +878,11 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) l->push_back(v); } // Sort all keys with ascending time values and remove duplicates? - if (sortKeys) { - std::stable_sort(l->begin(),l->end()); - l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare), l->end() ); - }} - break; + if (sortKeys) { + std::stable_sort(l->begin(), l->end()); + l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare), l->end()); + } + } break; }; ASSIMP_3DS_END_CHUNK(); @@ -946,92 +890,85 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) // ------------------------------------------------------------------------------------------------ // Read a face chunk - it contains smoothing groups and material assignments -void Discreet3DSImporter::ParseFaceChunk() -{ +void Discreet3DSImporter::ParseFaceChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); + D3DS::Mesh &mMesh = mScene->mMeshes.back(); // Get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_SMOOLIST: - { + switch (chunk.Flag) { + case Discreet3DS::CHUNK_SMOOLIST: { // This is the list of smoothing groups - a bitfield for every face. // Up to 32 smoothing groups assigned to a single face. - unsigned int num = chunkSize/4, m = 0; - if (num > mMesh.mFaces.size()) { + unsigned int num = chunkSize / 4, m = 0; + if (num > mMesh.mFaces.size()) { throw DeadlyImportError("3DS: More smoothing groups than faces"); } - for (std::vector::iterator i = mMesh.mFaces.begin(); m != num;++i, ++m) { + for (std::vector::iterator i = mMesh.mFaces.begin(); m != num; ++i, ++m) { // nth bit is set for nth smoothing group (*i).iSmoothGroup = stream->GetI4(); - }} - break; + } + } break; - case Discreet3DS::CHUNK_FACEMAT: - { + case Discreet3DS::CHUNK_FACEMAT: { // at fist an asciiz with the material name - const char* sz = (const char*)stream->GetPtr(); - while (stream->GetI1()); + const char *sz = (const char *)stream->GetPtr(); + while (stream->GetI1()) + ; // find the index of the material unsigned int idx = 0xcdcdcdcd, cnt = 0; - for (std::vector::const_iterator i = mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt) { + for (std::vector::const_iterator i = mScene->mMaterials.begin(); i != mScene->mMaterials.end(); ++i, ++cnt) { // use case independent comparisons. hopefully it will work. if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) { idx = cnt; break; } } - if (0xcdcdcdcd == idx) { - ASSIMP_LOG_ERROR_F( "3DS: Unknown material: ", sz); + if (0xcdcdcdcd == idx) { + ASSIMP_LOG_ERROR_F("3DS: Unknown material: ", sz); } // Now continue and read all material indices cnt = (uint16_t)stream->GetI2(); - for (unsigned int i = 0; i < cnt;++i) { + for (unsigned int i = 0; i < cnt; ++i) { unsigned int fidx = (uint16_t)stream->GetI2(); // check range - if (fidx >= mMesh.mFaceMaterials.size()) { + if (fidx >= mMesh.mFaceMaterials.size()) { ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list"); - } - else mMesh.mFaceMaterials[fidx] = idx; - }} - break; + } else + mMesh.mFaceMaterials[fidx] = idx; + } + } break; }; ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a mesh chunk. Here's the actual mesh data -void Discreet3DSImporter::ParseMeshChunk() -{ +void Discreet3DSImporter::ParseMeshChunk() { ASSIMP_3DS_BEGIN_CHUNK(); // Get the mesh we're currently working on - D3DS::Mesh& mMesh = mScene->mMeshes.back(); + D3DS::Mesh &mMesh = mScene->mMeshes.back(); // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_VERTLIST: - { + switch (chunk.Flag) { + case Discreet3DS::CHUNK_VERTLIST: { // This is the list of all vertices in the current mesh int num = (int)(uint16_t)stream->GetI2(); mMesh.mPositions.reserve(num); - while (num-- > 0) { + while (num-- > 0) { aiVector3D v; v.x = stream->GetF4(); v.y = stream->GetF4(); v.z = stream->GetF4(); mMesh.mPositions.push_back(v); - }} - break; - case Discreet3DS::CHUNK_TRMATRIX: - { + } + } break; + case Discreet3DS::CHUNK_TRMATRIX: { // This is the RLEATIVE transformation matrix of the current mesh. Vertices are // pretransformed by this matrix wonder. mMesh.mMat.a1 = stream->GetF4(); @@ -1046,31 +983,28 @@ void Discreet3DSImporter::ParseMeshChunk() mMesh.mMat.a4 = stream->GetF4(); mMesh.mMat.b4 = stream->GetF4(); mMesh.mMat.c4 = stream->GetF4(); - } - break; + } break; - case Discreet3DS::CHUNK_MAPLIST: - { + case Discreet3DS::CHUNK_MAPLIST: { // This is the list of all UV coords in the current mesh int num = (int)(uint16_t)stream->GetI2(); mMesh.mTexCoords.reserve(num); - while (num-- > 0) { + while (num-- > 0) { aiVector3D v; v.x = stream->GetF4(); v.y = stream->GetF4(); mMesh.mTexCoords.push_back(v); - }} - break; + } + } break; - case Discreet3DS::CHUNK_FACELIST: - { + case Discreet3DS::CHUNK_FACELIST: { // This is the list of all faces in the current mesh int num = (int)(uint16_t)stream->GetI2(); mMesh.mFaces.reserve(num); - while (num-- > 0) { + while (num-- > 0) { // 3DS faces are ALWAYS triangles mMesh.mFaces.push_back(D3DS::Face()); - D3DS::Face& sFace = mMesh.mFaces.back(); + D3DS::Face &sFace = mMesh.mFaces.back(); sFace.mIndices[0] = (uint16_t)stream->GetI2(); sFace.mIndices[1] = (uint16_t)stream->GetI2(); @@ -1081,103 +1015,93 @@ void Discreet3DSImporter::ParseMeshChunk() // Resize the material array (0xcdcdcdcd marks the default material; so if a face is // not referenced by a material, $$DEFAULT will be assigned to it) - mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd); + mMesh.mFaceMaterials.resize(mMesh.mFaces.size(), 0xcdcdcdcd); // Larger 3DS files could have multiple FACE chunks here - chunkSize = stream->GetRemainingSizeToLimit(); - if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) ) + chunkSize = (int)stream->GetRemainingSizeToLimit(); + if (chunkSize > (int)sizeof(Discreet3DS::Chunk)) ParseFaceChunk(); - } - break; + } break; }; ASSIMP_3DS_END_CHUNK(); } // ------------------------------------------------------------------------------------------------ // Read a 3DS material chunk -void Discreet3DSImporter::ParseMaterialChunk() -{ +void Discreet3DSImporter::ParseMaterialChunk() { ASSIMP_3DS_BEGIN_CHUNK(); - switch (chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_MAT_MATNAME: - { + { // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); + const char *sz = (const char *)stream->GetPtr(); unsigned int cnt = 0; while (stream->GetI1()) ++cnt; - if (!cnt) { + if (!cnt) { // This may not be, we use the default name instead ASSIMP_LOG_ERROR("3DS: Empty material name"); - } - else mScene->mMaterials.back().mName = std::string(sz,cnt); - } - break; + } else + mScene->mMaterials.back().mName = std::string(sz, cnt); + } break; - case Discreet3DS::CHUNK_MAT_DIFFUSE: - { + case Discreet3DS::CHUNK_MAT_DIFFUSE: { // This is the diffuse material color - aiColor3D* pc = &mScene->mMaterials.back().mDiffuse; + aiColor3D *pc = &mScene->mMaterials.back().mDiffuse; ParseColorChunk(pc); if (is_qnan(pc->r)) { // color chunk is invalid. Simply ignore it ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk"); pc->r = pc->g = pc->b = 1.0f; - }} - break; + } + } break; - case Discreet3DS::CHUNK_MAT_SPECULAR: - { + case Discreet3DS::CHUNK_MAT_SPECULAR: { // This is the specular material color - aiColor3D* pc = &mScene->mMaterials.back().mSpecular; + aiColor3D *pc = &mScene->mMaterials.back().mSpecular; ParseColorChunk(pc); if (is_qnan(pc->r)) { // color chunk is invalid. Simply ignore it ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk"); pc->r = pc->g = pc->b = 1.0f; - }} - break; + } + } break; - case Discreet3DS::CHUNK_MAT_AMBIENT: - { + case Discreet3DS::CHUNK_MAT_AMBIENT: { // This is the ambient material color - aiColor3D* pc = &mScene->mMaterials.back().mAmbient; + aiColor3D *pc = &mScene->mMaterials.back().mAmbient; ParseColorChunk(pc); if (is_qnan(pc->r)) { // color chunk is invalid. Simply ignore it ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk"); pc->r = pc->g = pc->b = 0.0f; - }} - break; + } + } break; - case Discreet3DS::CHUNK_MAT_SELF_ILLUM: - { + case Discreet3DS::CHUNK_MAT_SELF_ILLUM: { // This is the emissive material color - aiColor3D* pc = &mScene->mMaterials.back().mEmissive; + aiColor3D *pc = &mScene->mMaterials.back().mEmissive; ParseColorChunk(pc); if (is_qnan(pc->r)) { // color chunk is invalid. Simply ignore it ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk"); pc->r = pc->g = pc->b = 0.0f; - }} - break; - - case Discreet3DS::CHUNK_MAT_TRANSPARENCY: - { - // This is the material's transparency - ai_real* pcf = &mScene->mMaterials.back().mTransparency; - *pcf = ParsePercentageChunk(); - - // NOTE: transparency, not opacity - if (is_qnan(*pcf)) - *pcf = ai_real( 1.0 ); - else - *pcf = ai_real( 1.0 ) - *pcf * (ai_real)0xFFFF / ai_real( 100.0 ); } - break; + } break; + + case Discreet3DS::CHUNK_MAT_TRANSPARENCY: { + // This is the material's transparency + ai_real *pcf = &mScene->mMaterials.back().mTransparency; + *pcf = ParsePercentageChunk(); + + // NOTE: transparency, not opacity + if (is_qnan(*pcf)) + *pcf = ai_real(1.0); + else + *pcf = ai_real(1.0) - *pcf * (ai_real)0xFFFF / ai_real(100.0); + } break; case Discreet3DS::CHUNK_MAT_SHADING: // This is the material shading mode @@ -1189,37 +1113,32 @@ void Discreet3DSImporter::ParseMaterialChunk() mScene->mMaterials.back().mTwoSided = true; break; - case Discreet3DS::CHUNK_MAT_SHININESS: - { // This is the shininess of the material - ai_real* pcf = &mScene->mMaterials.back().mSpecularExponent; + case Discreet3DS::CHUNK_MAT_SHININESS: { // This is the shininess of the material + ai_real *pcf = &mScene->mMaterials.back().mSpecularExponent; *pcf = ParsePercentageChunk(); if (is_qnan(*pcf)) *pcf = 0.0; - else *pcf *= (ai_real)0xFFFF; - } - break; + else + *pcf *= (ai_real)0xFFFF; + } break; - case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: - { // This is the shininess strength of the material - ai_real* pcf = &mScene->mMaterials.back().mShininessStrength; - *pcf = ParsePercentageChunk(); - if (is_qnan(*pcf)) - *pcf = ai_real( 0.0 ); - else - *pcf *= (ai_real)0xffff / ai_real( 100.0 ); - } - break; + case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: { // This is the shininess strength of the material + ai_real *pcf = &mScene->mMaterials.back().mShininessStrength; + *pcf = ParsePercentageChunk(); + if (is_qnan(*pcf)) + *pcf = ai_real(0.0); + else + *pcf *= (ai_real)0xffff / ai_real(100.0); + } break; - case Discreet3DS::CHUNK_MAT_SELF_ILPCT: - { // This is the self illumination strength of the material - ai_real f = ParsePercentageChunk(); - if (is_qnan(f)) - f = ai_real( 0.0 ); - else - f *= (ai_real)0xFFFF / ai_real( 100.0 ); - mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f); - } - break; + case Discreet3DS::CHUNK_MAT_SELF_ILPCT: { // This is the self illumination strength of the material + ai_real f = ParsePercentageChunk(); + if (is_qnan(f)) + f = ai_real(0.0); + else + f *= (ai_real)0xFFFF / ai_real(100.0); + mScene->mMaterials.back().mEmissive = aiColor3D(f, f, f); + } break; // Parse texture chunks case Discreet3DS::CHUNK_MAT_TEXTURE: @@ -1255,28 +1174,23 @@ void Discreet3DSImporter::ParseMaterialChunk() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) -{ +void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture *pcOut) { ASSIMP_3DS_BEGIN_CHUNK(); // get chunk type - switch (chunk.Flag) - { - case Discreet3DS::CHUNK_MAPFILE: - { + switch (chunk.Flag) { + case Discreet3DS::CHUNK_MAPFILE: { // The material name string is already zero-terminated, but we need to be sure ... - const char* sz = (const char*)stream->GetPtr(); + const char *sz = (const char *)stream->GetPtr(); unsigned int cnt = 0; while (stream->GetI1()) ++cnt; - pcOut->mMapName = std::string(sz,cnt); - } - break; - + pcOut->mMapName = std::string(sz, cnt); + } break; case Discreet3DS::CHUNK_PERCENTD: // Manually parse the blend factor - pcOut->mTextureBlend = ai_real( stream->GetF8() ); + pcOut->mTextureBlend = ai_real(stream->GetF8()); break; case Discreet3DS::CHUNK_PERCENTF: @@ -1286,14 +1200,13 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) case Discreet3DS::CHUNK_PERCENTW: // Manually parse the blend factor - pcOut->mTextureBlend = (ai_real)((uint16_t)stream->GetI2()) / ai_real( 100.0 ); + pcOut->mTextureBlend = (ai_real)((uint16_t)stream->GetI2()) / ai_real(100.0); break; case Discreet3DS::CHUNK_MAT_MAP_USCALE: // Texture coordinate scaling in the U direction pcOut->mScaleU = stream->GetF4(); - if (0.0f == pcOut->mScaleU) - { + if (0.0f == pcOut->mScaleU) { ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1."); pcOut->mScaleU = 1.0f; } @@ -1301,8 +1214,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) case Discreet3DS::CHUNK_MAT_MAP_VSCALE: // Texture coordinate scaling in the V direction pcOut->mScaleV = stream->GetF4(); - if (0.0f == pcOut->mScaleV) - { + if (0.0f == pcOut->mScaleV) { ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1."); pcOut->mScaleV = 1.0f; } @@ -1320,11 +1232,10 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) case Discreet3DS::CHUNK_MAT_MAP_ANG: // Texture coordinate rotation, CCW in DEGREES - pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); + pcOut->mRotation = -AI_DEG_TO_RAD(stream->GetF4()); break; - case Discreet3DS::CHUNK_MAT_MAP_TILING: - { + case Discreet3DS::CHUNK_MAT_MAP_TILING: { const uint16_t iFlags = stream->GetI2(); // Get the mapping mode (for both axes) @@ -1335,9 +1246,9 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) pcOut->mMapMode = aiTextureMapMode_Decal; // wrapping in all remaining cases - else pcOut->mMapMode = aiTextureMapMode_Wrap; - } - break; + else + pcOut->mMapMode = aiTextureMapMode_Wrap; + } break; }; ASSIMP_3DS_END_CHUNK(); @@ -1360,13 +1271,12 @@ ai_real Discreet3DSImporter::ParsePercentageChunk() { // ------------------------------------------------------------------------------------------------ // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color -void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) -{ - ai_assert(out != NULL); +void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) { + ai_assert(out != nullptr); // error return value const ai_real qnan = get_qnan(); - static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); + static const aiColor3D clrError = aiColor3D(qnan, qnan, qnan); Discreet3DS::Chunk chunk; ReadChunk(&chunk); @@ -1375,13 +1285,12 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) bool bGamma = false; // Get the type of the chunk - switch(chunk.Flag) - { + switch (chunk.Flag) { case Discreet3DS::CHUNK_LINRGBF: bGamma = true; case Discreet3DS::CHUNK_RGBF: - if (sizeof(float) * 3 > diff) { + if (sizeof(float) * 3 > diff) { *out = clrError; return; } @@ -1392,18 +1301,16 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) case Discreet3DS::CHUNK_LINRGBB: bGamma = true; - case Discreet3DS::CHUNK_RGBB: - { - if ( sizeof( char ) * 3 > diff ) { - *out = clrError; - return; - } - const ai_real invVal = ai_real( 1.0 ) / ai_real( 255.0 ); - out->r = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal; - out->g = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal; - out->b = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal; + case Discreet3DS::CHUNK_RGBB: { + if (sizeof(char) * 3 > diff) { + *out = clrError; + return; } - break; + const ai_real invVal = ai_real(1.0) / ai_real(255.0); + out->r = (ai_real)(uint8_t)stream->GetI1() * invVal; + out->g = (ai_real)(uint8_t)stream->GetI1() * invVal; + out->b = (ai_real)(uint8_t)stream->GetI1() * invVal; + } break; // Percentage chunks are accepted, too. case Discreet3DS::CHUNK_PERCENTF: @@ -1416,7 +1323,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) case Discreet3DS::CHUNK_PERCENTW: if (acceptPercent && 1 <= diff) { - out->g = out->b = out->r = (ai_real)(uint8_t)stream->GetI1() / ai_real( 255.0 ); + out->g = out->b = out->r = (ai_real)(uint8_t)stream->GetI1() / ai_real(255.0); break; } *out = clrError; @@ -1425,7 +1332,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) default: stream->IncPtr(diff); // Skip unknown chunks, hope this won't cause any problems. - return ParseColorChunk(out,acceptPercent); + return ParseColorChunk(out, acceptPercent); }; (void)bGamma; } diff --git a/code/3DS/3DSLoader.h b/code/AssetLib/3DS/3DSLoader.h similarity index 99% rename from code/3DS/3DSLoader.h rename to code/AssetLib/3DS/3DSLoader.h index 9181294b3..68a48e7a2 100644 --- a/code/3DS/3DSLoader.h +++ b/code/AssetLib/3DS/3DSLoader.h @@ -65,15 +65,11 @@ using namespace D3DS; // --------------------------------------------------------------------------------- /** Importer class for 3D Studio r3 and r4 3DS files */ -class Discreet3DSImporter : public BaseImporter -{ +class Discreet3DSImporter : public BaseImporter { public: - Discreet3DSImporter(); ~Discreet3DSImporter(); -public: - // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. diff --git a/code/3MF/3MFXmlTags.h b/code/AssetLib/3MF/3MFXmlTags.h similarity index 96% rename from code/3MF/3MFXmlTags.h rename to code/AssetLib/3MF/3MFXmlTags.h index 3f1fc01ed..49e19c658 100644 --- a/code/3MF/3MFXmlTags.h +++ b/code/AssetLib/3MF/3MFXmlTags.h @@ -4,7 +4,6 @@ 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, @@ -56,6 +55,8 @@ namespace XmlTag { static const std::string resources = "resources"; static const std::string object = "object"; static const std::string mesh = "mesh"; + static const std::string components = "components"; + static const std::string component = "component"; static const std::string vertices = "vertices"; static const std::string vertex = "vertex"; static const std::string triangles = "triangles"; @@ -68,6 +69,7 @@ namespace XmlTag { static const std::string v3 = "v3"; static const std::string id = "id"; static const std::string pid = "pid"; + static const std::string pindex = "pindex"; static const std::string p1 = "p1"; static const std::string name = "name"; static const std::string type = "type"; diff --git a/code/3MF/D3MFExporter.cpp b/code/AssetLib/3MF/D3MFExporter.cpp similarity index 54% rename from code/3MF/D3MFExporter.cpp rename to code/AssetLib/3MF/D3MFExporter.cpp index 092b947e9..b4e5d515c 100644 --- a/code/3MF/D3MFExporter.cpp +++ b/code/AssetLib/3MF/D3MFExporter.cpp @@ -4,7 +4,6 @@ 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, @@ -44,81 +43,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "D3MFExporter.h" -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include "3MFXmlTags.h" #include "D3MFOpcPackage.h" #ifdef ASSIMP_USE_HUNTER -# include +#include #else -# include +#include #endif namespace Assimp { -void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) { - if ( nullptr == pIOSystem ) { - throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) ); +void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { + if (nullptr == pIOSystem) { + throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile)); } - D3MF::D3MFExporter myExporter( pFile, pScene ); - if ( myExporter.validate() ) { - if ( pIOSystem->Exists( pFile ) ) { - if ( !pIOSystem->DeleteFile( pFile ) ) { - throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) ); + D3MF::D3MFExporter myExporter(pFile, pScene); + if (myExporter.validate()) { + if (pIOSystem->Exists(pFile)) { + if (!pIOSystem->DeleteFile(pFile)) { + throw DeadlyExportError("File exists, cannot override : " + std::string(pFile)); } } bool ok = myExporter.exportArchive(pFile); - if ( !ok ) { - throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) ); + if (!ok) { + throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile)); } } } namespace D3MF { -D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene ) -: mArchiveName( pFile ) -, m_zipArchive( nullptr ) -, mScene( pScene ) -, mModelOutput() -, mRelOutput() -, mContentOutput() -, mBuildItems() -, mRelations() { +D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) : + mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() { // empty } D3MFExporter::~D3MFExporter() { - for ( size_t i = 0; i < mRelations.size(); ++i ) { - delete mRelations[ i ]; + for (size_t i = 0; i < mRelations.size(); ++i) { + delete mRelations[i]; } mRelations.clear(); } bool D3MFExporter::validate() { - if ( mArchiveName.empty() ) { + if (mArchiveName.empty()) { return false; } - if ( nullptr == mScene ) { + if (nullptr == mScene) { return false; } return true; } -bool D3MFExporter::exportArchive( const char *file ) { - bool ok( true ); +bool D3MFExporter::exportArchive(const char *file) { + bool ok(true); - m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' ); - if ( nullptr == m_zipArchive ) { + m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + if (nullptr == m_zipArchive) { return false; } @@ -126,7 +118,7 @@ bool D3MFExporter::exportArchive( const char *file ) { ok |= export3DModel(); ok |= exportRelations(); - zip_close( m_zipArchive ); + zip_close(m_zipArchive); m_zipArchive = nullptr; return ok; @@ -145,7 +137,7 @@ bool D3MFExporter::exportContentTypes() { mContentOutput << std::endl; mContentOutput << ""; mContentOutput << std::endl; - exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE ); + zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE); return true; } @@ -157,20 +149,20 @@ bool D3MFExporter::exportRelations() { mRelOutput << std::endl; mRelOutput << ""; - for ( size_t i = 0; i < mRelations.size(); ++i ) { - if ( mRelations[ i ]->target[ 0 ] == '/' ) { - mRelOutput << "target << "\" "; + for (size_t i = 0; i < mRelations.size(); ++i) { + if (mRelations[i]->target[0] == '/') { + mRelOutput << "target << "\" "; } else { - mRelOutput << "target << "\" "; + mRelOutput << "target << "\" "; } mRelOutput << "Id=\"" << mRelations[i]->id << "\" "; - mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />"; + mRelOutput << "Type=\"" << mRelations[i]->type << "\" />"; mRelOutput << std::endl; } mRelOutput << ""; mRelOutput << std::endl; - writeRelInfoToFile( "_rels", ".rels" ); + zipRelInfo("_rels", ".rels"); mRelOutput.flush(); return true; @@ -181,8 +173,8 @@ bool D3MFExporter::export3DModel() { writeHeader(); mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\"" - << "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">" - << std::endl; + << " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">" + << std::endl; mModelOutput << "<" << XmlTag::resources << ">"; mModelOutput << std::endl; @@ -192,7 +184,6 @@ bool D3MFExporter::export3DModel() { writeObjects(); - mModelOutput << ""; mModelOutput << std::endl; writeBuild(); @@ -203,36 +194,36 @@ bool D3MFExporter::export3DModel() { info->id = "rel0"; info->target = "/3D/3DModel.model"; info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; - mRelations.push_back( info ); + mRelations.push_back(info); - writeModelToArchive( "3D", "3DModel.model" ); + zipModel("3D", "3DModel.model"); mModelOutput.flush(); return true; } void D3MFExporter::writeHeader() { - mModelOutput << ""; + mModelOutput << ""; mModelOutput << std::endl; } void D3MFExporter::writeMetaData() { - if ( nullptr == mScene->mMetaData ) { + if (nullptr == mScene->mMetaData) { return; } - const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties ); - if ( 0 == numMetaEntries ) { + const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties); + if (0 == numMetaEntries) { return; } - const aiString *key = nullptr; + const aiString *key = nullptr; const aiMetadataEntry *entry(nullptr); - for ( size_t i = 0; i < numMetaEntries; ++i ) { - mScene->mMetaData->Get( i, key, entry ); - std::string k( key->C_Str() ); + for (size_t i = 0; i < numMetaEntries; ++i) { + mScene->mMetaData->Get(i, key, entry); + std::string k(key->C_Str()); aiString value; - mScene->mMetaData->Get( k, value ); + mScene->mMetaData->Get(k, value); mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">"; mModelOutput << value.C_Str(); mModelOutput << "" << std::endl; @@ -241,103 +232,114 @@ void D3MFExporter::writeMetaData() { void D3MFExporter::writeBaseMaterials() { mModelOutput << "\n"; - std::string strName, hexDiffuseColor , tmp; - for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) { - aiMaterial *mat = mScene->mMaterials[ i ]; + std::string strName, hexDiffuseColor, tmp; + for (size_t i = 0; i < mScene->mNumMaterials; ++i) { + aiMaterial *mat = mScene->mMaterials[i]; aiString name; - if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) { - strName = "basemat_" + to_string( i ); + if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) { + strName = "basemat_" + to_string(i); } else { strName = name.C_Str(); } aiColor4D color; - if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) { + if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) { hexDiffuseColor.clear(); tmp.clear(); - hexDiffuseColor = "#"; - - tmp = DecimalToHexa( (ai_real) color.r ); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.g); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.b); - hexDiffuseColor += tmp; - tmp = DecimalToHexa((ai_real)color.a); - hexDiffuseColor += tmp; + // rgbs % + if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) { + + hexDiffuseColor = Rgba2Hex( + (int)((ai_real)color.r) * 255, + (int)((ai_real)color.g) * 255, + (int)((ai_real)color.b) * 255, + (int)((ai_real)color.a) * 255, + true); + + } else { + hexDiffuseColor = "#"; + tmp = DecimalToHexa((ai_real)color.r); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.g); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.b); + hexDiffuseColor += tmp; + tmp = DecimalToHexa((ai_real)color.a); + hexDiffuseColor += tmp; + } } else { hexDiffuseColor = "#FFFFFFFF"; } - mModelOutput << "\n"; + mModelOutput << "\n"; } mModelOutput << "\n"; } void D3MFExporter::writeObjects() { - if ( nullptr == mScene->mRootNode ) { + if (nullptr == mScene->mRootNode) { return; } aiNode *root = mScene->mRootNode; - for ( unsigned int i = 0; i < root->mNumChildren; ++i ) { - aiNode *currentNode( root->mChildren[ i ] ); - if ( nullptr == currentNode ) { + for (unsigned int i = 0; i < root->mNumChildren; ++i) { + aiNode *currentNode(root->mChildren[i]); + if (nullptr == currentNode) { continue; } - mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">"; + mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">"; mModelOutput << std::endl; - for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) { - aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ]; - if ( nullptr == currentMesh ) { + for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) { + aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]]; + if (nullptr == currentMesh) { continue; } - writeMesh( currentMesh ); + writeMesh(currentMesh); } - mBuildItems.push_back( i ); + mBuildItems.push_back(i); mModelOutput << ""; mModelOutput << std::endl; } } -void D3MFExporter::writeMesh( aiMesh *mesh ) { - if ( nullptr == mesh ) { +void D3MFExporter::writeMesh(aiMesh *mesh) { + if (nullptr == mesh) { return; } mModelOutput << "<" << XmlTag::mesh << ">" << std::endl; mModelOutput << "<" << XmlTag::vertices << ">" << std::endl; - for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) { - writeVertex( mesh->mVertices[ i ] ); + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + writeVertex(mesh->mVertices[i]); } mModelOutput << "" << std::endl; - const unsigned int matIdx( mesh->mMaterialIndex ); + const unsigned int matIdx(mesh->mMaterialIndex); - writeFaces( mesh, matIdx ); + writeFaces(mesh, matIdx); mModelOutput << "" << std::endl; } -void D3MFExporter::writeVertex( const aiVector3D &pos ) { +void D3MFExporter::writeVertex(const aiVector3D &pos) { mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />"; mModelOutput << std::endl; } -void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) { - if ( nullptr == mesh ) { +void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) { + if (nullptr == mesh) { return; } - if ( !mesh->HasFaces() ) { + if (!mesh->HasFaces()) { return; } mModelOutput << "<" << XmlTag::triangles << ">" << std::endl; - for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) { - aiFace ¤tFace = mesh->mFaces[ i ]; - mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\"" - << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] - << "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />"; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace ¤tFace = mesh->mFaces[i]; + mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\"" + << currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2] + << "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />"; mModelOutput << std::endl; } mModelOutput << ""; @@ -347,53 +349,37 @@ void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) { void D3MFExporter::writeBuild() { mModelOutput << "<" << XmlTag::build << ">" << std::endl; - for ( size_t i = 0; i < mBuildItems.size(); ++i ) { - mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>"; + for (size_t i = 0; i < mBuildItems.size(); ++i) { + mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>"; mModelOutput << std::endl; } mModelOutput << ""; mModelOutput << std::endl; } -void D3MFExporter::exportContentTyp( const std::string &filename ) { - if ( nullptr == m_zipArchive ) { - throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." ); - } - const std::string entry = filename; - zip_entry_open( m_zipArchive, entry.c_str() ); - - const std::string &exportTxt( mContentOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); - - zip_entry_close( m_zipArchive ); +void D3MFExporter::zipContentType(const std::string &filename) { + addFileInZip(filename, mContentOutput.str()); } -void D3MFExporter::writeModelToArchive( const std::string &folder, const std::string &modelName ) { - if ( nullptr == m_zipArchive ) { - throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." ); - } +void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) { const std::string entry = folder + "/" + modelName; - zip_entry_open( m_zipArchive, entry.c_str() ); - - const std::string &exportTxt( mModelOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); - - zip_entry_close( m_zipArchive ); + addFileInZip(entry, mModelOutput.str()); } -void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) { - if ( nullptr == m_zipArchive ) { - throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." ); - } +void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) { const std::string entry = folder + "/" + relName; - zip_entry_open( m_zipArchive, entry.c_str() ); - - const std::string &exportTxt( mRelOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); - - zip_entry_close( m_zipArchive ); + addFileInZip(entry, mRelOutput.str()); } +void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) { + if (nullptr == m_zipArchive) { + throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); + } + + zip_entry_open(m_zipArchive, entry.c_str()); + zip_entry_write(m_zipArchive, content.c_str(), content.size()); + zip_entry_close(m_zipArchive); +} } // Namespace D3MF } // Namespace Assimp diff --git a/code/3MF/D3MFExporter.h b/code/AssetLib/3MF/D3MFExporter.h similarity index 90% rename from code/3MF/D3MFExporter.h rename to code/AssetLib/3MF/D3MFExporter.h index 6a447236b..abde3cea3 100644 --- a/code/3MF/D3MFExporter.h +++ b/code/AssetLib/3MF/D3MFExporter.h @@ -4,7 +4,6 @@ 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, @@ -83,9 +82,12 @@ protected: void writeVertex( const aiVector3D &pos ); void writeFaces( aiMesh *mesh, unsigned int matIdx ); void writeBuild(); - void exportContentTyp( const std::string &filename ); - void writeModelToArchive( const std::string &folder, const std::string &modelName ); - void writeRelInfoToFile( const std::string &folder, const std::string &relName ); + + // Zip the data + void zipContentType( const std::string &filename ); + void zipModel( const std::string &folder, const std::string &modelName ); + void zipRelInfo( const std::string &folder, const std::string &relName ); + void addFileInZip( const std::string &entry, const std::string &content ); private: std::string mArchiveName; diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp new file mode 100644 index 000000000..66b2c965b --- /dev/null +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -0,0 +1,626 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER + +#include "D3MFImporter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "3MFXmlTags.h" +#include "D3MFOpcPackage.h" +#include + +#include + +namespace Assimp { +namespace D3MF { + +enum class ResourceType { + RT_Object, + RT_BaseMaterials, + RT_Unknown +}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...) + +class Resource +{ +public: + Resource(int id) : + mId(id) {} + + virtual ~Resource() {} + + int mId; + + virtual ResourceType getType() { + return ResourceType::RT_Unknown; + } +}; + +class BaseMaterials : public Resource { +public: + BaseMaterials(int id) : + Resource(id), + mMaterials(), + mMaterialIndex() {} + + std::vector mMaterials; + std::vector mMaterialIndex; + + virtual ResourceType getType() { + return ResourceType::RT_BaseMaterials; + } +}; + +struct Component { + int mObjectId; + aiMatrix4x4 mTransformation; +}; + +class Object : public Resource { +public: + std::vector mMeshes; + std::vector mMeshIndex; + std::vector mComponents; + std::string mName; + + Object(int id) : + Resource(id), + mName (std::string("Object_") + to_string(id)){} + + virtual ResourceType getType() { + return ResourceType::RT_Object; + } +}; + + +class XmlSerializer { +public: + + XmlSerializer(XmlParser *xmlParser) : + mResourcesDictionnary(), + mMaterialCount(0), + mMeshCount(0), + mXmlParser(xmlParser) { + // empty + } + + ~XmlSerializer() { + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + delete it->second; + } + } + + void ImportXml(aiScene *scene) { + if (nullptr == scene) { + return; + } + + scene->mRootNode = new aiNode("3MF"); + + XmlNode node = mXmlParser->getRootNode().child("model"); + if (node.empty()) { + return; + } + XmlNode resNode = node.child("resources"); + for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tNodeName = currentNode.name(); + if (currentNodeName == D3MF::XmlTag::object) { + ReadObject(currentNode);; + } else if (currentNodeName == D3MF::XmlTag::basematerials) { + ReadBaseMaterials(currentNode); + } else if (currentNodeName == D3MF::XmlTag::meta) { + ReadMetadata(currentNode); + } + } + + XmlNode buildNode = node.child("build"); + for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tNodeName = currentNode.name(); + if (currentNodeName == D3MF::XmlTag::item) { + int objectId = -1; + std::string transformationMatrixStr; + aiMatrix4x4 transformationMatrix; + getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId); + bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr); + + auto it = mResourcesDictionnary.find(objectId); + if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) { + Object *obj = static_cast(it->second); + if (hasTransform) { + transformationMatrix = parseTransformMatrix(transformationMatrixStr); + } + + addObjectToNode(scene->mRootNode, obj, transformationMatrix); + } + } + } + + + // import the metadata + if (!mMetaData.empty()) { + const size_t numMeta(mMetaData.size()); + scene->mMetaData = aiMetadata::Alloc(static_cast(numMeta)); + for (size_t i = 0; i < numMeta; ++i) { + aiString val(mMetaData[i].value); + scene->mMetaData->Set(static_cast(i), mMetaData[i].name, val); + } + } + + // import the meshes + scene->mNumMeshes = static_cast(mMeshCount); + if (scene->mNumMeshes != 0) { + scene->mMeshes = new aiMesh *[scene->mNumMeshes](); + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + if (it->second->getType() == ResourceType::RT_Object) { + Object *obj = static_cast(it->second); + for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) { + scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i]; + } + } + } + } + + + // import the materials + scene->mNumMaterials = static_cast(mMaterialCount); + if (scene->mNumMaterials != 0) { + scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + if (it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *baseMaterials = static_cast(it->second); + for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) { + scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i]; + } + } + } + } + } + +private: + + void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) { + aiNode *sceneNode = new aiNode(obj->mName); + sceneNode->mNumMeshes = static_cast(obj->mMeshes.size()); + sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes]; + std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes); + + sceneNode->mTransformation = nodeTransform; + + parent->addChildren(1, &sceneNode); + + for (size_t i = 0; i < obj->mComponents.size(); ++i) { + Component c = obj->mComponents[i]; + auto it = mResourcesDictionnary.find(c.mObjectId); + if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) { + addObjectToNode(sceneNode, static_cast(it->second), c.mTransformation); + } + + } + } + + bool getNodeAttribute(const XmlNode& node, const std::string& attribute, std::string& value) { + pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str()); + if (!objectAttribute.empty()) { + value = objectAttribute.as_string(); + return true; + } else { + return false; + } + } + + bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) { + std::string strValue; + bool ret = getNodeAttribute(node, attribute, strValue); + if (ret) { + value = std::atoi(strValue.c_str()); + return true; + } else { + return false; + } + } + + aiMatrix4x4 parseTransformMatrix(std::string matrixStr) { + // split the string + std::vector numbers; + std::string currentNumber; + for (size_t i = 0; i < matrixStr.size(); ++i) { + const char c = matrixStr[i]; + if (c == ' ') { + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); + currentNumber.clear(); + } + } else { + currentNumber.push_back(c); + } + } + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); + } + + aiMatrix4x4 transformMatrix; + transformMatrix.a1 = numbers[0]; + transformMatrix.b1 = numbers[1]; + transformMatrix.c1 = numbers[2]; + transformMatrix.d1 = 0; + + transformMatrix.a2 = numbers[3]; + transformMatrix.b2 = numbers[4]; + transformMatrix.c2 = numbers[5]; + transformMatrix.d2 = 0; + + transformMatrix.a3 = numbers[6]; + transformMatrix.b3 = numbers[7]; + transformMatrix.c3 = numbers[8]; + transformMatrix.d3 = 0; + + transformMatrix.a4 = numbers[9]; + transformMatrix.b4 = numbers[10]; + transformMatrix.c4 = numbers[11]; + transformMatrix.d4 = 1; + return transformMatrix; + } + + void ReadObject(XmlNode &node) { + int id = -1, pid = -1, pindex = -1; + bool hasId = getNodeAttribute(node, D3MF::XmlTag::id, id); + //bool hasType = getNodeAttribute(node, D3MF::XmlTag::type, type); not used currently + bool hasPid = getNodeAttribute(node, D3MF::XmlTag::pid, pid); + bool hasPindex = getNodeAttribute(node, D3MF::XmlTag::pindex, pindex); + + std::string idStr = to_string(id); + + if (!hasId) { + return; + } + + Object *obj = new Object(id); + + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == D3MF::XmlTag::mesh) { + auto mesh = ReadMesh(currentNode); + mesh->mName.Set(idStr); + + if (hasPid) { + auto it = mResourcesDictionnary.find(pid); + if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *materials = static_cast(it->second); + mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; + } + } + + obj->mMeshes.push_back(mesh); + obj->mMeshIndex.push_back(mMeshCount); + mMeshCount++; + } else if (currentName == D3MF::XmlTag::components) { + for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) { + if (currentSubNode.name() == D3MF::XmlTag::component) { + int objectId = -1; + std::string componentTransformStr; + aiMatrix4x4 componentTransform; + if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) { + componentTransform = parseTransformMatrix(componentTransformStr); + } + + if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) + obj->mComponents.push_back({ objectId, componentTransform }); + } + } + } + } + + mResourcesDictionnary.insert(std::make_pair(id, obj)); + } + + aiMesh *ReadMesh(XmlNode &node) { + aiMesh *mesh = new aiMesh(); + + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == D3MF::XmlTag::vertices) { + ImportVertices(currentNode, mesh); + } else if (currentName == D3MF::XmlTag::triangles) { + ImportTriangles(currentNode, mesh); + } + + } + + return mesh; + } + + void ReadMetadata(XmlNode &node) { + pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str()); + const std::string name = attribute.as_string(); + const std::string value = node.value(); + if (name.empty()) { + return; + } + + MetaEntry entry; + entry.name = name; + entry.value = value; + mMetaData.push_back(entry); + } + + void ImportVertices(XmlNode &node, aiMesh *mesh) { + std::vector vertices; + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == D3MF::XmlTag::vertex) { + vertices.push_back(ReadVertex(currentNode)); + } + } + + mesh->mNumVertices = static_cast(vertices.size()); + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + std::copy(vertices.begin(), vertices.end(), mesh->mVertices); + } + + aiVector3D ReadVertex(XmlNode &node) { + aiVector3D vertex; + vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr); + vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr); + vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr); + + return vertex; + } + + void ImportTriangles(XmlNode &node, aiMesh *mesh) { + std::vector faces; + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == D3MF::XmlTag::triangle) { + aiFace face = ReadTriangle(currentNode); + faces.push_back(face); + + int pid, p1; + bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid); + bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1); + + if (hasPid && hasP1) { + auto it = mResourcesDictionnary.find(pid); + if (it != mResourcesDictionnary.end()) + { + if (it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *baseMaterials = static_cast(it->second); + mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1]; + } + // TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material + } + } + } + } + + mesh->mNumFaces = static_cast(faces.size()); + mesh->mFaces = new aiFace[mesh->mNumFaces]; + mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + std::copy(faces.begin(), faces.end(), mesh->mFaces); + } + + aiFace ReadTriangle(XmlNode &node) { + aiFace face; + + face.mNumIndices = 3; + face.mIndices = new unsigned int[face.mNumIndices]; + face.mIndices[0] = static_cast(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string())); + face.mIndices[1] = static_cast(std::atoi(node.attribute(D3MF::XmlTag::v2.c_str()).as_string())); + face.mIndices[2] = static_cast(std::atoi(node.attribute(D3MF::XmlTag::v3.c_str()).as_string())); + + return face; + } + + void ReadBaseMaterials(XmlNode &node) { + int id = -1; + if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) { + BaseMaterials* baseMaterials = new BaseMaterials(id); + + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) + { + if (currentNode.name() == D3MF::XmlTag::basematerials_base) { + baseMaterials->mMaterialIndex.push_back(mMaterialCount); + baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id)); + mMaterialCount++; + } + } + + mResourcesDictionnary.insert(std::make_pair(id, baseMaterials)); + } + } + + bool parseColor(const char *color, aiColor4D &diffuse) { + if (nullptr == color) { + return false; + } + + //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1) + const size_t len(strlen(color)); + if (9 != len && 7 != len) { + return false; + } + + const char *buf(color); + if ('#' != buf[0]) { + return false; + } + + char r[3] = { buf[1], buf[2], '\0' }; + diffuse.r = static_cast(strtol(r, nullptr, 16)) / ai_real(255.0); + + char g[3] = { buf[3], buf[4], '\0' }; + diffuse.g = static_cast(strtol(g, nullptr, 16)) / ai_real(255.0); + + char b[3] = { buf[5], buf[6], '\0' }; + diffuse.b = static_cast(strtol(b, nullptr, 16)) / ai_real(255.0); + + if (7 == len) + return true; + + char a[3] = { buf[7], buf[8], '\0' }; + diffuse.a = static_cast(strtol(a, nullptr, 16)) / ai_real(255.0); + + return true; + } + + void assignDiffuseColor(XmlNode &node, aiMaterial *mat) { + const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string(); + aiColor4D diffuse; + if (parseColor(color, diffuse)) { + mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + } + } + + aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) { + aiMaterial *material = new aiMaterial(); + material->mNumProperties = 0; + std::string name; + bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name); + + std::string stdMaterialName; + std::string strId(to_string(basematerialsId)); + stdMaterialName += "id"; + stdMaterialName += strId; + stdMaterialName += "_"; + if (hasName) { + stdMaterialName += std::string(name); + } else { + stdMaterialName += "basemat_"; + stdMaterialName += to_string(mMaterialCount - basematerialsId); + } + + aiString assimpMaterialName(stdMaterialName); + material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME); + + assignDiffuseColor(node, material); + + return material; + } + +private: + struct MetaEntry { + std::string name; + std::string value; + }; + std::vector mMetaData; + std::map mResourcesDictionnary; + unsigned int mMaterialCount, mMeshCount; + XmlParser *mXmlParser; +}; + +} //namespace D3MF + +static const aiImporterDesc desc = { + "3mf Importer", + "", + "", + "http://3mf.io/", + aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour, + 0, + 0, + 0, + 0, + "3mf" +}; + +D3MFImporter::D3MFImporter() : + BaseImporter() { + // empty +} + +D3MFImporter::~D3MFImporter() { + // empty +} + +bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { + const std::string extension(GetExtension(filename)); + if (extension == desc.mFileExtensions) { + return true; + } else if (!extension.length() || checkSig) { + if (nullptr == pIOHandler) { + return false; + } + if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { + return false; + } + D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); + return opcPackage.validate(); + } + + return false; +} + +void D3MFImporter::SetupProperties(const Importer * /*pImp*/) { + // empty +} + +const aiImporterDesc *D3MFImporter::GetInfo() const { + return &desc; +} + +void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) { + D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); + + XmlParser xmlParser; + if (xmlParser.parse(opcPackage.RootStream())) { + D3MF::XmlSerializer xmlSerializer(&xmlParser); + xmlSerializer.ImportXml(pScene); + } +} + +} // Namespace Assimp + +#endif // ASSIMP_BUILD_NO_3MF_IMPORTER diff --git a/code/3MF/D3MFImporter.h b/code/AssetLib/3MF/D3MFImporter.h similarity index 100% rename from code/3MF/D3MFImporter.h rename to code/AssetLib/3MF/D3MFImporter.h diff --git a/code/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp similarity index 54% rename from code/3MF/D3MFOpcPackage.cpp rename to code/AssetLib/3MF/D3MFOpcPackage.cpp index 565790656..29bd3a2c3 100644 --- a/code/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -4,7 +4,6 @@ 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, @@ -45,19 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "D3MFOpcPackage.h" #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include "3MFXmlTags.h" #include #include -#include "3MFXmlTags.h" +#include +#include +#include +#include namespace Assimp { @@ -68,49 +68,48 @@ typedef std::shared_ptr OpcPackageRelationshipPtr; class OpcPackageRelationshipReader { public: - OpcPackageRelationshipReader(XmlReader* xmlReader) { - while(xmlReader->read()) { - if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && - xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) - { - ParseRootNode(xmlReader); + OpcPackageRelationshipReader(XmlParser &parser) { + XmlNode root = parser.getRootNode(); + ParseRootNode(root); + } + + void ParseRootNode(XmlNode &node) { + ParseAttributes(node); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + std::string name = currentNode.name(); + if (name == "Relationships") { + ParseRelationsNode(currentNode); } } } - void ParseRootNode(XmlReader* xmlReader) - { - ParseAttributes(xmlReader); - - while(xmlReader->read()) - { - if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && - xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) - { - ParseChildNode(xmlReader); - } - } - } - - void ParseAttributes(XmlReader*) { + void ParseAttributes(XmlNode & /*node*/) { // empty } - bool validateRels( OpcPackageRelationshipPtr &relPtr ) { - if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) { + bool validateRels(OpcPackageRelationshipPtr &relPtr) { + if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) { return false; } return true; } - void ParseChildNode(XmlReader* xmlReader) { - OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); + void ParseRelationsNode(XmlNode &node) { + if (node.empty()) { + return; + } - relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str()); - relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str()); - relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str()); - if ( validateRels( relPtr ) ) { - m_relationShips.push_back( relPtr ); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + std::string name = currentNode.name(); + if (name == "Relationship") { + OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); + relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string(); + relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string(); + relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string(); + if (validateRels(relPtr)) { + m_relationShips.push_back(relPtr); + } + } } } @@ -118,51 +117,53 @@ public: }; // ------------------------------------------------------------------------------------------------ -D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) -: mRootStream(nullptr) -, mZipArchive() { - mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) ); - if(!mZipArchive->isOpen()) { - throw DeadlyImportError("Failed to open file " + rFile+ "."); +D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : + mRootStream(nullptr), + mZipArchive() { + mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); + if (!mZipArchive->isOpen()) { + throw DeadlyImportError("Failed to open file ", rFile, "."); } std::vector fileList; mZipArchive->getFileList(fileList); - for (auto& file: fileList) { - if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) { - //PkgRelationshipReader pkgRelReader(file, archive); - ai_assert(mZipArchive->Exists(file.c_str())); + for (auto &file : fileList) { + if (file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) { + if (!mZipArchive->Exists(file.c_str())) { + continue; + } IOStream *fileStream = mZipArchive->Open(file.c_str()); - - ai_assert(fileStream != nullptr); + if (nullptr == fileStream) { + ai_assert(fileStream != nullptr); + continue; + } std::string rootFile = ReadPackageRootRelationship(fileStream); - if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) { - rootFile = rootFile.substr( 1 ); - if ( rootFile[ 0 ] == '/' ) { + if (rootFile.size() > 0 && rootFile[0] == '/') { + rootFile = rootFile.substr(1); + if (rootFile[0] == '/') { // deal with zip-bug - rootFile = rootFile.substr( 1 ); + rootFile = rootFile.substr(1); } } - ASSIMP_LOG_DEBUG(rootFile); + ASSIMP_LOG_VERBOSE_DEBUG(rootFile); mZipArchive->Close(fileStream); mRootStream = mZipArchive->Open(rootFile.c_str()); - ai_assert( mRootStream != nullptr ); - if ( nullptr == mRootStream ) { - throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile ); + ai_assert(mRootStream != nullptr); + if (nullptr == mRootStream) { + throw DeadlyExportError("Cannot open root-file in archive : " + rootFile); } - } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { - ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file); + } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { + ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file); } else { - ASSIMP_LOG_WARN_F("Ignored file of unknown type: ",file); + ASSIMP_LOG_WARN_F("Ignored file of unknown type: ", file); } - } } @@ -170,32 +171,34 @@ D3MFOpcPackage::~D3MFOpcPackage() { mZipArchive->Close(mRootStream); } -IOStream* D3MFOpcPackage::RootStream() const { +IOStream *D3MFOpcPackage::RootStream() const { return mRootStream; } static const std::string ModelRef = "3D/3dmodel.model"; bool D3MFOpcPackage::validate() { - if ( nullptr == mRootStream || nullptr == mZipArchive ) { + if (nullptr == mRootStream || nullptr == mZipArchive) { return false; } - return mZipArchive->Exists( ModelRef.c_str() ); + return mZipArchive->Exists(ModelRef.c_str()); } -std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { - std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(stream)); - std::unique_ptr xml(irr::io::createIrrXMLReader(xmlStream.get())); +std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { + XmlParser xmlParser; + if (!xmlParser.parse(stream)) { + return ""; + } - OpcPackageRelationshipReader reader(xml.get()); + OpcPackageRelationshipReader reader(xmlParser); - auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr& rel){ + auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) { return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; }); - if ( itr == reader.m_relationShips.end() ) { - throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE ); + if (itr == reader.m_relationShips.end()) { + throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); } return (*itr)->target; diff --git a/code/3MF/D3MFOpcPackage.h b/code/AssetLib/3MF/D3MFOpcPackage.h similarity index 92% rename from code/3MF/D3MFOpcPackage.h rename to code/AssetLib/3MF/D3MFOpcPackage.h index 291f8ad53..b2001b980 100644 --- a/code/3MF/D3MFOpcPackage.h +++ b/code/AssetLib/3MF/D3MFOpcPackage.h @@ -4,7 +4,6 @@ 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, @@ -44,18 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define D3MFOPCPACKAGE_H #include - +#include #include -#include namespace Assimp { class ZipArchiveIOSystem; namespace D3MF { -using XmlReader = irr::io::IrrXMLReader ; -using XmlReaderPtr = std::shared_ptr ; - struct OpcPackageRelationship { std::string id; std::string type; @@ -64,7 +59,7 @@ struct OpcPackageRelationship { class D3MFOpcPackage { public: - D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); + D3MFOpcPackage( IOSystem* pIOHandler, const std::string& file ); ~D3MFOpcPackage(); IOStream* RootStream() const; bool validate(); diff --git a/code/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp similarity index 83% rename from code/AC/ACLoader.cpp rename to code/AssetLib/AC/ACLoader.cpp index 85aee7e3a..bf2828655 100644 --- a/code/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -192,7 +192,7 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { objects.push_back(Object()); Object &obj = objects.back(); - aiLight *light = NULL; + aiLight *light = nullptr; if (!ASSIMP_strincmp(buffer, "light", 5)) { // This is a light source. Add it to the list mLights->push_back(light = new aiLight()); @@ -207,7 +207,7 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast(mLights->size()) - 1); obj.name = std::string(light->mName.data); - ASSIMP_LOG_DEBUG("AC3D: Light source encountered"); + ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered"); obj.type = Object::Light; } else if (!ASSIMP_strincmp(buffer, "group", 5)) { obj.type = Object::Group; @@ -294,7 +294,7 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { // example writes no surf chunks if (!Q3DWorkAround) { ASSIMP_LOG_WARN("AC3D: SURF token was expected"); - ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled"); + ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled"); } --buffer; // make sure the line is processed a second time // break; --- see fix notes above @@ -471,30 +471,37 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, ++node->mNumMeshes; } - switch ((*it).flags & 0xf) { - // closed line - case 0x1: - needMat[idx].first += (unsigned int)(*it).entries.size(); - needMat[idx].second += (unsigned int)(*it).entries.size() << 1u; - break; + switch ((*it).GetType()) { + // closed line + case Surface::ClosedLine: + needMat[idx].first += (unsigned int)(*it).entries.size(); + needMat[idx].second += (unsigned int)(*it).entries.size() << 1u; + break; - // unclosed line - case 0x2: - needMat[idx].first += (unsigned int)(*it).entries.size() - 1; - needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u; - break; + // unclosed line + case Surface::OpenLine: + needMat[idx].first += (unsigned int)(*it).entries.size() - 1; + needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u; + break; - // 0 == polygon, else unknown - default: - if ((*it).flags & 0xf) { - ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown"); - (*it).flags &= ~(0xf); - } + // triangle strip + case Surface::TriangleStrip: + needMat[idx].first += (unsigned int)(*it).entries.size() - 2; + needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3; + break; - // the number of faces increments by one, the number - // of vertices by surface.numref. - needMat[idx].first++; - needMat[idx].second += (unsigned int)(*it).entries.size(); + 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 + // of vertices by surface.numref. + needMat[idx].first++; + needMat[idx].second += (unsigned int)(*it).entries.size(); }; } unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes]; @@ -535,7 +542,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, // allocate UV coordinates, but only if the texture name for the // surface is not empty - aiVector3D *uv = NULL; + aiVector3D *uv = nullptr; if (object.texture.length()) { uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; mesh->mNumUVComponents[0] = 2; @@ -546,8 +553,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, const Surface &src = *it; // closed polygon - unsigned int type = (*it).flags & 0xf; - if (!type) { + uint8_t type = (*it).GetType(); + if (type == Surface::Polygon) { aiFace &face = *faces++; face.mNumIndices = (unsigned int)src.entries.size(); 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(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 { it2 = (*it).entries.begin(); // either a closed or an unclosed line 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) { aiFace &face = *faces++; @@ -599,7 +664,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, ++uv; } - if (0x1 == type && tmp - 1 == m) { + if (Surface::ClosedLine == type && tmp - 1 == m) { // if this is a closed line repeat its beginning now it2 = (*it).entries.begin(); } else @@ -627,7 +692,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, std::unique_ptr div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name); - std::vector cpy(meshes.size() - oldm, NULL); + std::vector cpy(meshes.size() - oldm, nullptr); div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true); std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm); @@ -644,20 +709,20 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, else { // generate a name depending on the type of the node switch (object.type) { - case Object::Group: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++); - break; - case Object::Poly: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++); - break; - case Object::Light: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++); - break; + case Object::Group: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++); + break; + case Object::Poly: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++); + break; + case Object::Light: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++); + break; - // there shouldn't be more than one world, but we don't care - case Object::World: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++); - break; + // there shouldn't be more than one world, but we don't care + case Object::World: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++); + break; } } @@ -696,8 +761,8 @@ void AC3DImporter::InternReadFile(const std::string &pFile, std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file - if ( file.get() == nullptr ) { - throw DeadlyImportError("Failed to open AC3D file " + pFile + "."); + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open AC3D file ", pFile, "."); } // allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AC/ACLoader.h b/code/AssetLib/AC/ACLoader.h similarity index 75% rename from code/AC/ACLoader.h rename to code/AssetLib/AC/ACLoader.h index b32cc7ee3..c0bf97866 100644 --- a/code/AC/ACLoader.h +++ b/code/AssetLib/AC/ACLoader.h @@ -4,7 +4,6 @@ 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, @@ -56,27 +55,23 @@ struct aiMesh; struct aiMaterial; struct aiLight; - -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** AC3D (*.ac) importer class */ -class AC3DImporter : public BaseImporter -{ +class AC3DImporter : public BaseImporter { public: AC3DImporter(); ~AC3DImporter(); // Represents an AC3D material - struct Material - { - Material() - : rgb (0.6f,0.6f,0.6f) - , spec (1.f,1.f,1.f) - , shin (0.f) - , trans (0.f) - {} + struct Material { + Material() : + 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 aiColor3D rgb; @@ -101,43 +96,50 @@ public: }; // Represents an AC3D surface - struct Surface - { - Surface() - : mat (0) - , flags (0) - {} + struct Surface { + Surface() : + mat(0), + flags(0) {} - unsigned int mat,flags; + unsigned int mat, flags; - typedef std::pair SurfaceEntry; - std::vector< SurfaceEntry > entries; + typedef std::pair SurfaceEntry; + std::vector 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 const uint8_t GetType() const { return (flags & Mask); } }; // Represents an AC3D object - struct 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() - {} + struct 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 description - enum Type - { + enum Type { World = 0x0, - Poly = 0x1, + Poly = 0x1, Group = 0x2, Light = 0x4 } type; @@ -177,37 +179,33 @@ public: float crease; }; - public: - // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const; + bool CanRead(const std::string &pFile, IOSystem *pIOHandler, + bool checkSig) const; protected: - // ------------------------------------------------------------------- /** Return importer meta information. * See #BaseImporter::GetInfo for the details */ - const aiImporterDesc* GetInfo () const; + const aiImporterDesc *GetInfo() const; // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. * See BaseImporter::InternReadFile() for details*/ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler); + void InternReadFile(const std::string &pFile, aiScene *pScene, + IOSystem *pIOHandler); // ------------------------------------------------------------------- /** Called prior to ReadFile(). * The function is a request to the importer to update its configuration * basing on the Importer's configuration property list.*/ - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer *pImp); private: - // ------------------------------------------------------------------- /** Get the next line from the file. * @return false if the end of the file was reached*/ @@ -218,7 +216,7 @@ private: * load subobjects, the method returns after a 'kids 0' was * encountered. * @objects List of output objects*/ - void LoadObjectSection(std::vector& objects); + void LoadObjectSection(std::vector &objects); // ------------------------------------------------------------------- /** Convert all objects into meshes and nodes. @@ -227,24 +225,24 @@ private: * @param outMaterials List of output materials * @param materials Material list * @param Scenegraph node for the object */ - aiNode* ConvertObjectSection(Object& object, - std::vector& meshes, - std::vector& outMaterials, - const std::vector& materials, - aiNode* parent = NULL); + aiNode *ConvertObjectSection(Object &object, + std::vector &meshes, + std::vector &outMaterials, + const std::vector &materials, + aiNode *parent = nullptr); // ------------------------------------------------------------------- /** Convert a material * @param object Current object * @param matSrc Source material description * @param matDest Destination material to be filled */ - void ConvertMaterial(const Object& object, - const Material& matSrc, - aiMaterial& matDest); + void ConvertMaterial(const Object &object, + const Material &matSrc, + aiMaterial &matDest); private: // points to the next data line - const char* buffer; + const char *buffer; // Configuration option: if enabled, up to two meshes // are generated per material: those faces who have @@ -261,7 +259,7 @@ private: unsigned int mNumMeshes; // current list of light sources - std::vector* mLights; + std::vector *mLights; // name counters unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter; diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp new file mode 100644 index 000000000..179197037 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -0,0 +1,541 @@ +/* +--------------------------------------------------------------------------- +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 AMFImporter.cpp +/// \brief AMF-format files importer for Assimp: main algorithm implementation. +/// \date 2016 +/// \author smal.root@gmail.com + +#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER + +// Header files, Assimp. +#include "AMFImporter.hpp" +#include "AMFImporter_Macro.hpp" + +#include +#include + +// Header files, stdlib. +#include + +namespace Assimp { + +const aiImporterDesc AMFImporter::Description = { + "Additive manufacturing file format(AMF) Importer", + "smalcom", + "", + "See documentation in source code. Chapter: Limitations.", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "amf" +}; + +void AMFImporter::Clear() { + mNodeElement_Cur = nullptr; + mUnit.clear(); + mMaterial_Converted.clear(); + mTexture_Converted.clear(); + // Delete all elements + if (!mNodeElement_List.empty()) { + for (AMFNodeElementBase *ne : mNodeElement_List) { + delete ne; + } + + mNodeElement_List.clear(); + } +} + +AMFImporter::AMFImporter() AI_NO_EXCEPT : + mNodeElement_Cur(nullptr), + mXmlParser(nullptr), + mUnit(), + mVersion(), + mMaterial_Converted(), + mTexture_Converted() { + // empty +} + +AMFImporter::~AMFImporter() { + delete mXmlParser; + // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. + Clear(); +} + +/*********************************************************************************************************************************************/ +/************************************************************ Functions: find set ************************************************************/ +/*********************************************************************************************************************************************/ + +bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const { + for (AMFNodeElementBase *ne : mNodeElement_List) { + if ((ne->ID == pID) && (ne->Type == pType)) { + if (pNodeElement != nullptr) { + *pNodeElement = ne; + } + + return true; + } + } // for(CAMFImporter_NodeElement* ne: mNodeElement_List) + + return false; +} + +bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const { + aiString node_name(pID.c_str()); + for (aiNode *node : nodeArray) { + if (node->mName == node_name) { + if (pNode != nullptr) { + *pNode = node; + } + + return true; + } + } // for(aiNode* node: pNodeList) + + return false; +} + +bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const { + for (const SPP_Material &mat : mMaterial_Converted) { + if (mat.ID == pID) { + if (pConvertedMaterial != nullptr) { + *pConvertedMaterial = &mat; + } + + return true; + } + } // for(const SPP_Material& mat: mMaterial_Converted) + + return false; +} + +/*********************************************************************************************************************************************/ +/************************************************************ Functions: throw set ***********************************************************/ +/*********************************************************************************************************************************************/ + +void AMFImporter::Throw_CloseNotFound(const std::string &nodeName) { + throw DeadlyImportError("Close tag for node <" + nodeName + "> not found. Seems file is corrupt."); +} + +void AMFImporter::Throw_IncorrectAttr(const std::string &nodeName, const std::string &attrName) { + throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + attrName + "\"."); +} + +void AMFImporter::Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &attrName) { + throw DeadlyImportError("Attribute \"" + attrName + "\" in node <" + nodeName + "> has incorrect value."); +} + +void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) { + throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription); +} + +void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { + throw DeadlyImportError("Not found node with name \"", pID, "\"."); +} + +/*********************************************************************************************************************************************/ +/************************************************************* Functions: XML set ************************************************************/ +/*********************************************************************************************************************************************/ + +void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) { + if (node.children().begin() == node.children().end()) { + throw DeadlyImportError(std::string("Node <") + node.name() + "> must have children."); + } +} + +bool AMFImporter::XML_SearchNode(const std::string &nodeName) { + return nullptr != mXmlParser->findNode(nodeName); +} + +void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) { + size_t instr_len; + + pOutString.clear(); + instr_len = strlen(pInStr); + if (!instr_len) return; + + pOutString.reserve(instr_len * 3 / 2); + // check and correct floats in format ".x". Must be "x.y". + if (pInStr[0] == '.') pOutString.push_back('0'); + + pOutString.push_back(pInStr[0]); + for (size_t ci = 1; ci < instr_len; ci++) { + if ((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) { + pOutString.push_back('0'); + pOutString.push_back('.'); + } else { + pOutString.push_back(pInStr[ci]); + } + } +} + +static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) { + return (isalnum(pChar) || (pChar == '+') || (pChar == '/')); +} + +void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector &pOutputData) const { + // With help from + // René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html + const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + uint8_t tidx = 0; + uint8_t arr4[4], arr3[3]; + + // check input data + if (pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four."); + // prepare output place + pOutputData.clear(); + pOutputData.reserve(pInputBase64.size() / 4 * 3); + + for (size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--) { + if (ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) { + arr4[tidx++] = pInputBase64[in_idx++]; + if (tidx == 4) { + for (tidx = 0; tidx < 4; tidx++) + arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]); + + arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); + arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2); + arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3]; + for (tidx = 0; tidx < 3; tidx++) + pOutputData.push_back(arr3[tidx]); + + tidx = 0; + } // if(tidx == 4) + } // if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) + else { + in_idx++; + } // if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else + } + + if (tidx) { + for (uint8_t i = tidx; i < 4; i++) + arr4[i] = 0; + for (uint8_t i = 0; i < 4; i++) + arr4[i] = (uint8_t)(base64_chars.find(arr4[i])); + + arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); + arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2); + arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3]; + for (uint8_t i = 0; i < (tidx - 1); i++) + pOutputData.push_back(arr3[i]); + } +} + +void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { + std::unique_ptr file(pIOHandler->Open(pFile, "rb")); + + // Check whether we can read from the file + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open AMF file ", pFile, "."); + } + + mXmlParser = new XmlParser(); + if (!mXmlParser->parse(file.get())) { + delete mXmlParser; + throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); + } + + // Start reading, search for root tag + if (!mXmlParser->hasNode("amf")) { + throw DeadlyImportError("Root node \"amf\" not found."); + } + ParseNode_Root(); +} // namespace Assimp + +void AMFImporter::ParseHelper_Node_Enter(AMFNodeElementBase *node) { + mNodeElement_Cur->Child.push_back(node); // add new element to current element child list. + mNodeElement_Cur = node; +} + +void AMFImporter::ParseHelper_Node_Exit() { + if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent; +} + +// +// +// Root XML element. +// Multi elements - No. +void AMFImporter::ParseNode_Root() { + AMFNodeElementBase *ne = nullptr; + XmlNode *root = mXmlParser->findNode("amf"); + if (nullptr == root) { + throw DeadlyImportError("Root node \"amf\" not found."); + } + XmlNode node = *root; + mUnit = node.attribute("unit").as_string(); + mVersion = node.attribute("version").as_string(); + + // Read attributes for node . + // Check attributes + if (!mUnit.empty()) { + if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) { + Throw_IncorrectAttrValue("unit", mUnit); + } + } + + // create root node element. + ne = new AMFRoot(nullptr); + + mNodeElement_Cur = ne; // set first "current" element + // and assign attribute's values + ((AMFRoot *)ne)->Unit = mUnit; + ((AMFRoot *)ne)->Version = mVersion; + + // Check for child nodes + for (XmlNode ¤tNode : node.children() ) { + const std::string currentName = currentNode.name(); + if (currentName == "object") { + ParseNode_Object(currentNode); + } else if (currentName == "material") { + ParseNode_Material(currentNode); + } else if (currentName == "texture") { + ParseNode_Texture(currentNode); + } else if (currentName == "constellation") { + ParseNode_Constellation(currentNode); + } else if (currentName == "metadata") { + ParseNode_Metadata(currentNode); + } + mNodeElement_Cur = ne; + } + mNodeElement_Cur = ne; // force restore "current" element + mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph. +} + +// +// +// A collection of objects or constellations with specific relative locations. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Constellation(XmlNode &node) { + std::string id; + id = node.attribute("id").as_string(); + + // create and if needed - define new grouping object. + AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur); + + AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience + + if (!id.empty()) { + als.ID = id; + } + + // Check for child nodes + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + std::string name = currentNode.name(); + if (name == "instance") { + ParseNode_Instance(currentNode); + } else if (name == "metadata") { + ParseNode_Metadata(currentNode); + } + } + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); + } + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// A collection of objects or constellations with specific relative locations. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Instance(XmlNode &node) { + AMFNodeElementBase *ne(nullptr); + + // Read attributes for node . + std::string objectid = node.attribute("objectid").as_string(); + + // used object id must be defined, check that. + if (objectid.empty()) { + throw DeadlyImportError("\"objectid\" in must be defined."); + } + // create and define new grouping object. + ne = new AMFInstance(mNodeElement_Cur); + AMFInstance &als = *((AMFInstance *)ne); + als.ObjectID = objectid; + + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "deltax") { + als.Delta.x = (ai_real)std::atof(currentNode.value()); + } else if (currentName == "deltay") { + als.Delta.y = (ai_real)std::atof(currentNode.value()); + } else if (currentName == "deltaz") { + als.Delta.z = (ai_real)std::atof(currentNode.value()); + } else if (currentName == "rx") { + als.Delta.x = (ai_real)std::atof(currentNode.value()); + } else if (currentName == "ry") { + als.Delta.y = (ai_real)std::atof(currentNode.value()); + } else if (currentName == "rz") { + als.Delta.z = (ai_real)std::atof(currentNode.value()); + } + } + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// An object definition. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Object(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + // Read attributes for node . + std::string id = node.attribute("id").as_string(); + + // create and if needed - define new geometry object. + ne = new AMFObject(mNodeElement_Cur); + + AMFObject &als = *((AMFObject *)ne); // alias for convenience + + if (!id.empty()) { + als.ID = id; + } + + // Check for child nodes + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "color") { + ParseNode_Color(currentNode); + } else if (currentName == "mesh") { + ParseNode_Mesh(currentNode); + } else if (currentName == "metadata") { + ParseNode_Metadata(currentNode); + } + } + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// Specify additional information about an entity. +// Multi elements - Yes. +// Parent element - , , , , . +// +// Reserved types are: +// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user. +// "Description" - A description of the content of the entity +// "URL" - A link to an external resource relating to the entity +// "Author" - Specifies the name(s) of the author(s) of the entity +// "Company" - Specifying the company generating the entity +// "CAD" - specifies the name of the originating CAD software and version +// "Revision" - specifies the revision of the entity +// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system +// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only) +void AMFImporter::ParseNode_Metadata(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + std::string type = node.attribute("type").as_string(), value; + XmlParser::getValueAsString(node, value); + + // read attribute + ne = new AMFMetadata(mNodeElement_Cur); + ((AMFMetadata *)ne)->Type = type; + ((AMFMetadata *)ne)->Value = value; + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const { + const std::string extension = GetExtension(pFile); + + if (extension == "amf") { + return true; + } + + if (extension.empty() || pCheckSig) { + const char *tokens[] = { " &pExtensionList) { + pExtensionList.insert("amf"); +} + +const aiImporterDesc *AMFImporter::GetInfo() const { + return &Description; +} + +void AMFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + Clear(); // delete old graph. + ParseFile(pFile, pIOHandler); + Postprocess_BuildScene(pScene); + // scene graph is ready, exit. +} + +} // namespace Assimp + +#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/AssetLib/AMF/AMFImporter.hpp b/code/AssetLib/AMF/AMFImporter.hpp new file mode 100644 index 000000000..4671559ee --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter.hpp @@ -0,0 +1,311 @@ +/* +--------------------------------------------------------------------------- +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 AMFImporter.hpp +/// \brief AMF-format files importer for Assimp. +/// \date 2016 +/// \author smal.root@gmail.com +// Thanks to acorn89 for support. + +#pragma once +#ifndef INCLUDED_AI_AMF_IMPORTER_H +#define INCLUDED_AI_AMF_IMPORTER_H + +#include "AMFImporter_Node.hpp" + +// Header files, Assimp. +#include "assimp/types.h" +#include +#include +#include +#include + +// Header files, stdlib. +#include + +namespace Assimp { + +/// \class AMFImporter +/// Class that holding scene graph which include: geometry, metadata, materials etc. +/// +/// Implementing features. +/// +/// Limitations. +/// +/// 1. When for texture mapping used set of source textures (r, g, b, a) not only one then attribute "tiled" for all set will be true if it true in any of +/// source textures. +/// Example. Triangle use for texture mapping three textures. Two of them has "tiled" set to false and one - set to true. In scene all three textures +/// will be tiled. +/// +/// Unsupported features: +/// 1. Node , formulas in and . For implementing this feature can be used expression parser "muParser" like in project +/// "amf_tools". +/// 2. Attribute "profile" in node . +/// 3. Curved geometry: , and children nodes of them. +/// 4. Attributes: "unit" and "version" in read but do nothing. +/// 5. stored only for root node . +/// 6. Color averaging of vertices for which 's set different colors. +/// +/// Supported nodes: +/// General: +/// ; ; and children , , , , , ; ; +/// +/// Geometry: +/// ; ; ; ; and children , , ; ; and children , , ; +/// +/// Material: +/// and children , , , ; ; ; +/// two variants of texture coordinates: +/// new - and children , , , , , +/// old - and children , , , , , +/// +class AMFImporter : public BaseImporter { +private: + struct SPP_Material; // forward declaration + + /// Data type for post-processing step. More suitable container for part of material's composition. + struct SPP_Composite { + SPP_Material *Material; ///< Pointer to material - part of composition. + std::string Formula; ///< Formula for calculating ratio of \ref Material. + }; + + /// \struct SPP_Material + /// Data type for post-processing step. More suitable container for material. + struct SPP_Material { + std::string ID; ///< Material ID. + std::list Metadata; ///< Metadata of material. + AMFColor *Color; ///< Color of material. + std::list Composition; ///< List of child materials if current material is composition of few another. + + /// Return color calculated for specified coordinate. + /// \param [in] pX - "x" coordinate. + /// \param [in] pY - "y" coordinate. + /// \param [in] pZ - "z" coordinate. + /// \return calculated color. + aiColor4D GetColor(const float pX, const float pY, const float pZ) const; + }; + + /// Data type for post-processing step. More suitable container for texture. + struct SPP_Texture { + std::string ID; + size_t Width, Height, Depth; + bool Tiled; + char FormatHint[9]; // 8 for string + 1 for terminator. + uint8_t *Data; + }; + + /// Data type for post-processing step. Contain face data. + struct SComplexFace { + aiFace Face; ///< Face vertices. + const AMFColor *Color; ///< Face color. Equal to nullptr if color is not set for the face. + const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. + }; + + using AMFMetaDataArray = std::vector; + using MeshArray = std::vector; + using NodeArray = std::vector; + + /// Clear all temporary data. + void Clear(); + + /// Get data stored in and place it to arrays. + /// \param [in] pNodeElement - reference to node element which kept data. + /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in . + /// \param [in] pVertexColorArray - reference to vertices colors for all &pVertexCoordinateArray, + std::vector &pVertexColorArray) const; + + /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new + /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it + /// to converted textures list. + /// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified. + /// \param [in] pID_R - ID of source "red" texture. + /// \param [in] pID_G - ID of source "green" texture. + /// \param [in] pID_B - ID of source "blue" texture. + /// \param [in] pID_A - ID of source "alpha" texture. + /// \return index of the texture in array of the converted textures. + size_t PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B, const std::string &pID_A); + + /// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc). + /// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after + /// processing. + /// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing. + void PostprocessHelper_SplitFacesByTextureID(std::list &pInputList, std::list> &pOutputList_Separated); + + /// Check if child elements of node element is metadata and add it to scene node. + /// \param [in] pMetadataList - reference to list with collected metadata. + /// \param [out] pSceneNode - scene node in which metadata will be added. + void Postprocess_AddMetadata(const AMFMetaDataArray &pMetadataList, aiNode &pSceneNode) const; + + /// To create aiMesh and aiNode for it from . + /// \param [in] pNodeElement - reference to node element which kept data. + /// \param [out] meshList - reference to a list with all aiMesh of the scene. + /// \param [out] pSceneNode - pointer to place where new aiNode will be created. + void Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode); + + /// Create mesh for every in . + /// \param [in] pNodeElement - reference to node element which kept data. + /// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all 's. + /// \param [in] pVertexColorArray - reference to vertices colors for all 's. If color for vertex is not set then corresponding member of array + /// contain nullptr. + /// \param [in] pObjectColor - pointer to colors for . If color is not set then argument contain nullptr. + /// \param [in] pMaterialList - reference to a list with defined materials. + /// \param [out] pMeshList - reference to a list with all aiMesh of the scene. + /// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's. + void Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector &pVertexCoordinateArray, + const std::vector &pVertexColorArray, const AMFColor *pObjectColor, + MeshArray &pMeshList, aiNode &pSceneNode); + + /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material. + /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material. + void Postprocess_BuildMaterial(const AMFMaterial &pMaterial); + + /// Create and add to aiNode's list new part of scene graph defined by . + /// \param [in] pConstellation - reference to node. + /// \param [out] nodeArray - reference to aiNode's list. + void Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const; + + /// Build Assimp scene graph in aiScene from collected data. + /// \param [out] pScene - pointer to aiScene where tree will be built. + void Postprocess_BuildScene(aiScene *pScene); + + /// Decode Base64-encoded data. + /// \param [in] pInputBase64 - reference to input Base64-encoded string. + /// \param [out] pOutputData - reference to output array for decoded data. + void ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector &pOutputData) const; + + /// Parse node of the file. + void ParseNode_Root(); + + /// Parse node of the file. + void ParseNode_Constellation(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Instance(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Material(XmlNode &node); + + /// Parse node. + void ParseNode_Metadata(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Object(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Texture(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Coordinates(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Edge(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Mesh(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Triangle(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Vertex(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Vertices(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Volume(XmlNode &node); + + /// Parse node of the file. + void ParseNode_Color(XmlNode &node); + + /// Parse of node of the file. + /// \param [in] pUseOldName - if true then use old name of node(and children) - , instead of new name - . + void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false); + +public: + /// Default constructor. + AMFImporter() AI_NO_EXCEPT; + + /// Default destructor. + ~AMFImporter(); + + /// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph. + /// Also exception can be thrown if trouble will found. + /// \param [in] pFile - name of file to be parsed. + /// \param [in] pIOHandler - pointer to IO helper object. + void ParseFile(const std::string &pFile, IOSystem *pIOHandler); + void ParseHelper_Node_Enter(AMFNodeElementBase *child); + void ParseHelper_Node_Exit(); + bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const; + void GetExtensionList(std::set &pExtensionList); + void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); + const aiImporterDesc *GetInfo() const; + bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const; + bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const; + bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const; + void Throw_CloseNotFound(const std::string &nodeName); + void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName); + void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName); + void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription); + void Throw_ID_NotFound(const std::string &pID) const; + void XML_CheckNode_MustHaveChildren(pugi::xml_node &node); + bool XML_SearchNode(const std::string &nodeName); + void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString); + AMFImporter(const AMFImporter &pScene) = delete; + AMFImporter &operator=(const AMFImporter &pScene) = delete; + +private: + static const aiImporterDesc Description; + + AMFNodeElementBase *mNodeElement_Cur; ///< Current element. + std::list mNodeElement_List; ///< All elements of scene graph. + XmlParser *mXmlParser; + std::string mUnit; + std::string mVersion; + std::list mMaterial_Converted; ///< List of converted materials for postprocessing step. + std::list mTexture_Converted; ///< List of converted textures for postprocessing step. +}; + +} // namespace Assimp + +#endif // INCLUDED_AI_AMF_IMPORTER_H diff --git a/code/AssetLib/AMF/AMFImporter_Geometry.cpp b/code/AssetLib/AMF/AMFImporter_Geometry.cpp new file mode 100644 index 000000000..7afe52311 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Geometry.cpp @@ -0,0 +1,289 @@ +/* +--------------------------------------------------------------------------- +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 AMFImporter_Geometry.cpp +/// \brief Parsing data from geometry nodes. +/// \date 2016 +/// \author smal.root@gmail.com + +#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER + +#include "AMFImporter.hpp" +#include "AMFImporter_Macro.hpp" + +#include + +namespace Assimp { + +// +// +// A 3D mesh hull. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Mesh(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + // Check for child nodes + if (0 != ASSIMP_stricmp(node.name(), "mesh")) { + return; + } + // create new mesh object. + ne = new AMFMesh(mNodeElement_Cur); + bool found_verts = false, found_volumes = false; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + pugi::xml_node vertNode = node.child("vertices"); + if (!vertNode.empty()) { + ParseNode_Vertices(vertNode); + found_verts = true; + } + + pugi::xml_node volumeNode = node.child("volume"); + if (!volumeNode.empty()) { + ParseNode_Volume(volumeNode); + found_volumes = true; + } + ParseHelper_Node_Exit(); + } + + if (!found_verts && !found_volumes) { + mNodeElement_Cur->Child.push_back(ne); + } // if(!mReader->isEmptyElement()) else + + // and to node element list because its a new object in graph. + mNodeElement_List.push_back(ne); +} + +// +// +// The list of vertices to be used in defining triangles. +// Multi elements - No. +// Parent element - . +void AMFImporter::ParseNode_Vertices(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + // create new mesh object. + ne = new AMFVertices(mNodeElement_Cur); + // Check for child nodes + pugi::xml_node vertexNode = node.child("vertex"); + if (!vertexNode.empty()) { + ParseHelper_Node_Enter(ne); + + ParseNode_Vertex(vertexNode); + + ParseHelper_Node_Exit(); + + } else { + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + } // if(!mReader->isEmptyElement()) else + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// A vertex to be referenced in triangles. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Vertex(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + // create new mesh object. + ne = new AMFVertex(mNodeElement_Cur); + + // Check for child nodes + pugi::xml_node colorNode = node.child("color"); + bool col_read = false; + bool coord_read = false; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + if (!colorNode.empty()) { + ParseNode_Color(colorNode); + col_read = true; + } + pugi::xml_node coordNode = node.child("coordinates"); + if (!coordNode.empty()) { + ParseNode_Coordinates(coordNode); + coord_read = true; + } + ParseHelper_Node_Exit(); + } + + if (!coord_read && !col_read) { + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// Specifies the 3D location of this vertex. +// Multi elements - No. +// Parent element - . +// +// Children elements: +// , , +// Multi elements - No. +// X, Y, or Z coordinate, respectively, of a vertex position in space. +void AMFImporter::ParseNode_Coordinates(XmlNode &node) { + AMFNodeElementBase *ne = nullptr; + + // create new color object. + ne = new AMFCoordinates(mNodeElement_Cur); + + AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "X") { + XmlParser::getValueAsFloat(currentNode, als.Coordinate.x); + } else if (currentName == "Y") { + XmlParser::getValueAsFloat(currentNode, als.Coordinate.y); + } else if (currentName == "Z") { + XmlParser::getValueAsFloat(currentNode, als.Coordinate.z); + } + } + + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// Defines a volume from the established vertex list. +// Multi elements - Yes. +// Parent element - . +void AMFImporter::ParseNode_Volume(XmlNode &node) { + std::string materialid; + std::string type; + AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur); + + // Read attributes for node . + // and assign read data + + ((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string(); + + ((AMFVolume *)ne)->Type = type; + // Check for child nodes + bool col_read = false; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string currentName = currentNode.name(); + if (currentName == "color") { + if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for ."); + ParseNode_Color(currentNode); + col_read = true; + } else if (currentName == "triangle") { + ParseNode_Triangle(currentNode); + } else if (currentName == "metadata") { + ParseNode_Metadata(currentNode); + } else if (currentName == "volume") { + ParseNode_Metadata(currentNode); + } + } + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +// +// +// Defines a 3D triangle from three vertices, according to the right-hand rule (counter-clockwise when looking from the outside). +// Multi elements - Yes. +// Parent element - . +// +// Children elements: +// , , +// Multi elements - No. +// Index of the desired vertices in a triangle or edge. +void AMFImporter::ParseNode_Triangle(XmlNode &node) { + AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur); + + // create new triangle object. + + AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience + + bool col_read = false; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string currentName = currentNode.name(); + if (currentName == "color") { + if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for ."); + ParseNode_Color(currentNode); + col_read = true; + } else if (currentName == "texmap") { + ParseNode_TexMap(currentNode); + } else if (currentName == "map") { + ParseNode_TexMap(currentNode, true); + } else if (currentName == "v1") { + als.V[0] = std::atoi(currentNode.value()); + } else if (currentName == "v2") { + als.V[1] = std::atoi(currentNode.value()); + } else if (currentName == "v3") { + als.V[2] = std::atoi(currentNode.value()); + } + } + ParseHelper_Node_Exit(); + } else { + mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element + } + + mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. +} + +} // namespace Assimp + +#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/AMF/AMFImporter_Macro.hpp b/code/AssetLib/AMF/AMFImporter_Macro.hpp similarity index 99% rename from code/AMF/AMFImporter_Macro.hpp rename to code/AssetLib/AMF/AMFImporter_Macro.hpp index ec06cb999..c1a6e3f2d 100644 --- a/code/AMF/AMFImporter_Macro.hpp +++ b/code/AssetLib/AMF/AMFImporter_Macro.hpp @@ -1,12 +1,10 @@ -/* +/* --------------------------------------------------------------------------- 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, diff --git a/code/AMF/AMFImporter_Material.cpp b/code/AssetLib/AMF/AMFImporter_Material.cpp similarity index 53% rename from code/AMF/AMFImporter_Material.cpp rename to code/AssetLib/AMF/AMFImporter_Material.cpp index 64da12dda..e1b6c3e8b 100644 --- a/code/AMF/AMFImporter_Material.cpp +++ b/code/AssetLib/AMF/AMFImporter_Material.cpp @@ -1,12 +1,10 @@ -/* +/* --------------------------------------------------------------------------- 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, @@ -49,10 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER #include "AMFImporter.hpp" -#include "AMFImporter_Macro.hpp" -namespace Assimp -{ +namespace Assimp { // , and . @@ -68,46 +64,44 @@ namespace Assimp // Multi elements - No. // Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The // values can be specified as constants, or as a formula depending on the coordinates. -void AMFImporter::ParseNode_Color() { - std::string profile; - CAMFImporter_NodeElement* ne; - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("profile", profile, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - +void AMFImporter::ParseNode_Color(XmlNode &node) { + std::string profile = node.attribute("profile").as_string(); + // create new color object. - ne = new CAMFImporter_NodeElement_Color(mNodeElement_Cur); - - CAMFImporter_NodeElement_Color& als = *((CAMFImporter_NodeElement_Color*)ne);// alias for convenience + AMFNodeElementBase *ne = new AMFColor(mNodeElement_Cur); + AMFColor& als = *((AMFColor*)ne);// alias for convenience als.Profile = profile; - // Check for child nodes - if(!mReader->isEmptyElement()) - { + if (!node.empty()) { + ParseHelper_Node_Enter(ne); bool read_flag[4] = { false, false, false, false }; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("color"); - MACRO_NODECHECK_READCOMP_F("r", read_flag[0], als.Color.r); - MACRO_NODECHECK_READCOMP_F("g", read_flag[1], als.Color.g); - MACRO_NODECHECK_READCOMP_F("b", read_flag[2], als.Color.b); - MACRO_NODECHECK_READCOMP_F("a", read_flag[3], als.Color.a); - MACRO_NODECHECK_LOOPEND("color"); - ParseHelper_Node_Exit(); + for (pugi::xml_node &child : node.children()) { + std::string name = child.name(); + if ( name == "r") { + read_flag[0] = true; + XmlParser::getValueAsFloat(child, als.Color.r); + } else if (name == "g") { + read_flag[1] = true; + XmlParser::getValueAsFloat(child, als.Color.g); + } else if (name == "b") { + read_flag[2] = true; + XmlParser::getValueAsFloat(child, als.Color.b); + } else if (name == "a") { + read_flag[3] = true; + XmlParser::getValueAsFloat(child, als.Color.a); + } + ParseHelper_Node_Exit(); + } // check that all components was defined - if (!(read_flag[0] && read_flag[1] && read_flag[2])) { - throw DeadlyImportError("Not all color components are defined."); - } + if (!(read_flag[0] && read_flag[1] && read_flag[2])) { + throw DeadlyImportError("Not all color components are defined."); + } - // check if is absent. Then manually add "a == 1". - if (!read_flag[3]) { - als.Color.a = 1; - } - } - else - { + // check if is absent. Then manually add "a == 1". + if (!read_flag[3]) { + als.Color.a = 1; + } + } else { mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element } @@ -122,45 +116,25 @@ void AMFImporter::ParseNode_Color() { // An available material. // Multi elements - Yes. // Parent element - . -void AMFImporter::ParseNode_Material() { - std::string id; - CAMFImporter_NodeElement* ne; - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // create new object. - ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur); - - // and assign read data - ((CAMFImporter_NodeElement_Material*)ne)->ID = id; +void AMFImporter::ParseNode_Material(XmlNode &node) { + // create new object and assign read data + std::string id = node.attribute("id").as_string(); + AMFNodeElementBase *ne = new AMFMaterial(mNodeElement_Cur); + ((AMFMaterial*)ne)->ID = id; // Check for child nodes - if(!mReader->isEmptyElement()) - { - bool col_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("material"); - if(XML_CheckNode_NameEqual("color")) - { - // Check if data already defined. - if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (pugi::xml_node &child : node.children()) { + const std::string name = child.name(); + if (name == "color") { + ParseNode_Color(child); + } else if (name == "metadata") { + ParseNode_Metadata(child); } - - if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } - MACRO_NODECHECK_LOOPEND("material"); - ParseHelper_Node_Exit(); - } - else - { + } + ParseHelper_Node_Exit(); + } else { mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element } @@ -183,51 +157,41 @@ void AMFImporter::ParseNode_Material() { // then layer by layer. // Multi elements - Yes. // Parent element - . -void AMFImporter::ParseNode_Texture() -{ - std::string id; - uint32_t width = 0; - uint32_t height = 0; - uint32_t depth = 1; - std::string type; - bool tiled = false; - std::string enc64_data; +void AMFImporter::ParseNode_Texture(XmlNode &node) { + std::string id = node.attribute("id").as_string(); + uint32_t width = node.attribute("width").as_uint(); + uint32_t height = node.attribute("height").as_uint(); + uint32_t depth = node.attribute("depth").as_uint(); + std::string type = node.attribute("type").as_string(); + bool tiled = node.attribute("tiled").as_bool(); - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("width", width, XML_ReadNode_GetAttrVal_AsU32); - MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsU32); - MACRO_ATTRREAD_CHECK_RET("depth", depth, XML_ReadNode_GetAttrVal_AsU32); - MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("tiled", tiled, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_LOOPEND; - - // create new texture object. - CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur); - - CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience - - // Check for child nodes - if (!mReader->isEmptyElement()) { - XML_ReadNode_GetVal_AsString(enc64_data); + if (node.empty()) { + return; } + // create new texture object. + AMFNodeElementBase *ne = new AMFTexture(mNodeElement_Cur); + + AMFTexture& als = *((AMFTexture*)ne);// alias for convenience + + std::string enc64_data = node.value(); + // Check for child nodes + // check that all components was defined if (id.empty()) { - throw DeadlyImportError("ID for texture must be defined."); + throw DeadlyImportError("ID for texture must be defined."); } if (width < 1) { - Throw_IncorrectAttrValue("width"); + throw DeadlyImportError("INvalid width for texture."); } if (height < 1) { - Throw_IncorrectAttrValue("height"); - } + throw DeadlyImportError("Invalid height for texture."); + } if (depth < 1) { - Throw_IncorrectAttrValue("depth"); + throw DeadlyImportError("Invalid depth for texture."); } if (type != "grayscale") { - Throw_IncorrectAttrValue("type"); + throw DeadlyImportError("Invalid type for texture."); } if (enc64_data.empty()) { throw DeadlyImportError("Texture data not defined."); @@ -263,57 +227,94 @@ void AMFImporter::ParseNode_Texture() // , , , , , . Old name: , , , , , . // Multi elements - No. // Texture coordinates for every vertex of triangle. -void AMFImporter::ParseNode_TexMap(const bool pUseOldName) { - std::string rtexid, gtexid, btexid, atexid; - +void AMFImporter::ParseNode_TexMap(XmlNode &node, const bool pUseOldName) { // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("rtexid", rtexid, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("gtexid", gtexid, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("btexid", btexid, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("atexid", atexid, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; + AMFNodeElementBase *ne = new AMFTexMap(mNodeElement_Cur); + AMFTexMap &als = *((AMFTexMap *)ne); // + std::string rtexid, gtexid, btexid, atexid; + if (!node.empty()) { + ParseHelper_Node_Enter(ne); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "rtexid") { + XmlParser::getValueAsString(node, rtexid); + } else if (currentName == "gtexid") { + XmlParser::getValueAsString(node, gtexid); + } else if (currentName == "btexid") { + XmlParser::getValueAsString(node, btexid); + } else if (currentName == "atexid") { + XmlParser::getValueAsString(node, atexid); + } + } + ParseHelper_Node_Exit(); + } - // create new texture coordinates object. - CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur); - - CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience + // create new texture coordinates object, alias for convenience // check data - if(rtexid.empty() && gtexid.empty() && btexid.empty()) throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined."); + if (rtexid.empty() && gtexid.empty() && btexid.empty()) { + throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined."); + } + // Check for children nodes - XML_CheckNode_MustHaveChildren(); + //XML_CheckNode_MustHaveChildren(); + if (node.children().begin() == node.children().end()) { + throw DeadlyImportError("Invalid children definition."); + } // read children nodes bool read_flag[6] = { false, false, false, false, false, false }; - ParseHelper_Node_Enter(ne); - if(!pUseOldName) - { - MACRO_NODECHECK_LOOPBEGIN("texmap"); - MACRO_NODECHECK_READCOMP_F("utex1", read_flag[0], als.TextureCoordinate[0].x); - MACRO_NODECHECK_READCOMP_F("utex2", read_flag[1], als.TextureCoordinate[1].x); - MACRO_NODECHECK_READCOMP_F("utex3", read_flag[2], als.TextureCoordinate[2].x); - MACRO_NODECHECK_READCOMP_F("vtex1", read_flag[3], als.TextureCoordinate[0].y); - MACRO_NODECHECK_READCOMP_F("vtex2", read_flag[4], als.TextureCoordinate[1].y); - MACRO_NODECHECK_READCOMP_F("vtex3", read_flag[5], als.TextureCoordinate[2].y); - MACRO_NODECHECK_LOOPEND("texmap"); + if (!pUseOldName) { + for (pugi::xml_attribute &attr : node.attributes()) { + const std::string name = attr.name(); + if (name == "utex1") { + read_flag[0] = true; + als.TextureCoordinate[0].x = attr.as_float(); + } else if (name == "utex2") { + read_flag[1] = true; + als.TextureCoordinate[1].x = attr.as_float(); + } else if (name == "utex3") { + read_flag[2] = true; + als.TextureCoordinate[2].x = attr.as_float(); + } else if (name == "vtex1") { + read_flag[3] = true; + als.TextureCoordinate[0].y = attr.as_float(); + } else if (name == "vtex2") { + read_flag[4] = true; + als.TextureCoordinate[1].y = attr.as_float(); + } else if (name == "vtex3") { + read_flag[5] = true; + als.TextureCoordinate[0].y = attr.as_float(); + } + } + } else { + for (pugi::xml_attribute &attr : node.attributes()) { + const std::string name = attr.name(); + if (name == "u") { + read_flag[0] = true; + als.TextureCoordinate[0].x = attr.as_float(); + } else if (name == "u2") { + read_flag[1] = true; + als.TextureCoordinate[1].x = attr.as_float(); + } else if (name == "u3") { + read_flag[2] = true; + als.TextureCoordinate[2].x = attr.as_float(); + } else if (name == "v1") { + read_flag[3] = true; + als.TextureCoordinate[0].y = attr.as_float(); + } else if (name == "v2") { + read_flag[4] = true; + als.TextureCoordinate[1].y = attr.as_float(); + } else if (name == "v3") { + read_flag[5] = true; + als.TextureCoordinate[0].y = attr.as_float(); + } + } } - else - { - MACRO_NODECHECK_LOOPBEGIN("map"); - MACRO_NODECHECK_READCOMP_F("u1", read_flag[0], als.TextureCoordinate[0].x); - MACRO_NODECHECK_READCOMP_F("u2", read_flag[1], als.TextureCoordinate[1].x); - MACRO_NODECHECK_READCOMP_F("u3", read_flag[2], als.TextureCoordinate[2].x); - MACRO_NODECHECK_READCOMP_F("v1", read_flag[3], als.TextureCoordinate[0].y); - MACRO_NODECHECK_READCOMP_F("v2", read_flag[4], als.TextureCoordinate[1].y); - MACRO_NODECHECK_READCOMP_F("v3", read_flag[5], als.TextureCoordinate[2].y); - MACRO_NODECHECK_LOOPEND("map"); - }// if(!pUseOldName) else - - ParseHelper_Node_Exit(); // check that all components was defined - if(!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) + if (!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) { throw DeadlyImportError("Not all texture coordinates are defined."); + } // copy attributes data als.TextureID_R = rtexid; @@ -321,7 +322,7 @@ void AMFImporter::ParseNode_TexMap(const bool pUseOldName) { als.TextureID_B = btexid; als.TextureID_A = atexid; - mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph. + mNodeElement_List.push_back(ne); } }// namespace Assimp diff --git a/code/AssetLib/AMF/AMFImporter_Node.hpp b/code/AssetLib/AMF/AMFImporter_Node.hpp new file mode 100644 index 000000000..81e0312b6 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Node.hpp @@ -0,0 +1,306 @@ +/* +--------------------------------------------------------------------------- +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 AMFImporter_Node.hpp +/// \brief Elements of scene graph. +/// \date 2016 +/// \author smal.root@gmail.com + +#pragma once +#ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H +#define INCLUDED_AI_AMF_IMPORTER_NODE_H + +// Header files, stdlib. +#include +#include +#include + +// Header files, Assimp. +#include "assimp/scene.h" +#include "assimp/types.h" + +/// \class CAMFImporter_NodeElement +/// Base class for elements of nodes. +class AMFNodeElementBase { +public: + /// Define what data type contain node element. + enum EType { + ENET_Color, ///< Color element: . + ENET_Constellation, ///< Grouping element: . + ENET_Coordinates, ///< Coordinates element: . + ENET_Edge, ///< Edge element: . + ENET_Instance, ///< Grouping element: . + ENET_Material, ///< Material element: . + ENET_Metadata, ///< Metadata element: . + ENET_Mesh, ///< Metadata element: . + ENET_Object, ///< Element which hold object: . + ENET_Root, ///< Root element: . + ENET_Triangle, ///< Triangle element: . + ENET_TexMap, ///< Texture coordinates element: or . + ENET_Texture, ///< Texture element: . + ENET_Vertex, ///< Vertex element: . + ENET_Vertices, ///< Vertex element: . + ENET_Volume, ///< Volume element: . + + ENET_Invalid ///< Element has invalid type and possible contain invalid data. + }; + + const EType Type; ///< Type of element. + std::string ID; ///< ID of element. + AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root. + std::list Child; ///< Child elements. + +public: /// Destructor, virtual.. + virtual ~AMFNodeElementBase() { + // empty + } + + /// Disabled copy constructor and co. + AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete; + AMFNodeElementBase(AMFNodeElementBase &&) = delete; + AMFNodeElementBase &operator=(const AMFNodeElementBase &pNodeElement) = delete; + AMFNodeElementBase() = delete; + +protected: + /// In constructor inheritor must set element type. + /// \param [in] pType - element type. + /// \param [in] pParent - parent element. + AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) : + Type(pType), ID(), Parent(pParent), Child() { + // empty + } +}; // class IAMFImporter_NodeElement + +/// \struct CAMFImporter_NodeElement_Constellation +/// A collection of objects or constellations with specific relative locations. +struct AMFConstellation : public AMFNodeElementBase { + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFConstellation(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Constellation, pParent) {} + +}; // struct CAMFImporter_NodeElement_Constellation + +/// \struct CAMFImporter_NodeElement_Instance +/// Part of constellation. +struct AMFInstance : public AMFNodeElementBase { + + std::string ObjectID; ///< ID of object for instantiation. + /// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to + /// create an instance of the object in the current constellation. + aiVector3D Delta; + + /// \var Rotation - The rotation, in degrees, to rotate the referenced object about its x, y, and z axes, respectively, to create an + /// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z. + aiVector3D Rotation; + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFInstance(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Instance, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Metadata +/// Structure that define metadata node. +struct AMFMetadata : public AMFNodeElementBase { + + std::string Type; ///< Type of "Value". + std::string Value; ///< Value. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFMetadata(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Metadata, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Root +/// Structure that define root node. +struct AMFRoot : public AMFNodeElementBase { + + std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron". + std::string Version; ///< Version of format. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFRoot(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Root, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Color +/// Structure that define object node. +struct AMFColor : public AMFNodeElementBase { + bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. + std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA. + aiColor4D Color; ///< Constant color. + std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b.. + + /// @brief Constructor. + /// @param [in] pParent - pointer to parent node. + AMFColor(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() { + // empty + } +}; + +/// \struct CAMFImporter_NodeElement_Material +/// Structure that define material node. +struct AMFMaterial : public AMFNodeElementBase { + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFMaterial(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Material, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Object +/// Structure that define object node. +struct AMFObject : public AMFNodeElementBase { + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFObject(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Object, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Mesh +/// Structure that define mesh node. +struct AMFMesh : public AMFNodeElementBase { + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFMesh(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Mesh, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Vertex +/// Structure that define vertex node. +struct AMFVertex : public AMFNodeElementBase { + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFVertex(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Vertex, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Edge +/// Structure that define edge node. +struct AMFEdge : public AMFNodeElementBase { + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFEdge(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Edge, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Vertices +/// Structure that define vertices node. +struct AMFVertices : public AMFNodeElementBase { + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFVertices(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Vertices, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Volume +/// Structure that define volume node. +struct AMFVolume : public AMFNodeElementBase { + std::string MaterialID; ///< Which material to use. + std::string Type; ///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFVolume(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Volume, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_Coordinates +/// Structure that define coordinates node. +struct AMFCoordinates : public AMFNodeElementBase { + aiVector3D Coordinate; ///< Coordinate. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFCoordinates(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Coordinates, pParent) {} +}; + +/// \struct CAMFImporter_NodeElement_TexMap +/// Structure that define texture coordinates node. +struct AMFTexMap : public AMFNodeElementBase { + aiVector3D TextureCoordinate[3]; ///< Texture coordinates. + std::string TextureID_R; ///< Texture ID for red color component. + std::string TextureID_G; ///< Texture ID for green color component. + std::string TextureID_B; ///< Texture ID for blue color component. + std::string TextureID_A; ///< Texture ID for alpha color component. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFTexMap(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() { + // empty + } +}; + +/// \struct CAMFImporter_NodeElement_Triangle +/// Structure that define triangle node. +struct AMFTriangle : public AMFNodeElementBase { + size_t V[3]; ///< Triangle vertices. + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFTriangle(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Triangle, pParent) { + // empty + } +}; + +/// Structure that define texture node. +struct AMFTexture : public AMFNodeElementBase { + size_t Width, Height, Depth; ///< Size of the texture. + std::vector Data; ///< Data of the texture. + bool Tiled; + + /// Constructor. + /// \param [in] pParent - pointer to parent node. + AMFTexture(AMFNodeElementBase *pParent) : + AMFNodeElementBase(ENET_Texture, pParent), Width(0), Height(0), Depth(0), Data(), Tiled(false) { + // empty + } +}; + +#endif // INCLUDED_AI_AMF_IMPORTER_NODE_H diff --git a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp new file mode 100644 index 000000000..98151d1c0 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp @@ -0,0 +1,892 @@ +/* +--------------------------------------------------------------------------- +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 AMFImporter_Postprocess.cpp +/// \brief Convert built scenegraph and objects to Assimp scenegraph. +/// \date 2016 +/// \author smal.root@gmail.com + +#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER + +#include "AMFImporter.hpp" + +#include +#include +#include + +#include + +namespace Assimp { + +aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const { + aiColor4D tcol; + + // Check if stored data are supported. + if (!Composition.empty()) { + throw DeadlyImportError("IME. GetColor for composition"); + } else if (Color->Composed) { + throw DeadlyImportError("IME. GetColor, composed color"); + } else { + tcol = Color->Color; + } + + // Check if default color must be used + if ((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) { + tcol.r = 0.5f; + tcol.g = 0.5f; + tcol.b = 0.5f; + tcol.a = 1; + } + + return tcol; +} + +void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector &pVertexCoordinateArray, + std::vector &pVertexColorArray) const { + AMFVertices *vn = nullptr; + size_t col_idx; + + // All data stored in "vertices", search for it. + for (AMFNodeElementBase *ne_child : pNodeElement.Child) { + if (ne_child->Type == AMFNodeElementBase::ENET_Vertices) { + vn = (AMFVertices*)ne_child; + } + } + + // If "vertices" not found then no work for us. + if (vn == nullptr) { + return; + } + + // all coordinates stored as child and we need to reserve space for future push_back's. + pVertexCoordinateArray.reserve(vn->Child.size()); + + // colors count equal vertices count. + pVertexColorArray.resize(vn->Child.size()); + col_idx = 0; + + // Inside vertices collect all data and place to arrays + for (AMFNodeElementBase *vn_child : vn->Child) { + // vertices, colors + if (vn_child->Type == AMFNodeElementBase::ENET_Vertex) { + // by default clear color for current vertex + pVertexColorArray[col_idx] = nullptr; + + for (AMFNodeElementBase *vtx : vn_child->Child) { + if (vtx->Type == AMFNodeElementBase::ENET_Coordinates) { + pVertexCoordinateArray.push_back(((AMFCoordinates *)vtx)->Coordinate); + continue; + } + + if (vtx->Type == AMFNodeElementBase::ENET_Color) { + pVertexColorArray[col_idx] = (AMFColor *)vtx; + continue; + } + } + + ++col_idx; + } + } +} + +size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) { + if (r.empty() && g.empty() && b.empty() && a.empty()) { + throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined."); + } + + std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a; + size_t TextureConverted_Index = 0; + for (const SPP_Texture &tex_convd : mTexture_Converted) { + if (tex_convd.ID == TextureConverted_ID) { + return TextureConverted_Index; + } else { + ++TextureConverted_Index; + } + } + + // Converted texture not found, create it. + AMFTexture *src_texture[4] { + nullptr + }; + std::vector src_texture_4check; + SPP_Texture converted_texture; + + { // find all specified source textures + AMFNodeElementBase *t_tex = nullptr; + + // R + if (!r.empty()) { + if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) { + Throw_ID_NotFound(r); + } + + src_texture[0] = (AMFTexture *)t_tex; + src_texture_4check.push_back((AMFTexture *)t_tex); + } else { + src_texture[0] = nullptr; + } + + // G + if (!g.empty()) { + if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) { + Throw_ID_NotFound(g); + } + + src_texture[1] = (AMFTexture *)t_tex; + src_texture_4check.push_back((AMFTexture *)t_tex); + } else { + src_texture[1] = nullptr; + } + + // B + if (!b.empty()) { + if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) { + Throw_ID_NotFound(b); + } + + src_texture[2] = (AMFTexture *)t_tex; + src_texture_4check.push_back((AMFTexture *)t_tex); + } else { + src_texture[2] = nullptr; + } + + // A + if (!a.empty()) { + if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) { + Throw_ID_NotFound(a); + } + + src_texture[3] = (AMFTexture *)t_tex; + src_texture_4check.push_back((AMFTexture *)t_tex); + } else { + src_texture[3] = nullptr; + } + } // END: find all specified source textures + + // check that all textures has same size + if (src_texture_4check.size() > 1) { + for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++) { + if ((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) || + (src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth)) { + throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size."); + } + } + } // if(src_texture_4check.size() > 1) + + // set texture attributes + converted_texture.Width = src_texture_4check[0]->Width; + converted_texture.Height = src_texture_4check[0]->Height; + converted_texture.Depth = src_texture_4check[0]->Depth; + // if one of source texture is tiled then converted texture is tiled too. + converted_texture.Tiled = false; + for (uint8_t i = 0; i < src_texture_4check.size(); ++i) { + converted_texture.Tiled |= src_texture_4check[i]->Tiled; + } + + // Create format hint. + strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string. + if (!r.empty()) converted_texture.FormatHint[4] = '8'; + if (!g.empty()) converted_texture.FormatHint[5] = '8'; + if (!b.empty()) converted_texture.FormatHint[6] = '8'; + if (!a.empty()) converted_texture.FormatHint[7] = '8'; + + // Сopy data of textures. + size_t tex_size = 0; + size_t step = 0; + size_t off_g = 0; + size_t off_b = 0; + + // Calculate size of the target array and rule how data will be copied. + if (!r.empty() && nullptr != src_texture[0]) { + tex_size += src_texture[0]->Data.size(); + step++, off_g++, off_b++; + } + if (!g.empty() && nullptr != src_texture[1]) { + tex_size += src_texture[1]->Data.size(); + step++, off_b++; + } + if (!b.empty() && nullptr != src_texture[2]) { + tex_size += src_texture[2]->Data.size(); + step++; + } + if (!a.empty() && nullptr != src_texture[3]) { + tex_size += src_texture[3]->Data.size(); + step++; + } + + // Create target array. + converted_texture.Data = new uint8_t[tex_size]; + // And copy data + auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void { + if (!pID.empty()) { + for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) { + AMFTexture *tex = src_texture[pSrcTexNum]; + ai_assert(tex); + converted_texture.Data[idx_target] = tex->Data.at(idx_src); + } + } + }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void + + CopyTextureData(r, 0, step, 0); + CopyTextureData(g, off_g, step, 1); + CopyTextureData(b, off_b, step, 2); + CopyTextureData(a, step - 1, step, 3); + + // Store new converted texture ID + converted_texture.ID = TextureConverted_ID; + // Store new converted texture + mTexture_Converted.push_back(converted_texture); + + return TextureConverted_Index; +} + +void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list &pInputList, std::list> &pOutputList_Separated) { + auto texmap_is_equal = [](const AMFTexMap *pTexMap1, const AMFTexMap *pTexMap2) -> bool { + if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true; + if (pTexMap1 == nullptr) return false; + if (pTexMap2 == nullptr) return false; + + if (pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false; + if (pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false; + if (pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false; + if (pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false; + + return true; + }; + + pOutputList_Separated.clear(); + if (pInputList.empty()) return; + + do { + SComplexFace face_start = pInputList.front(); + std::list face_list_cur; + + for (std::list::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;) { + if (texmap_is_equal(face_start.TexMap, it->TexMap)) { + auto it_old = it; + + ++it; + face_list_cur.push_back(*it_old); + pInputList.erase(it_old); + } else { + ++it; + } + } + + if (!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur); + + } while (!pInputList.empty()); +} + +void AMFImporter::Postprocess_AddMetadata(const AMFMetaDataArray &metadataList, aiNode &sceneNode) const { + if (metadataList.empty()) { + return; + } + + if (sceneNode.mMetaData != nullptr) { + throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong."); + } + + // copy collected metadata to output node. + sceneNode.mMetaData = aiMetadata::Alloc(static_cast(metadataList.size())); + size_t meta_idx(0); + + for (const AMFMetadata &metadata : metadataList) { + sceneNode.mMetaData->Set(static_cast(meta_idx++), metadata.Type, aiString(metadata.Value)); + } +} + +void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode) { + AMFColor *object_color = nullptr; + + // create new aiNode and set name as has. + *pSceneNode = new aiNode; + (*pSceneNode)->mName = pNodeElement.ID; + // read mesh and color + for (const AMFNodeElementBase *ne_child : pNodeElement.Child) { + std::vector vertex_arr; + std::vector color_arr; + + // color for object + if (ne_child->Type == AMFNodeElementBase::ENET_Color) { + object_color = (AMFColor *) ne_child; + } + + if (ne_child->Type == AMFNodeElementBase::ENET_Mesh) { + // Create arrays from children of mesh: vertices. + PostprocessHelper_CreateMeshDataArray(*((AMFMesh *)ne_child), vertex_arr, color_arr); + // Use this arrays as a source when creating every aiMesh + Postprocess_BuildMeshSet(*((AMFMesh *)ne_child), vertex_arr, color_arr, object_color, meshList, **pSceneNode); + } + } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement) +} + +void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector &pVertexCoordinateArray, + const std::vector &pVertexColorArray, const AMFColor *pObjectColor, MeshArray &pMeshList, aiNode &pSceneNode) { + std::list mesh_idx; + + // all data stored in "volume", search for it. + for (const AMFNodeElementBase *ne_child : pNodeElement.Child) { + const AMFColor *ne_volume_color = nullptr; + const SPP_Material *cur_mat = nullptr; + + if (ne_child->Type == AMFNodeElementBase::ENET_Volume) { + /******************* Get faces *******************/ + const AMFVolume *ne_volume = reinterpret_cast(ne_child); + + std::list complex_faces_list; // List of the faces of the volume. + std::list> complex_faces_toplist; // List of the face list for every mesh. + + // check if volume use material + if (!ne_volume->MaterialID.empty()) { + if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) { + Throw_ID_NotFound(ne_volume->MaterialID); + } + } + + // inside "volume" collect all data and place to arrays or create new objects + for (const AMFNodeElementBase *ne_volume_child : ne_volume->Child) { + // color for volume + if (ne_volume_child->Type == AMFNodeElementBase::ENET_Color) { + ne_volume_color = reinterpret_cast(ne_volume_child); + } else if (ne_volume_child->Type == AMFNodeElementBase::ENET_Triangle) // triangles, triangles colors + { + const AMFTriangle &tri_al = *reinterpret_cast(ne_volume_child); + + SComplexFace complex_face; + + // initialize pointers + complex_face.Color = nullptr; + complex_face.TexMap = nullptr; + // get data from triangle children: color, texture coordinates. + if (tri_al.Child.size()) { + for (const AMFNodeElementBase *ne_triangle_child : tri_al.Child) { + if (ne_triangle_child->Type == AMFNodeElementBase::ENET_Color) + complex_face.Color = reinterpret_cast(ne_triangle_child); + else if (ne_triangle_child->Type == AMFNodeElementBase::ENET_TexMap) + complex_face.TexMap = reinterpret_cast(ne_triangle_child); + } + } // if(tri_al.Child.size()) + + // create new face and store it. + complex_face.Face.mNumIndices = 3; + complex_face.Face.mIndices = new unsigned int[3]; + complex_face.Face.mIndices[0] = static_cast(tri_al.V[0]); + complex_face.Face.mIndices[1] = static_cast(tri_al.V[1]); + complex_face.Face.mIndices[2] = static_cast(tri_al.V[2]); + complex_faces_list.push_back(complex_face); + } + } // for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child) + + /**** Split faces list: one list per mesh ****/ + PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist); + + /***** Create mesh for every faces list ******/ + for (std::list &face_list_cur : complex_faces_toplist) { + auto VertexIndex_GetMinimal = [](const std::list &pFaceList, const size_t *pBiggerThan) -> size_t { + size_t rv = 0; + + if (pBiggerThan != nullptr) { + bool found = false; + + for (const SComplexFace &face : pFaceList) { + for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) { + if (face.Face.mIndices[idx_vert] > *pBiggerThan) { + rv = face.Face.mIndices[idx_vert]; + found = true; + break; + } + } + + if (found) { + break; + } + } + + if (!found) { + return *pBiggerThan; + } + } else { + rv = pFaceList.front().Face.mIndices[0]; + } // if(pBiggerThan != nullptr) else + + for (const SComplexFace &face : pFaceList) { + for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) { + if (face.Face.mIndices[vi] < rv) { + if (pBiggerThan != nullptr) { + if (face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi]; + } else { + rv = face.Face.mIndices[vi]; + } + } + } + } // for(const SComplexFace& face: pFaceList) + + return rv; + }; // auto VertexIndex_GetMinimal = [](const std::list& pFaceList, const size_t* pBiggerThan) -> size_t + + auto VertexIndex_Replace = [](std::list &pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void { + for (const SComplexFace &face : pFaceList) { + for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) { + if (face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast(pIdx_To); + } + } + }; // auto VertexIndex_Replace = [](std::list& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void + + auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D { + // Color priorities(In descending order): + // 1. triangle color; + // 2. vertex color; + // 3. volume color; + // 4. object color; + // 5. material; + // 6. default - invisible coat. + // + // Fill vertices colors in color priority list above that's points from 1 to 6. + if ((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr)) // check for vertex color + { + if (pVertexColorArray[pIdx]->Composed) + throw DeadlyImportError("IME: vertex color composed"); + else + return pVertexColorArray[pIdx]->Color; + } else if (ne_volume_color != nullptr) // check for volume color + { + if (ne_volume_color->Composed) + throw DeadlyImportError("IME: volume color composed"); + else + return ne_volume_color->Color; + } else if (pObjectColor != nullptr) // check for object color + { + if (pObjectColor->Composed) + throw DeadlyImportError("IME: object color composed"); + else + return pObjectColor->Color; + } else if (cur_mat != nullptr) // check for material + { + return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z); + } else // set default color. + { + return { 0, 0, 0, 0 }; + } // if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else + }; // auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D + + aiMesh *tmesh = new aiMesh; + + tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // Only triangles is supported by AMF. + // + // set geometry and colors (vertices) + // + // copy faces/triangles + tmesh->mNumFaces = static_cast(face_list_cur.size()); + tmesh->mFaces = new aiFace[tmesh->mNumFaces]; + + // Create vertices list and optimize indices. Optimization mean following.In AMF all volumes use one big list of vertices. And one volume + // can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10. + // Do you need all this thousands of garbage? Of course no. So, optimization step transform sparse indices set to continuous. + size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles. + std::vector vert_arr, texcoord_arr; + std::vector col_arr; + + vert_arr.reserve(VertexCount_Max * 2); // "* 2" - see below TODO. + col_arr.reserve(VertexCount_Max * 2); + + { // fill arrays + size_t vert_idx_from, vert_idx_to; + + // first iteration. + vert_idx_to = 0; + vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr); + vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from)); + col_arr.push_back(Vertex_CalculateColor(vert_idx_from)); + if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to); + + // rest iterations + do { + vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to); + if (vert_idx_from == vert_idx_to) break; // all indices are transferred, + + vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from)); + col_arr.push_back(Vertex_CalculateColor(vert_idx_from)); + vert_idx_to++; + if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to); + + } while (true); + } // fill arrays. END. + + // + // check if triangle colors are used and create additional faces if needed. + // + for (const SComplexFace &face_cur : face_list_cur) { + if (face_cur.Color != nullptr) { + aiColor4D face_color; + size_t vert_idx_new = vert_arr.size(); + + if (face_cur.Color->Composed) + throw DeadlyImportError("IME: face color composed"); + else + face_color = face_cur.Color->Color; + + for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) { + vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind])); + col_arr.push_back(face_color); + face_cur.Face.mIndices[idx_ind] = static_cast(vert_idx_new++); + } + } // if(face_cur.Color != nullptr) + } // for(const SComplexFace& face_cur: face_list_cur) + + // + // if texture is used then copy texture coordinates too. + // + if (face_list_cur.front().TexMap != nullptr) { + size_t idx_vert_new = vert_arr.size(); + ///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for + /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about + /// optimization. + bool *idx_vert_used; + + idx_vert_used = new bool[VertexCount_Max * 2]; + for (size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++) + idx_vert_used[i] = false; + + // This ID's will be used when set materials ID in scene. + tmesh->mMaterialIndex = static_cast(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R, + face_list_cur.front().TexMap->TextureID_G, + face_list_cur.front().TexMap->TextureID_B, + face_list_cur.front().TexMap->TextureID_A)); + texcoord_arr.resize(VertexCount_Max * 2); + for (const SComplexFace &face_cur : face_list_cur) { + for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) { + const size_t idx_vert = face_cur.Face.mIndices[idx_ind]; + + if (!idx_vert_used[idx_vert]) { + texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind]; + idx_vert_used[idx_vert] = true; + } else if (texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind]) { + // in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture + // coordinates. + vert_arr.push_back(vert_arr.at(idx_vert)); + col_arr.push_back(col_arr.at(idx_vert)); + texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind]; + face_cur.Face.mIndices[idx_ind] = static_cast(idx_vert_new++); + } + } // for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) + } // for(const SComplexFace& face_cur: face_list_cur) + + delete[] idx_vert_used; + // shrink array + texcoord_arr.resize(idx_vert_new); + } // if(face_list_cur.front().TexMap != nullptr) + + // + // copy collected data to mesh + // + tmesh->mNumVertices = static_cast(vert_arr.size()); + tmesh->mVertices = new aiVector3D[tmesh->mNumVertices]; + tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices]; + + memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D)); + memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D)); + if (texcoord_arr.size() > 0) { + tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices]; + memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D)); + tmesh->mNumUVComponents[0] = 2; // U and V stored in "x", "y" of aiVector3D. + } + + size_t idx_face = 0; + for (const SComplexFace &face_cur : face_list_cur) + tmesh->mFaces[idx_face++] = face_cur.Face; + + // store new aiMesh + mesh_idx.push_back(static_cast(pMeshList.size())); + pMeshList.push_back(tmesh); + } // for(const std::list& face_list_cur: complex_faces_toplist) + } // if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) + } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) + + // if meshes was created then assign new indices with current aiNode + if (!mesh_idx.empty()) { + std::list::const_iterator mit = mesh_idx.begin(); + + pSceneNode.mNumMeshes = static_cast(mesh_idx.size()); + pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes]; + for (size_t i = 0; i < pSceneNode.mNumMeshes; i++) + pSceneNode.mMeshes[i] = *mit++; + } // if(mesh_idx.size() > 0) +} + +void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial &pMaterial) { + SPP_Material new_mat; + + new_mat.ID = pMaterial.ID; + for (const AMFNodeElementBase *mat_child : pMaterial.Child) { + if (mat_child->Type == AMFNodeElementBase::ENET_Color) { + new_mat.Color = (AMFColor*)mat_child; + } else if (mat_child->Type == AMFNodeElementBase::ENET_Metadata) { + new_mat.Metadata.push_back((AMFMetadata *)mat_child); + } + } // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child) + + // place converted material to special list + mMaterial_Converted.push_back(new_mat); +} + +void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const { + aiNode *con_node; + std::list ch_node; + + // We will build next hierarchy: + // aiNode as parent () for set of nodes as a children + // |- aiNode for transformation ( -> , ) - aiNode for pointing to object ("objectid") + // ... + // \_ aiNode for transformation ( -> , ) - aiNode for pointing to object ("objectid") + con_node = new aiNode; + con_node->mName = pConstellation.ID; + // Walk through children and search for instances of another objects, constellations. + for (const AMFNodeElementBase *ne : pConstellation.Child) { + aiMatrix4x4 tmat; + aiNode *t_node; + aiNode *found_node; + + if (ne->Type == AMFNodeElementBase::ENET_Metadata) continue; + if (ne->Type != AMFNodeElementBase::ENET_Instance) throw DeadlyImportError("Only nodes can be in ."); + + // create alias for conveniance + AMFInstance &als = *((AMFInstance *)ne); + // find referenced object + if (!Find_ConvertedNode(als.ObjectID, nodeArray, &found_node)) Throw_ID_NotFound(als.ObjectID); + + // create node for applying transformation + t_node = new aiNode; + t_node->mParent = con_node; + // apply transformation + aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat; + aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat; + aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat; + aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat; + // create array for one child node + t_node->mNumChildren = 1; + t_node->mChildren = new aiNode *[t_node->mNumChildren]; + SceneCombiner::Copy(&t_node->mChildren[0], found_node); + t_node->mChildren[0]->mParent = t_node; + ch_node.push_back(t_node); + } // for(const CAMFImporter_NodeElement* ne: pConstellation.Child) + + // copy found aiNode's as children + if (ch_node.empty()) throw DeadlyImportError(" must have at least one ."); + + size_t ch_idx = 0; + + con_node->mNumChildren = static_cast(ch_node.size()); + con_node->mChildren = new aiNode *[con_node->mNumChildren]; + for (aiNode *node : ch_node) + con_node->mChildren[ch_idx++] = node; + + // and place "root" of node to node list + nodeArray.push_back(con_node); +} + +void AMFImporter::Postprocess_BuildScene(aiScene *pScene) { + NodeArray nodeArray; + MeshArray mesh_list; + AMFMetaDataArray meta_list; + + // + // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used. + // For building aiScene we are must to do few steps: + // 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() element + AMFNodeElementBase *root_el = nullptr; + + for (AMFNodeElementBase *ne : mNodeElement_List) { + if (ne->Type != AMFNodeElementBase::ENET_Root) { + continue; + } + + root_el = ne; + break; + } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List) + + // Check if root element are found. + if (root_el == nullptr) { + throw DeadlyImportError("Root() element not found."); + } + + // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in : , , , + // and . But at first we must read and because they will be used in . can be read + // at any moment. + // + // 1. + // 2. will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet + for (const AMFNodeElementBase *root_child : root_el->Child) { + if (root_child->Type == AMFNodeElementBase::ENET_Material) { + Postprocess_BuildMaterial(*((AMFMaterial *)root_child)); + } + } + + // After "appearance" nodes we must read because it will be used in -> . + // + // 3. + for (const AMFNodeElementBase *root_child : root_el->Child) { + if (root_child->Type == AMFNodeElementBase::ENET_Object) { + aiNode *tnode = nullptr; + + // for mesh and node must be built: object ID assigned to aiNode name and will be used in future for + Postprocess_BuildNodeAndObject(*((AMFObject *)root_child), mesh_list, &tnode); + if (tnode != nullptr) { + nodeArray.push_back(tnode); + } + } + } // for(const CAMFImporter_NodeElement* root_child: root_el->Child) + + // And finally read rest of nodes. + // + for (const AMFNodeElementBase *root_child : root_el->Child) { + // 4. + if (root_child->Type == AMFNodeElementBase::ENET_Constellation) { + // and at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's. + Postprocess_BuildConstellation(*((AMFConstellation *)root_child), nodeArray); + } + + // 5, + if (root_child->Type == AMFNodeElementBase::ENET_Metadata) meta_list.push_back((AMFMetadata *)root_child); + } // for(const CAMFImporter_NodeElement* root_child: root_el->Child) + + // at now we can add collected metadata to root node + Postprocess_AddMetadata(meta_list, *pScene->mRootNode); + // + // Check constellation children + // + // As said in specification: + // "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing." + // What that means? For example: if some object is used in constellation then you must show only constellation but not original object. + // And at this step we are checking that relations. +nl_clean_loop: + + if (nodeArray.size() > 1) { + // walk through all nodes + for (NodeArray::iterator nl_it = nodeArray.begin(); nl_it != nodeArray.end(); ++nl_it) { + // and try to find them in another top nodes. + NodeArray::const_iterator next_it = nl_it; + + ++next_it; + for (; next_it != nodeArray.end(); ++next_it) { + if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) { + // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop. + nodeArray.erase(nl_it); + + goto nl_clean_loop; + } + } // for(; next_it != node_list.end(); next_it++) + } // for(std::list::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++) + } + + // + // move created objects to aiScene + // + // + // Nodes + if (!nodeArray.empty()) { + NodeArray::const_iterator nl_it = nodeArray.begin(); + + pScene->mRootNode->mNumChildren = static_cast(nodeArray.size()); + pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; + for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) { + // Objects and constellation that must be showed placed at top of hierarchy in node. So all aiNode's in node_list must have + // mRootNode only as parent. + (*nl_it)->mParent = pScene->mRootNode; + pScene->mRootNode->mChildren[i] = *nl_it++; + } + } // if(node_list.size() > 0) + + // + // Meshes + if (!mesh_list.empty()) { + MeshArray::const_iterator ml_it = mesh_list.begin(); + + pScene->mNumMeshes = static_cast(mesh_list.size()); + pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; + for (size_t i = 0; i < pScene->mNumMeshes; i++) + pScene->mMeshes[i] = *ml_it++; + } // if(mesh_list.size() > 0) + + // + // Textures + pScene->mNumTextures = static_cast(mTexture_Converted.size()); + if (pScene->mNumTextures > 0) { + size_t idx; + + idx = 0; + pScene->mTextures = new aiTexture *[pScene->mNumTextures]; + for (const SPP_Texture &tex_convd : mTexture_Converted) { + pScene->mTextures[idx] = new aiTexture; + pScene->mTextures[idx]->mWidth = static_cast(tex_convd.Width); + pScene->mTextures[idx]->mHeight = static_cast(tex_convd.Height); + pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data; + // texture format description. + strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint); + idx++; + } // for(const SPP_Texture& tex_convd: mTexture_Converted) + + // Create materials for embedded textures. + idx = 0; + pScene->mNumMaterials = static_cast(mTexture_Converted.size()); + pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; + for (const SPP_Texture &tex_convd : mTexture_Converted) { + const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx)); + const int mode = aiTextureOp_Multiply; + const int repeat = tex_convd.Tiled ? 1 : 0; + + pScene->mMaterials[idx] = new aiMaterial; + pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0)); + pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0)); + pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); + pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); + idx++; + } + } // if(pScene->mNumTextures > 0) +} // END: after that walk through children of root and collect data + +} // namespace Assimp + +#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER diff --git a/code/ASE/ASELoader.cpp b/code/AssetLib/ASE/ASELoader.cpp similarity index 64% rename from code/ASE/ASELoader.cpp rename to code/AssetLib/ASE/ASELoader.cpp index b2155d5e5..057272c91 100644 --- a/code/ASE/ASELoader.cpp +++ b/code/AssetLib/ASE/ASELoader.cpp @@ -51,15 +51,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "ASELoader.h" -#include -#include #include "Common/TargetAnimation.h" +#include +#include -#include -#include -#include -#include #include +#include +#include +#include +#include #include @@ -84,12 +84,8 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ASEImporter::ASEImporter() -: mParser() -, mBuffer() -, pcScene() -, configRecomputeNormals() -, noSkeletonMesh() { +ASEImporter::ASEImporter() : + mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() { // empty } @@ -101,7 +97,7 @@ ASEImporter::~ASEImporter() { // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { +bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { // check file extension const std::string extension = GetExtension(pFile); @@ -110,41 +106,43 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool } if ((!extension.length() || cs) && pIOHandler) { - const char* tokens[] = {"*3dsmax_asciiexport"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + const char *tokens[] = { "*3dsmax_asciiexport" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); } return false; } // ------------------------------------------------------------------------------------------------ // Loader meta information -const aiImporterDesc* ASEImporter::GetInfo () const { +const aiImporterDesc *ASEImporter::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration options -void ASEImporter::SetupProperties(const Importer* pImp) { +void ASEImporter::SetupProperties(const Importer *pImp) { configRecomputeNormals = (pImp->GetPropertyInteger( - AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false); + AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS, 1) ? + true : + false); - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void ASEImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) { - std::unique_ptr file( pIOHandler->Open( pFile, "rb")); +void ASEImporter::InternReadFile(const std::string &pFile, + aiScene *pScene, IOSystem *pIOHandler) { + std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file - if( file.get() == nullptr) { - throw DeadlyImportError( "Failed to open ASE file " + pFile + "."); + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open ASE file ", pFile, "."); } // Allocate storage and copy the contents of the file to a memory buffer std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); + TextFileToBuffer(file.get(), mBuffer2); this->mBuffer = &mBuffer2[0]; this->pcScene = pScene; @@ -155,8 +153,8 @@ void ASEImporter::InternReadFile( const std::string& pFile, // ASE is the actual version 200 (that is currently written by max) // ------------------------------------------------------------------ unsigned int defaultFormat; - std::string::size_type s = pFile.length()-1; - switch (pFile.c_str()[s]) { + std::string::size_type s = pFile.length() - 1; + switch (pFile.c_str()[s]) { case 'C': case 'c': @@ -167,7 +165,7 @@ void ASEImporter::InternReadFile( const std::string& pFile, }; // Construct an ASE parser and parse the file - ASE::Parser parser(mBuffer,defaultFormat); + ASE::Parser parser(mBuffer, defaultFormat); mParser = &parser; mParser->Parse(); @@ -175,7 +173,7 @@ void ASEImporter::InternReadFile( const std::string& pFile, // Check whether we god at least one mesh. If we did - generate // materials and copy meshes. // ------------------------------------------------------------------ - if ( !mParser->m_vMeshes.empty()) { + if (!mParser->m_vMeshes.empty()) { // If absolutely no material has been loaded from the file // we need to generate a default material @@ -183,32 +181,32 @@ void ASEImporter::InternReadFile( const std::string& pFile, // process all meshes bool tookNormals = false; - std::vector avOutMeshes; - avOutMeshes.reserve(mParser->m_vMeshes.size()*2); - for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { + std::vector avOutMeshes; + avOutMeshes.reserve(mParser->m_vMeshes.size() * 2); + for (std::vector::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) { if ((*i).bSkip) { continue; } BuildUniqueRepresentation(*i); // Need to generate proper vertex normals if necessary - if(GenerateNormals(*i)) { + if (GenerateNormals(*i)) { tookNormals = true; } // Convert all meshes to aiMesh objects - ConvertMeshes(*i,avOutMeshes); + ConvertMeshes(*i, avOutMeshes); } - if (tookNormals) { + if (tookNormals) { ASSIMP_LOG_DEBUG("ASE: Taking normals from the file. Use " - "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " - "experience problems"); + "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " + "experience problems"); } // Now build the output mesh list. Remove dummies pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); - aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (std::vector::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) { + aiMesh **pp = pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; + for (std::vector::const_iterator i = avOutMeshes.begin(); i != avOutMeshes.end(); ++i) { if (!(*i)->mNumFaces) { continue; } @@ -225,18 +223,21 @@ void ASEImporter::InternReadFile( const std::string& pFile, // Copy all scene graph nodes - lights, cameras, dummies and meshes // into one huge list. //------------------------------------------------------------------ - std::vector nodes; - nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() - + mParser->m_vCameras.size() + mParser->m_vDummies.size()); + std::vector nodes; + nodes.reserve(mParser->m_vMeshes.size() + mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size()); // Lights - for (auto &light : mParser->m_vLights)nodes.push_back(&light); + for (auto &light : mParser->m_vLights) + nodes.push_back(&light); // Cameras - for (auto &camera : mParser->m_vCameras)nodes.push_back(&camera); + for (auto &camera : mParser->m_vCameras) + nodes.push_back(&camera); // Meshes - for (auto &mesh : mParser->m_vMeshes)nodes.push_back(&mesh); + for (auto &mesh : mParser->m_vMeshes) + nodes.push_back(&mesh); // Dummies - for (auto &dummy : mParser->m_vDummies)nodes.push_back(&dummy); + for (auto &dummy : mParser->m_vDummies) + nodes.push_back(&dummy); // build the final node graph BuildNodes(nodes); @@ -255,7 +256,7 @@ void ASEImporter::InternReadFile( const std::string& pFile, // to build a mesh for the animation skeleton // FIXME: very strange results // ------------------------------------------------------------------ - if (!pScene->mNumMeshes) { + if (!pScene->mNumMeshes) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; if (!noSkeletonMesh) { SkeletonMeshBuilder skeleton(pScene); @@ -263,82 +264,80 @@ void ASEImporter::InternReadFile( const std::string& pFile, } } // ------------------------------------------------------------------------------------------------ -void ASEImporter::GenerateDefaultMaterial() -{ - ai_assert(NULL != mParser); +void ASEImporter::GenerateDefaultMaterial() { + ai_assert(nullptr != mParser); bool bHas = false; - for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { - if ((*i).bSkip)continue; + for (std::vector::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) { + if ((*i).bSkip) continue; if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) { (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size(); bHas = true; } } - if (bHas || mParser->m_vMaterials.empty()) { + if (bHas || mParser->m_vMaterials.empty()) { // add a simple material without submaterials to the parser's list - mParser->m_vMaterials.push_back ( ASE::Material(AI_DEFAULT_MATERIAL_NAME) ); - ASE::Material& mat = mParser->m_vMaterials.back(); + mParser->m_vMaterials.push_back(ASE::Material(AI_DEFAULT_MATERIAL_NAME)); + ASE::Material &mat = mParser->m_vMaterials.back(); - mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); - mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); - mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); - mat.mShading = Discreet3DS::Gouraud; + mat.mDiffuse = aiColor3D(0.6f, 0.6f, 0.6f); + mat.mSpecular = aiColor3D(1.0f, 1.0f, 1.0f); + mat.mAmbient = aiColor3D(0.05f, 0.05f, 0.05f); + mat.mShading = Discreet3DS::Gouraud; } } // ------------------------------------------------------------------------------------------------ -void ASEImporter::BuildAnimations(const std::vector& nodes) -{ +void ASEImporter::BuildAnimations(const std::vector &nodes) { // check whether we have at least one mesh which has animations - std::vector::const_iterator i = nodes.begin(); + std::vector::const_iterator i = nodes.begin(); unsigned int iNum = 0; - for (;i != nodes.end();++i) { + for (; i != nodes.end(); ++i) { // TODO: Implement Bezier & TCB support if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. " - "This is not supported."); + "This is not supported."); } if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { ASSIMP_LOG_WARN("ASE: Rotation controller uses Bezier/TCB keys. " - "This is not supported."); + "This is not supported."); } - if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { + if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. " - "This is not supported."); + "This is not supported."); } // We compare against 1 here - firstly one key is not // really an animation and secondly MAX writes dummies // that represent the node transformation. - if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){ + if ((*i)->mAnim.akeyPositions.size() > 1 || (*i)->mAnim.akeyRotations.size() > 1 || (*i)->mAnim.akeyScaling.size() > 1) { ++iNum; } - if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { + if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan((*i)->mTargetPosition.x)) { ++iNum; } } - if (iNum) { + if (iNum) { // Generate a new animation channel and setup everything for it pcScene->mNumAnimations = 1; - pcScene->mAnimations = new aiAnimation*[1]; - aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation(); - pcAnim->mNumChannels = iNum; - pcAnim->mChannels = new aiNodeAnim*[iNum]; + pcScene->mAnimations = new aiAnimation *[1]; + aiAnimation *pcAnim = pcScene->mAnimations[0] = new aiAnimation(); + pcAnim->mNumChannels = iNum; + pcAnim->mChannels = new aiNodeAnim *[iNum]; pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame; iNum = 0; // Now iterate through all meshes and collect all data we can find - for (i = nodes.begin();i != nodes.end();++i) { + for (i = nodes.begin(); i != nodes.end(); ++i) { - ASE::BaseNode* me = *i; - if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) { + ASE::BaseNode *me = *i; + if (me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan(me->mTargetPosition.x)) { // Generate an extra channel for the camera/light target. // BuildNodes() does also generate an extra node, named // .Target. - aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); + aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); nd->mNodeName.Set(me->mName + ".Target"); // If there is no input position channel we will need @@ -357,32 +356,31 @@ void ASEImporter::BuildAnimations(const std::vector& nodes) helper.Process(&me->mTargetAnim.akeyPositions);*/ // Allocate the key array and fill it - nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size(); + nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size(); nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0], - nd->mNumPositionKeys * sizeof(aiVectorKey)); + ::memcpy(nd->mPositionKeys, &me->mTargetAnim.akeyPositions[0], + nd->mNumPositionKeys * sizeof(aiVectorKey)); } - if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { + if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { // Begin a new node animation channel for this node - aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); + aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); nd->mNodeName.Set(me->mName); // copy position keys - if (me->mAnim.akeyPositions.size() > 1 ) - { + if (me->mAnim.akeyPositions.size() > 1) { // Allocate the key array and fill it - nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size(); + nd->mNumPositionKeys = (unsigned int)me->mAnim.akeyPositions.size(); nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0], - nd->mNumPositionKeys * sizeof(aiVectorKey)); + ::memcpy(nd->mPositionKeys, &me->mAnim.akeyPositions[0], + nd->mNumPositionKeys * sizeof(aiVectorKey)); } // copy rotation keys - if (me->mAnim.akeyRotations.size() > 1 ) { + if (me->mAnim.akeyRotations.size() > 1) { // Allocate the key array and fill it - nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size(); + nd->mNumRotationKeys = (unsigned int)me->mAnim.akeyRotations.size(); nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; // -------------------------------------------------------------------- @@ -395,11 +393,11 @@ void ASEImporter::BuildAnimations(const std::vector& nodes) // -------------------------------------------------------------------- aiQuaternion cur; - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) { aiQuatKey q = me->mAnim.akeyRotations[a]; if (mParser->iFileFormat > 110) { - cur = (a ? cur*q.mValue : q.mValue); + cur = (a ? cur * q.mValue : q.mValue); q.mValue = cur.Normalize(); } nd->mRotationKeys[a] = q; @@ -409,13 +407,13 @@ void ASEImporter::BuildAnimations(const std::vector& nodes) } } // copy scaling keys - if (me->mAnim.akeyScaling.size() > 1 ) { + if (me->mAnim.akeyScaling.size() > 1) { // Allocate the key array and fill it - nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size(); + nd->mNumScalingKeys = (unsigned int)me->mAnim.akeyScaling.size(); nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; - ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0], - nd->mNumScalingKeys * sizeof(aiVectorKey)); + ::memcpy(nd->mScalingKeys, &me->mAnim.akeyScaling[0], + nd->mNumScalingKeys * sizeof(aiVectorKey)); } } } @@ -424,18 +422,17 @@ void ASEImporter::BuildAnimations(const std::vector& nodes) // ------------------------------------------------------------------------------------------------ // Build output cameras -void ASEImporter::BuildCameras() -{ - if (!mParser->m_vCameras.empty()) { +void ASEImporter::BuildCameras() { + if (!mParser->m_vCameras.empty()) { pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size(); - pcScene->mCameras = new aiCamera*[pcScene->mNumCameras]; + pcScene->mCameras = new aiCamera *[pcScene->mNumCameras]; - for (unsigned int i = 0; i < pcScene->mNumCameras;++i) { - aiCamera* out = pcScene->mCameras[i] = new aiCamera(); - ASE::Camera& in = mParser->m_vCameras[i]; + for (unsigned int i = 0; i < pcScene->mNumCameras; ++i) { + aiCamera *out = pcScene->mCameras[i] = new aiCamera(); + ASE::Camera &in = mParser->m_vCameras[i]; // copy members - out->mClipPlaneFar = in.mFar; + out->mClipPlaneFar = in.mFar; out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); out->mHorizontalFOV = in.mFOV; @@ -446,24 +443,22 @@ void ASEImporter::BuildCameras() // ------------------------------------------------------------------------------------------------ // Build output lights -void ASEImporter::BuildLights() -{ - if (!mParser->m_vLights.empty()) { +void ASEImporter::BuildLights() { + if (!mParser->m_vLights.empty()) { pcScene->mNumLights = (unsigned int)mParser->m_vLights.size(); - pcScene->mLights = new aiLight*[pcScene->mNumLights]; + pcScene->mLights = new aiLight *[pcScene->mNumLights]; - for (unsigned int i = 0; i < pcScene->mNumLights;++i) { - aiLight* out = pcScene->mLights[i] = new aiLight(); - ASE::Light& in = mParser->m_vLights[i]; + for (unsigned int i = 0; i < pcScene->mNumLights; ++i) { + aiLight *out = pcScene->mLights[i] = new aiLight(); + ASE::Light &in = mParser->m_vLights[i]; // The direction is encoded in the transformation matrix of the node. // In 3DS MAX the light source points into negative Z direction if // the node transformation is the identity. - out->mDirection = aiVector3D(0.f,0.f,-1.f); + out->mDirection = aiVector3D(0.f, 0.f, -1.f); out->mName.Set(in.mName); - switch (in.mLightType) - { + switch (in.mLightType) { case ASE::Light::TARGET: out->mType = aiLightSource_SPOT; out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle); @@ -475,7 +470,7 @@ void ASEImporter::BuildLights() break; default: - //case ASE::Light::OMNI: + //case ASE::Light::OMNI: out->mType = aiLightSource_POINT; break; }; @@ -485,57 +480,55 @@ void ASEImporter::BuildLights() } // ------------------------------------------------------------------------------------------------ -void ASEImporter::AddNodes(const std::vector& nodes, - aiNode* pcParent,const char* szName) -{ +void ASEImporter::AddNodes(const std::vector &nodes, + aiNode *pcParent, const char *szName) { aiMatrix4x4 m; - AddNodes(nodes,pcParent,szName,m); + AddNodes(nodes, pcParent, szName, m); } // ------------------------------------------------------------------------------------------------ // Add meshes to a given node -void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) -{ - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { +void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) { + for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) { // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color) - const aiMesh* pcMesh = pcScene->mMeshes[i]; - const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; + const aiMesh *pcMesh = pcScene->mMeshes[i]; + const ASE::Mesh *mesh = (const ASE::Mesh *)pcMesh->mColors[2]; if (mesh == snode) { ++node->mNumMeshes; } } - if(node->mNumMeshes) { + if (node->mNumMeshes) { node->mMeshes = new unsigned int[node->mNumMeshes]; - for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) { + for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes; ++i) { - const aiMesh* pcMesh = pcScene->mMeshes[i]; - const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; - if (mesh == snode) { + const aiMesh *pcMesh = pcScene->mMeshes[i]; + const ASE::Mesh *mesh = (const ASE::Mesh *)pcMesh->mColors[2]; + if (mesh == snode) { node->mMeshes[p++] = i; // Transform all vertices of the mesh back into their local space -> // at the moment they are pretransformed - aiMatrix4x4 m = mesh->mTransform; + aiMatrix4x4 m = mesh->mTransform; m.Inverse(); - aiVector3D* pvCurPtr = pcMesh->mVertices; - const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) { + aiVector3D *pvCurPtr = pcMesh->mVertices; + const aiVector3D *pvEndPtr = pvCurPtr + pcMesh->mNumVertices; + while (pvCurPtr != pvEndPtr) { *pvCurPtr = m * (*pvCurPtr); pvCurPtr++; } // Do the same for the normal vectors, if we have them. // As always, inverse transpose. - if (pcMesh->mNormals) { - aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform ); + if (pcMesh->mNormals) { + aiMatrix3x3 m3 = aiMatrix3x3(mesh->mTransform); m3.Transpose(); pvCurPtr = pcMesh->mNormals; pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) { + while (pvCurPtr != pvEndPtr) { *pvCurPtr = m3 * (*pvCurPtr); pvCurPtr++; } @@ -547,68 +540,65 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) // ------------------------------------------------------------------------------------------------ // Add child nodes to a given parent node -void ASEImporter::AddNodes (const std::vector& nodes, - aiNode* pcParent, const char* szName, - const aiMatrix4x4& mat) -{ +void ASEImporter::AddNodes(const std::vector &nodes, + aiNode *pcParent, const char *szName, + const aiMatrix4x4 &mat) { const size_t len = szName ? ::strlen(szName) : 0; ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); // Receives child nodes for the pcParent node - std::vector apcNodes; + std::vector apcNodes; // Now iterate through all nodes in the scene and search for one // which has *us* as parent. - for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { - const BaseNode* snode = *it; + for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { + const BaseNode *snode = *it; if (szName) { - if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str())) + if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str())) continue; - } - else if (snode->mParent.length()) + } else if (snode->mParent.length()) continue; (*it)->mProcessed = true; // Allocate a new node and add it to the output data structure apcNodes.push_back(new aiNode()); - aiNode* node = apcNodes.back(); + aiNode *node = apcNodes.back(); node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); node->mParent = pcParent; // Setup the transformation matrix of the node - aiMatrix4x4 mParentAdjust = mat; + aiMatrix4x4 mParentAdjust = mat; mParentAdjust.Inverse(); - node->mTransformation = mParentAdjust*snode->mTransform; + node->mTransformation = mParentAdjust * snode->mTransform; // Add sub nodes - prevent stack overflow due to recursive parenting - if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName ) { - AddNodes(nodes,node,node->mName.data,snode->mTransform); + if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) { + AddNodes(nodes, node, node->mName.data, snode->mTransform); } // Further processing depends on the type of the node - if (snode->mType == ASE::BaseNode::Mesh) { + if (snode->mType == ASE::BaseNode::Mesh) { // If the type of this node is "Mesh" we need to search // the list of output meshes in the data structure for // all those that belonged to this node once. This is // slightly inconvinient here and a better solution should // be used when this code is refactored next. - AddMeshes(snode,node); - } - else if (is_not_qnan( snode->mTargetPosition.x )) { + AddMeshes(snode, node); + } else if (is_not_qnan(snode->mTargetPosition.x)) { // If this is a target camera or light we generate a small // child node which marks the position of the camera // target (the direction information is contained in *this* // node's animation track but the exact target position // would be lost otherwise) - if (!node->mNumChildren) { - node->mChildren = new aiNode*[1]; + if (!node->mNumChildren) { + node->mChildren = new aiNode *[1]; } - aiNode* nd = new aiNode(); + aiNode *nd = new aiNode(); - nd->mName.Set ( snode->mName + ".Target" ); + nd->mName.Set(snode->mName + ".Target"); nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4; nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4; @@ -617,14 +607,14 @@ void ASEImporter::AddNodes (const std::vector& nodes, nd->mParent = node; // The .Target node is always the first child node - for (unsigned int m = 0; m < node->mNumChildren;++m) - node->mChildren[m+1] = node->mChildren[m]; + for (unsigned int m = 0; m < node->mNumChildren; ++m) + node->mChildren[m + 1] = node->mChildren[m]; node->mChildren[0] = nd; node->mNumChildren++; // What we did is so great, it is at least worth a debug message - ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")"); + ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (" + snode->mName + ")"); } } @@ -632,10 +622,10 @@ void ASEImporter::AddNodes (const std::vector& nodes, // We allocate one slot more in case this is a target camera/light pcParent->mNumChildren = (unsigned int)apcNodes.size(); if (pcParent->mNumChildren) { - pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; + pcParent->mChildren = new aiNode *[apcNodes.size() + 1 /* PLUS ONE !!! */]; // now build all nodes for our nice new children - for (unsigned int p = 0; p < apcNodes.size();++p) + for (unsigned int p = 0; p < apcNodes.size(); ++p) pcParent->mChildren[p] = apcNodes[p]; } return; @@ -643,32 +633,32 @@ void ASEImporter::AddNodes (const std::vector& nodes, // ------------------------------------------------------------------------------------------------ // Build the output node graph -void ASEImporter::BuildNodes(std::vector& nodes) { - ai_assert(NULL != pcScene); +void ASEImporter::BuildNodes(std::vector &nodes) { + ai_assert(nullptr != pcScene); // allocate the one and only root node - aiNode* root = pcScene->mRootNode = new aiNode(); + aiNode *root = pcScene->mRootNode = new aiNode(); root->mName.Set(""); // Setup the coordinate system transformation pcScene->mRootNode->mNumChildren = 1; - pcScene->mRootNode->mChildren = new aiNode*[1]; - aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode(); + pcScene->mRootNode->mChildren = new aiNode *[1]; + aiNode *ch = pcScene->mRootNode->mChildren[0] = new aiNode(); ch->mParent = root; // Change the transformation matrix of all nodes for (BaseNode *node : nodes) { - aiMatrix4x4& m = node->mTransform; + aiMatrix4x4 &m = node->mTransform; m.Transpose(); // row-order vs column-order } // add all nodes - AddNodes(nodes,ch,NULL); + AddNodes(nodes, ch, nullptr); // now iterate through al nodes and find those that have not yet // been added to the nodegraph (= their parent could not be recognized) - std::vector aiList; - for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { + std::vector aiList; + for (std::vector::iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { if ((*it)->mProcessed) { continue; } @@ -678,54 +668,54 @@ void ASEImporter::BuildNodes(std::vector& nodes) { // search the list another time, starting *here* and try to find out whether // there is a node that references *us* as a parent - for (std::vector::const_iterator it2 = nodes.begin();it2 != end; ++it2) { + for (std::vector::const_iterator it2 = nodes.begin(); it2 != end; ++it2) { if (it2 == it) { continue; } - if ((*it2)->mName == (*it)->mParent) { + if ((*it2)->mName == (*it)->mParent) { bKnowParent = true; break; } } - if (!bKnowParent) { + if (!bKnowParent) { aiList.push_back(*it); } } // Are there ane orphaned nodes? - if (!aiList.empty()) { - std::vector apcNodes; + if (!aiList.empty()) { + std::vector apcNodes; apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); - for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i) + for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren; ++i) apcNodes.push_back(pcScene->mRootNode->mChildren[i]); delete[] pcScene->mRootNode->mChildren; - for (std::vector::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) { - const ASE::BaseNode* src = *i; + for (std::vector::/*const_*/ iterator i = aiList.begin(); i != aiList.end(); ++i) { + const ASE::BaseNode *src = *i; // The parent is not known, so we can assume that we must add // this node to the root node of the whole scene - aiNode* pcNode = new aiNode(); + aiNode *pcNode = new aiNode(); pcNode->mParent = pcScene->mRootNode; pcNode->mName.Set(src->mName); - AddMeshes(src,pcNode); - AddNodes(nodes,pcNode,pcNode->mName.data); + AddMeshes(src, pcNode); + AddNodes(nodes, pcNode, pcNode->mName.data); apcNodes.push_back(pcNode); } // Regenerate our output array - pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()]; - for (unsigned int i = 0; i < apcNodes.size();++i) + pcScene->mRootNode->mChildren = new aiNode *[apcNodes.size()]; + for (unsigned int i = 0; i < apcNodes.size(); ++i) pcScene->mRootNode->mChildren[i] = apcNodes[i]; pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); } - // Reset the third color set to NULL - we used this field to store a temporary pointer - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - pcScene->mMeshes[i]->mColors[2] = NULL; + // Reset the third color set to nullptr - we used this field to store a temporary pointer + for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) + pcScene->mMeshes[i]->mColors[2] = nullptr; // The root node should not have at least one child or the file is valid if (!pcScene->mRootNode->mNumChildren) { @@ -733,17 +723,17 @@ void ASEImporter::BuildNodes(std::vector& nodes) { } // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system - pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); + pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f); } // ------------------------------------------------------------------------------------------------ // Convert the imported data to the internal verbose representation -void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { +void ASEImporter::BuildUniqueRepresentation(ASE::Mesh &mesh) { // allocate output storage std::vector mPositions; std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - std::vector mVertexColors; + std::vector mVertexColors; std::vector mNormals; std::vector mBoneVertices; @@ -751,13 +741,13 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { mPositions.resize(iSize); // optional texture coordinates - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) { - if (!mesh.amTexCoords[i].empty()) { + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (!mesh.amTexCoords[i].empty()) { amTexCoords[i].resize(iSize); } } // optional vertex colors - if (!mesh.mVertexColors.empty()) { + if (!mesh.mVertexColors.empty()) { mVertexColors.resize(iSize); } @@ -766,38 +756,37 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { mNormals.resize(iSize); } // bone vertices. There is no need to change the bone list - if (!mesh.mBoneVertices.empty()) { + if (!mesh.mBoneVertices.empty()) { mBoneVertices.resize(iSize); } // iterate through all faces in the mesh unsigned int iCurrent = 0, fi = 0; - for (std::vector::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) { - for (unsigned int n = 0; n < 3;++n,++iCurrent) - { + for (std::vector::iterator i = mesh.mFaces.begin(); i != mesh.mFaces.end(); ++i, ++fi) { + for (unsigned int n = 0; n < 3; ++n, ++iCurrent) { mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; // add texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (mesh.amTexCoords[c].empty())break; + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) { + if (mesh.amTexCoords[c].empty()) break; amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; } // add vertex colors - if (!mesh.mVertexColors.empty()) { + if (!mesh.mVertexColors.empty()) { mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]]; } // add normal vectors if (!mesh.mNormals.empty()) { - mNormals[iCurrent] = mesh.mNormals[fi*3+n]; + mNormals[iCurrent] = mesh.mNormals[fi * 3 + n]; mNormals[iCurrent].Normalize(); } // handle bone vertices - if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { + if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { // (sometimes this will cause bone verts to be duplicated // however, I' quite sure Schrompf' JoinVerticesStep // will fix that again ...) - mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; + mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; } (*i).mIndices[n] = iCurrent; } @@ -808,31 +797,29 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { mesh.mPositions = mPositions; mesh.mVertexColors = mVertexColors; - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) mesh.amTexCoords[c] = amTexCoords[c]; } // ------------------------------------------------------------------------------------------------ // Copy a texture from the ASE structs to the output material -void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type) -{ +void CopyASETexture(aiMaterial &mat, ASE::Texture &texture, aiTextureType type) { // Setup the texture name aiString tex; - tex.Set( texture.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + tex.Set(texture.mMapName); + mat.AddProperty(&tex, AI_MATKEY_TEXTURE(type, 0)); // Setup the texture blend factor if (is_not_qnan(texture.mTextureBlend)) - mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + mat.AddProperty(&texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type, 0)); // Setup texture UV transformations - mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); + mat.AddProperty(&texture.mOffsetU, 5, AI_MATKEY_UVTRANSFORM(type, 0)); } // ------------------------------------------------------------------------------------------------ // Convert from ASE material to output material -void ASEImporter::ConvertMaterial(ASE::Material& mat) -{ +void ASEImporter::ConvertMaterial(ASE::Material &mat) { // LARGE TODO: Much code her is copied from 3DS ... join them maybe? // Allocate the output material @@ -845,135 +832,134 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) mat.mAmbient.b += mParser->m_clrAmbient.b; aiString name; - name.Set( mat.mName); - mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME); + name.Set(mat.mName); + mat.pcInstance->AddProperty(&name, AI_MATKEY_NAME); // material colors - mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); - mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + mat.pcInstance->AddProperty(&mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.pcInstance->AddProperty(&mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.pcInstance->AddProperty(&mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.pcInstance->AddProperty(&mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); // shininess - if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) - { - mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); - mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); + if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) { + mat.pcInstance->AddProperty(&mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); + mat.pcInstance->AddProperty(&mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); } // If there is no shininess, we can disable phong lighting else if (D3DS::Discreet3DS::Metal == mat.mShading || - D3DS::Discreet3DS::Phong == mat.mShading || - D3DS::Discreet3DS::Blinn == mat.mShading) - { + D3DS::Discreet3DS::Phong == mat.mShading || + D3DS::Discreet3DS::Blinn == mat.mShading) { mat.mShading = D3DS::Discreet3DS::Gouraud; } // opacity - mat.pcInstance->AddProperty( &mat.mTransparency,1,AI_MATKEY_OPACITY); + mat.pcInstance->AddProperty(&mat.mTransparency, 1, AI_MATKEY_OPACITY); // Two sided rendering? - if (mat.mTwoSided) - { + if (mat.mTwoSided) { int i = 1; - mat.pcInstance->AddProperty(&i,1,AI_MATKEY_TWOSIDED); + mat.pcInstance->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); } // shading mode aiShadingMode eShading = aiShadingMode_NoShading; - switch (mat.mShading) - { - case D3DS::Discreet3DS::Flat: - eShading = aiShadingMode_Flat; break; - case D3DS::Discreet3DS::Phong : - eShading = aiShadingMode_Phong; break; - case D3DS::Discreet3DS::Blinn : - eShading = aiShadingMode_Blinn; break; + switch (mat.mShading) { + case D3DS::Discreet3DS::Flat: + eShading = aiShadingMode_Flat; + break; + case D3DS::Discreet3DS::Phong: + eShading = aiShadingMode_Phong; + break; + case D3DS::Discreet3DS::Blinn: + eShading = aiShadingMode_Blinn; + break; - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse (L dot N) shading - case D3DS::Discreet3DS::Wire: - { - // set the wireframe flag - unsigned int iWire = 1; - mat.pcInstance->AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - case D3DS::Discreet3DS::Gouraud: - eShading = aiShadingMode_Gouraud; break; - case D3DS::Discreet3DS::Metal : - eShading = aiShadingMode_CookTorrance; break; + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse (L dot N) shading + case D3DS::Discreet3DS::Wire: { + // set the wireframe flag + unsigned int iWire = 1; + mat.pcInstance->AddProperty((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME); } - mat.pcInstance->AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); + case D3DS::Discreet3DS::Gouraud: + eShading = aiShadingMode_Gouraud; + break; + case D3DS::Discreet3DS::Metal: + eShading = aiShadingMode_CookTorrance; + break; + } + mat.pcInstance->AddProperty((int *)&eShading, 1, AI_MATKEY_SHADING_MODEL); // DIFFUSE texture - if( mat.sTexDiffuse.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE); + if (mat.sTexDiffuse.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexDiffuse, aiTextureType_DIFFUSE); // SPECULAR texture - if( mat.sTexSpecular.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR); + if (mat.sTexSpecular.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexSpecular, aiTextureType_SPECULAR); // AMBIENT texture - if( mat.sTexAmbient.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT); + if (mat.sTexAmbient.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexAmbient, aiTextureType_AMBIENT); // OPACITY texture - if( mat.sTexOpacity.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY); + if (mat.sTexOpacity.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexOpacity, aiTextureType_OPACITY); // EMISSIVE texture - if( mat.sTexEmissive.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE); + if (mat.sTexEmissive.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexEmissive, aiTextureType_EMISSIVE); // BUMP texture - if( mat.sTexBump.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT); + if (mat.sTexBump.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexBump, aiTextureType_HEIGHT); // SHININESS texture - if( mat.sTexShininess.mMapName.length() > 0) - CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); + if (mat.sTexShininess.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance, mat.sTexShininess, aiTextureType_SHININESS); // store the name of the material itself, too - if( mat.mName.length() > 0) { - aiString tex;tex.Set( mat.mName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME); + if (mat.mName.length() > 0) { + aiString tex; + tex.Set(mat.mName); + mat.pcInstance->AddProperty(&tex, AI_MATKEY_NAME); } return; } // ------------------------------------------------------------------------------------------------ // Build output meshes -void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMeshes) -{ +void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector &avOutMeshes) { // validate the material index of the mesh - if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { - mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; + if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { + mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1; ASSIMP_LOG_WARN("Material index is out of range"); } // If the material the mesh is assigned to is consisting of submeshes, split it if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { - std::vector vSubMaterials = mParser-> - m_vMaterials[mesh.iMaterialIndex].avSubMaterials; + std::vector vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials; - std::vector* aiSplit = new std::vector[vSubMaterials.size()]; + std::vector *aiSplit = new std::vector[vSubMaterials.size()]; // build a list of all faces per sub-material - for (unsigned int i = 0; i < mesh.mFaces.size();++i) { + for (unsigned int i = 0; i < mesh.mFaces.size(); ++i) { // check range if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { ASSIMP_LOG_WARN("Submaterial index is out of range"); // use the last material instead - aiSplit[vSubMaterials.size()-1].push_back(i); - } - else aiSplit[mesh.mFaces[i].iMaterial].push_back(i); + aiSplit[vSubMaterials.size() - 1].push_back(i); + } else + aiSplit[mesh.mFaces[i].iMaterial].push_back(i); } // now generate submeshes - for (unsigned int p = 0; p < vSubMaterials.size();++p) { - if (!aiSplit[p].empty()) { + for (unsigned int p = 0; p < vSubMaterials.size(); ++p) { + if (!aiSplit[p].empty()) { - aiMesh* p_pcOut = new aiMesh(); + aiMesh *p_pcOut = new aiMesh(); p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // let the sub material index @@ -983,55 +969,55 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true; // store the real index here ... color channel 3 - p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; + p_pcOut->mColors[3] = (aiColor4D *)(uintptr_t)mesh.iMaterialIndex; // store a pointer to the mesh in color channel 2 - p_pcOut->mColors[2] = (aiColor4D*) &mesh; + p_pcOut->mColors[2] = (aiColor4D *)&mesh; avOutMeshes.push_back(p_pcOut); // convert vertices - p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3; + p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size() * 3; p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); // receive output vertex weights - std::vector > *avOutputBones = NULL; - if (!mesh.mBones.empty()) { - avOutputBones = new std::vector >[mesh.mBones.size()]; + std::vector> *avOutputBones = nullptr; + if (!mesh.mBones.empty()) { + avOutputBones = new std::vector>[mesh.mBones.size()]; } // allocate enough storage for faces p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; - unsigned int iBase = 0,iIndex; - if (p_pcOut->mNumVertices) { + unsigned int iBase = 0, iIndex; + if (p_pcOut->mNumVertices) { p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; - p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { + p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; + for (unsigned int q = 0; q < aiSplit[p].size(); ++q) { iIndex = aiSplit[p][q]; p_pcOut->mFaces[q].mIndices = new unsigned int[3]; p_pcOut->mFaces[q].mNumIndices = 3; - for (unsigned int t = 0; t < 3;++t, ++iBase) { + for (unsigned int t = 0; t < 3; ++t, ++iBase) { const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; - p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2]; - p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2]; + p_pcOut->mVertices[iBase] = mesh.mPositions[iIndex2]; + p_pcOut->mNormals[iBase] = mesh.mNormals[iIndex2]; // convert bones, if existing if (!mesh.mBones.empty()) { ai_assert(avOutputBones); // check whether there is a vertex weight for this vertex index - if (iIndex2 < mesh.mBoneVertices.size()) { + if (iIndex2 < mesh.mBoneVertices.size()) { - for (std::vector >::const_iterator - blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); - blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) { + for (std::vector>::const_iterator + blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); + blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end(); ++blubb) { // NOTE: illegal cases have already been filtered out avOutputBones[(*blubb).first].push_back(std::pair( - iBase,(*blubb).second)); + iBase, (*blubb).second)); } } } @@ -1040,14 +1026,13 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } } // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (!mesh.amTexCoords[c].empty()) - { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) { + if (!mesh.amTexCoords[c].empty()) { p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { + for (unsigned int q = 0; q < aiSplit[p].size(); ++q) { iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) { + for (unsigned int t = 0; t < 3; ++t) { p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; } } @@ -1057,38 +1042,36 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // Convert vertex colors (only one set supported) - if (!mesh.mVertexColors.empty()){ + if (!mesh.mVertexColors.empty()) { p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) { + for (unsigned int q = 0; q < aiSplit[p].size(); ++q) { iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) { + for (unsigned int t = 0; t < 3; ++t) { p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; } } } // Copy bones - if (!mesh.mBones.empty()) { + if (!mesh.mBones.empty()) { p_pcOut->mNumBones = 0; - for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) - if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++; + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) + if (!avOutputBones[mrspock].empty()) p_pcOut->mNumBones++; - p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ]; - aiBone** pcBone = p_pcOut->mBones; - for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) - { - if (!avOutputBones[mrspock].empty()) { + p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones]; + aiBone **pcBone = p_pcOut->mBones; + for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) { + if (!avOutputBones[mrspock].empty()) { // we will need this bone. add it to the output mesh and // add all per-vertex weights - aiBone* pc = *pcBone = new aiBone(); + aiBone *pc = *pcBone = new aiBone(); pc->mName.Set(mesh.mBones[mrspock].mName); pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size(); pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk) - { - const std::pair& ref = avOutputBones[mrspock][captainkirk]; + for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights; ++captainkirk) { + const std::pair &ref = avOutputBones[mrspock][captainkirk]; pc->mWeights[captainkirk].mVertexId = ref.first; pc->mWeights[captainkirk].mWeight = ref.second; } @@ -1102,15 +1085,13 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // delete storage delete[] aiSplit; - } - else - { + } else { // Otherwise we can simply copy the data to one output mesh // This codepath needs less memory and uses fast memcpy()s // to do the actual copying. So I think it is worth the // effort here. - aiMesh* p_pcOut = new aiMesh(); + aiMesh *p_pcOut = new aiMesh(); p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // set an empty sub material index @@ -1118,10 +1099,10 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true; // store the real index here ... in color channel 3 - p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; + p_pcOut->mColors[3] = (aiColor4D *)(uintptr_t)mesh.iMaterialIndex; // store a pointer to the mesh in color channel 2 - p_pcOut->mColors[2] = (aiColor4D*) &mesh; + p_pcOut->mColors[2] = (aiColor4D *)&mesh; avOutMeshes.push_back(p_pcOut); // If the mesh hasn't faces or vertices, there are two cases @@ -1140,20 +1121,20 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh // copy vertices p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()]; - memcpy(p_pcOut->mVertices,&mesh.mPositions[0], - mesh.mPositions.size() * sizeof(aiVector3D)); + memcpy(p_pcOut->mVertices, &mesh.mPositions[0], + mesh.mPositions.size() * sizeof(aiVector3D)); // copy normals p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()]; - memcpy(p_pcOut->mNormals,&mesh.mNormals[0], - mesh.mNormals.size() * sizeof(aiVector3D)); + memcpy(p_pcOut->mNormals, &mesh.mNormals[0], + mesh.mNormals.size() * sizeof(aiVector3D)); // copy texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (!mesh.amTexCoords[c].empty()) { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) { + if (!mesh.amTexCoords[c].empty()) { p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()]; - memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0], - mesh.amTexCoords[c].size() * sizeof(aiVector3D)); + memcpy(p_pcOut->mTextureCoords[c], &mesh.amTexCoords[c][0], + mesh.amTexCoords[c].size() * sizeof(aiVector3D)); // setup the number of valid vertex components p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; @@ -1161,14 +1142,14 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // copy vertex colors - if (!mesh.mVertexColors.empty()) { + if (!mesh.mVertexColors.empty()) { p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()]; - memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0], - mesh.mVertexColors.size() * sizeof(aiColor4D)); + memcpy(p_pcOut->mColors[0], &mesh.mVertexColors[0], + mesh.mVertexColors.size() * sizeof(aiColor4D)); } // copy faces - for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) { + for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces; ++iFace) { p_pcOut->mFaces[iFace].mNumIndices = 3; p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; @@ -1179,18 +1160,17 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // copy vertex bones - if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { - std::vector > avBonesOut( mesh.mBones.size() ); + if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { + std::vector> avBonesOut(mesh.mBones.size()); // find all vertex weights for this bone unsigned int quak = 0; - for (std::vector::const_iterator harrypotter = mesh.mBoneVertices.begin(); - harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) { + for (std::vector::const_iterator harrypotter = mesh.mBoneVertices.begin(); + harrypotter != mesh.mBoneVertices.end(); ++harrypotter, ++quak) { - for (std::vector >::const_iterator - ronaldweasley = (*harrypotter).mBoneWeights.begin(); - ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley) - { + for (std::vector>::const_iterator + ronaldweasley = (*harrypotter).mBoneWeights.begin(); + ronaldweasley != (*harrypotter).mBoneWeights.end(); ++ronaldweasley) { aiVertexWeight weight; weight.mVertexId = quak; weight.mWeight = (*ronaldweasley).second; @@ -1200,19 +1180,19 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh // now build a final bone list p_pcOut->mNumBones = 0; - for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) - if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++; + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size(); ++jfkennedy) + if (!avBonesOut[jfkennedy].empty()) p_pcOut->mNumBones++; - p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones]; - aiBone** pcBone = p_pcOut->mBones; - for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) { + p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones]; + aiBone **pcBone = p_pcOut->mBones; + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size(); ++jfkennedy) { if (!avBonesOut[jfkennedy].empty()) { - aiBone* pc = *pcBone = new aiBone(); + aiBone *pc = *pcBone = new aiBone(); pc->mName.Set(mesh.mBones[jfkennedy].mName); pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], - sizeof(aiVertexWeight) * pc->mNumWeights); + ::memcpy(pc->mWeights, &avBonesOut[jfkennedy][0], + sizeof(aiVertexWeight) * pc->mNumWeights); ++pcBone; } } @@ -1222,23 +1202,20 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh // ------------------------------------------------------------------------------------------------ // Setup proper material indices and build output materials -void ASEImporter::BuildMaterialIndices() -{ - ai_assert(NULL != pcScene); +void ASEImporter::BuildMaterialIndices() { + ai_assert(nullptr != pcScene); // iterate through all materials and check whether we need them - for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) - { - ASE::Material& mat = mParser->m_vMaterials[iMat]; - if (mat.bNeed) { + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) { + ASE::Material &mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) { // Convert it to the aiMaterial layout ConvertMaterial(mat); ++pcScene->mNumMaterials; } - for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) - { - ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) { + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) { + ASE::Material &submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { // Convert it to the aiMaterial layout ConvertMaterial(submat); ++pcScene->mNumMaterials; @@ -1247,15 +1224,14 @@ void ASEImporter::BuildMaterialIndices() } // allocate the output material array - pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials]; - D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials]; + pcScene->mMaterials = new aiMaterial *[pcScene->mNumMaterials]; + D3DS::Material **pcIntMaterials = new D3DS::Material *[pcScene->mNumMaterials]; unsigned int iNum = 0; - for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { - ASE::Material& mat = mParser->m_vMaterials[iMat]; - if (mat.bNeed) - { - ai_assert(NULL != mat.pcInstance); + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) { + ASE::Material &mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) { + ai_assert(nullptr != mat.pcInstance); pcScene->mMaterials[iNum] = mat.pcInstance; // Store the internal material, too @@ -1263,22 +1239,20 @@ void ASEImporter::BuildMaterialIndices() // Iterate through all meshes and search for one which is using // this top-level material index - for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) - { - aiMesh* mesh = pcScene->mMeshes[iMesh]; + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) { + aiMesh *mesh = pcScene->mMeshes[iMesh]; if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex && - iMat == (uintptr_t)mesh->mColors[3]) - { + iMat == (uintptr_t)mesh->mColors[3]) { mesh->mMaterialIndex = iNum; - mesh->mColors[3] = NULL; + mesh->mColors[3] = nullptr; } } iNum++; } - for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { - ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) { - ai_assert(NULL != submat.pcInstance); + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) { + ASE::Material &submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { + ai_assert(nullptr != submat.pcInstance); pcScene->mMaterials[iNum] = submat.pcInstance; // Store the internal material, too @@ -1286,12 +1260,12 @@ void ASEImporter::BuildMaterialIndices() // Iterate through all meshes and search for one which is using // this sub-level material index - for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { - aiMesh* mesh = pcScene->mMeshes[iMesh]; + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) { + aiMesh *mesh = pcScene->mMeshes[iMesh]; if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { mesh->mMaterialIndex = iNum; - mesh->mColors[3] = NULL; + mesh->mColors[3] = nullptr; } } iNum++; @@ -1305,15 +1279,13 @@ void ASEImporter::BuildMaterialIndices() // ------------------------------------------------------------------------------------------------ // Generate normal vectors basing on smoothing groups -bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { +bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) { - if (!mesh.mNormals.empty() && !configRecomputeNormals) - { + if (!mesh.mNormals.empty() && !configRecomputeNormals) { // Check whether there are only uninitialized normals. If there are // some, skip all normals from the file and compute them on our own - for (std::vector::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) { - if ((*qq).x || (*qq).y || (*qq).z) - { + for (std::vector::const_iterator qq = mesh.mNormals.begin(); qq != mesh.mNormals.end(); ++qq) { + if ((*qq).x || (*qq).y || (*qq).z) { return true; } } diff --git a/code/ASE/ASELoader.h b/code/AssetLib/ASE/ASELoader.h similarity index 100% rename from code/ASE/ASELoader.h rename to code/AssetLib/ASE/ASELoader.h diff --git a/code/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp similarity index 59% rename from code/ASE/ASEParser.cpp rename to code/AssetLib/ASE/ASEParser.cpp index efc6ecd0d..c801f53a1 100644 --- a/code/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -49,8 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers -#include "PostProcessing/TextureTransform.h" #include "ASELoader.h" +#include "PostProcessing/TextureTransform.h" #include #include @@ -67,26 +67,23 @@ using namespace Assimp::ASE; // ------------------------------------------------------------------------------------------------ // Handle a "top-level" section in the file. EOF is no error in this case. -#define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \ - else if ('{' == *filePtr)iDepth++; \ - else if ('}' == *filePtr) \ - { \ - if (0 == --iDepth) \ - { \ - ++filePtr; \ - SkipToNextToken(); \ - return; \ - } \ - } \ - else if ('\0' == *filePtr) \ - { \ - return; \ - } \ - if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ - { \ - ++iLineNumber; \ - bLastWasEndLine = true; \ - } else bLastWasEndLine = false; \ +#define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \ + else if ('{' == *filePtr) iDepth++; \ + else if ('}' == *filePtr) { \ + if (0 == --iDepth) { \ + ++filePtr; \ + SkipToNextToken(); \ + return; \ + } \ + } \ + else if ('\0' == *filePtr) { \ + return; \ + } \ + if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \ + ++iLineNumber; \ + bLastWasEndLine = true; \ + } else \ + bLastWasEndLine = false; \ ++filePtr; // ------------------------------------------------------------------------------------------------ @@ -94,59 +91,54 @@ using namespace Assimp::ASE; // @param level "Depth" of the section // @param msg Full name of the section (including the asterisk) -#define AI_ASE_HANDLE_SECTION(level, msg) \ - if ('{' == *filePtr)iDepth++; \ - else if ('}' == *filePtr) \ - { \ - if (0 == --iDepth) \ - { \ - ++filePtr; \ - SkipToNextToken(); \ - return; \ - } \ - } \ - else if ('\0' == *filePtr) \ - { \ +#define AI_ASE_HANDLE_SECTION(level, msg) \ + if ('{' == *filePtr) \ + iDepth++; \ + else if ('}' == *filePtr) { \ + if (0 == --iDepth) { \ + ++filePtr; \ + SkipToNextToken(); \ + return; \ + } \ + } else if ('\0' == *filePtr) { \ LogError("Encountered unexpected EOL while parsing a " msg \ - " chunk (Level " level ")"); \ - } \ - if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ - { \ - ++iLineNumber; \ - bLastWasEndLine = true; \ - } else bLastWasEndLine = false; \ + " chunk (Level " level ")"); \ + } \ + if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \ + ++iLineNumber; \ + bLastWasEndLine = true; \ + } else \ + bLastWasEndLine = false; \ ++filePtr; // ------------------------------------------------------------------------------------------------ -Parser::Parser (const char* szFile, unsigned int fileFormatDefault) -{ - ai_assert(NULL != szFile); +Parser::Parser(const char *szFile, unsigned int fileFormatDefault) { + ai_assert(nullptr != szFile); filePtr = szFile; iFileFormat = fileFormatDefault; // make sure that the color values are invalid m_clrBackground.r = get_qnan(); - m_clrAmbient.r = get_qnan(); + m_clrAmbient.r = get_qnan(); // setup some default values iLineNumber = 0; iFirstFrame = 0; iLastFrame = 0; - iFrameSpeed = 30; // use 30 as default value for this property - iTicksPerFrame = 1; // use 1 as default value for this property + iFrameSpeed = 30; // use 30 as default value for this property + iTicksPerFrame = 1; // use 1 as default value for this property bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping } // ------------------------------------------------------------------------------------------------ -void Parser::LogWarning(const char* szWarn) -{ - ai_assert(NULL != szWarn); +void Parser::LogWarning(const char *szWarn) { + ai_assert(nullptr != szWarn); - char szTemp[1024]; + char szTemp[2048]; #if _MSC_VER >= 1400 - sprintf_s(szTemp, "Line %u: %s",iLineNumber,szWarn); + sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn); #else - ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp, sizeof(szTemp), "Line %u: %s", iLineNumber, szWarn); #endif // output the warning to the logger ... @@ -154,15 +146,14 @@ void Parser::LogWarning(const char* szWarn) } // ------------------------------------------------------------------------------------------------ -void Parser::LogInfo(const char* szWarn) -{ - ai_assert(NULL != szWarn); +void Parser::LogInfo(const char *szWarn) { + ai_assert(nullptr != szWarn); char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); + sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn); #else - ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn); #endif // output the information to the logger ... @@ -170,15 +161,14 @@ void Parser::LogInfo(const char* szWarn) } // ------------------------------------------------------------------------------------------------ -AI_WONT_RETURN void Parser::LogError(const char* szWarn) -{ - ai_assert(NULL != szWarn); +AI_WONT_RETURN void Parser::LogError(const char *szWarn) { + ai_assert(nullptr != szWarn); char szTemp[1024]; #if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn); + sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn); #else - ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn); + ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn); #endif // throw an exception @@ -186,76 +176,60 @@ AI_WONT_RETURN void Parser::LogError(const char* szWarn) } // ------------------------------------------------------------------------------------------------ -bool Parser::SkipToNextToken() -{ - while (true) - { +bool Parser::SkipToNextToken() { + while (true) { char me = *filePtr; // increase the line number counter if necessary - if (IsLineEnd(me) && !bLastWasEndLine) - { + if (IsLineEnd(me) && !bLastWasEndLine) { ++iLineNumber; bLastWasEndLine = true; - } - else bLastWasEndLine = false; - if ('*' == me || '}' == me || '{' == me)return true; - if ('\0' == me)return false; + } else + bLastWasEndLine = false; + if ('*' == me || '}' == me || '{' == me) return true; + if ('\0' == me) return false; ++filePtr; } } // ------------------------------------------------------------------------------------------------ -bool Parser::SkipSection() -{ +bool Parser::SkipSection() { // must handle subsections ... int iCnt = 0; - while (true) - { - if ('}' == *filePtr) - { + while (true) { + if ('}' == *filePtr) { --iCnt; - if (0 == iCnt) - { + if (0 == iCnt) { // go to the next valid token ... ++filePtr; SkipToNextToken(); return true; } - } - else if ('{' == *filePtr) - { + } else if ('{' == *filePtr) { ++iCnt; - } - else if ('\0' == *filePtr) - { + } else if ('\0' == *filePtr) { LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]"); return false; - } - else if(IsLineEnd(*filePtr))++iLineNumber; + } else if (IsLineEnd(*filePtr)) + ++iLineNumber; ++filePtr; } } // ------------------------------------------------------------------------------------------------ -void Parser::Parse() -{ +void Parser::Parse() { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Version should be 200. Validate this ... - if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18)) - { + if (TokenMatch(filePtr, "3DSMAX_ASCIIEXPORT", 18)) { unsigned int fmt; ParseLV4MeshLong(fmt); - if (fmt > 200) - { + if (fmt > 200) { LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \ be <= 200"); } @@ -266,32 +240,29 @@ void Parser::Parse() // at the file extension (ASE, ASK, ASC) // ************************************************************* - if ( fmt ) { + if (fmt) { iFileFormat = fmt; } continue; } // main scene information - if (TokenMatch(filePtr,"SCENE",5)) - { + if (TokenMatch(filePtr, "SCENE", 5)) { ParseLV1SceneBlock(); continue; } // "group" - no implementation yet, in facte // we're just ignoring them for the moment - if (TokenMatch(filePtr,"GROUP",5)) - { + if (TokenMatch(filePtr, "GROUP", 5)) { Parse(); continue; } // material list - if (TokenMatch(filePtr,"MATERIAL_LIST",13)) - { + if (TokenMatch(filePtr, "MATERIAL_LIST", 13)) { ParseLV1MaterialListBlock(); continue; } // geometric object (mesh) - if (TokenMatch(filePtr,"GEOMOBJECT",10)) + if (TokenMatch(filePtr, "GEOMOBJECT", 10)) { m_vMeshes.push_back(Mesh("UNNAMED")); @@ -299,7 +270,7 @@ void Parser::Parse() continue; } // helper object = dummy in the hierarchy - if (TokenMatch(filePtr,"HELPEROBJECT",12)) + if (TokenMatch(filePtr, "HELPEROBJECT", 12)) { m_vDummies.push_back(Dummy()); @@ -307,7 +278,7 @@ void Parser::Parse() continue; } // light object - if (TokenMatch(filePtr,"LIGHTOBJECT",11)) + if (TokenMatch(filePtr, "LIGHTOBJECT", 11)) { m_vLights.push_back(Light("UNNAMED")); @@ -315,23 +286,20 @@ void Parser::Parse() continue; } // camera object - if (TokenMatch(filePtr,"CAMERAOBJECT",12)) - { + if (TokenMatch(filePtr, "CAMERAOBJECT", 12)) { m_vCameras.push_back(Camera("UNNAMED")); ParseLV1ObjectBlock(m_vCameras.back()); continue; } // comment - print it on the console - if (TokenMatch(filePtr,"COMMENT",7)) - { + if (TokenMatch(filePtr, "COMMENT", 7)) { std::string out = ""; - ParseString(out,"*COMMENT"); + ParseString(out, "*COMMENT"); LogInfo(("Comment: " + out).c_str()); continue; } // ASC bone weights - if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18)) - { + if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr, "MESH_SOFTSKINVERTS", 18)) { ParseLV1SoftSkinBlock(); } } @@ -341,8 +309,7 @@ void Parser::Parse() } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV1SoftSkinBlock() -{ +void Parser::ParseLV1SoftSkinBlock() { // TODO: fix line counting here // ************************************************************** @@ -364,80 +331,77 @@ void Parser::ParseLV1SoftSkinBlock() FORMAT END */ // ************************************************************** - while (true) - { - if (*filePtr == '}' ) {++filePtr;return;} - else if (*filePtr == '\0') return; - else if (*filePtr == '{' ) ++filePtr; + while (true) { + if (*filePtr == '}') { + ++filePtr; + return; + } else if (*filePtr == '\0') + return; + else if (*filePtr == '{') + ++filePtr; else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr)) { - ASE::Mesh* curMesh = NULL; - unsigned int numVerts = 0; + ASE::Mesh *curMesh = nullptr; + unsigned int numVerts = 0; - const char* sz = filePtr; - while (!IsSpaceOrNewLine(*filePtr))++filePtr; + const char *sz = filePtr; + while (!IsSpaceOrNewLine(*filePtr)) + ++filePtr; - const unsigned int diff = (unsigned int)(filePtr-sz); - if (diff) - { - std::string name = std::string(sz,diff); + const unsigned int diff = (unsigned int)(filePtr - sz); + if (diff) { + std::string name = std::string(sz, diff); for (std::vector::iterator it = m_vMeshes.begin(); - it != m_vMeshes.end(); ++it) - { - if ((*it).mName == name) - { - curMesh = & (*it); + it != m_vMeshes.end(); ++it) { + if ((*it).mName == name) { + curMesh = &(*it); break; } } - if (!curMesh) - { + if (!curMesh) { LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section"); // Skip the mesh data - until we find a new mesh // or the end of the *MESH_SOFTSKINVERTS section - while (true) - { + while (true) { SkipSpacesAndLineEnd(&filePtr); - if (*filePtr == '}') - {++filePtr;return;} - else if (!IsNumeric(*filePtr)) + if (*filePtr == '}') { + ++filePtr; + return; + } else if (!IsNumeric(*filePtr)) break; SkipLine(&filePtr); } - } - else - { + } else { SkipSpacesAndLineEnd(&filePtr); ParseLV4MeshLong(numVerts); // Reserve enough storage curMesh->mBoneVertices.reserve(numVerts); - for (unsigned int i = 0; i < numVerts;++i) - { + for (unsigned int i = 0; i < numVerts; ++i) { SkipSpacesAndLineEnd(&filePtr); unsigned int numWeights; ParseLV4MeshLong(numWeights); curMesh->mBoneVertices.push_back(ASE::BoneVertex()); - ASE::BoneVertex& vert = curMesh->mBoneVertices.back(); + ASE::BoneVertex &vert = curMesh->mBoneVertices.back(); // Reserve enough storage vert.mBoneWeights.reserve(numWeights); std::string bone; - for (unsigned int w = 0; w < numWeights;++w) { + for (unsigned int w = 0; w < numWeights; ++w) { bone.clear(); - ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); + ParseString(bone, "*MESH_SOFTSKINVERTS.Bone"); // Find the bone in the mesh's list - std::pair me; + std::pair me; me.first = -1; - for (unsigned int n = 0; n < curMesh->mBones.size();++n) { + for (unsigned int n = 0; n < curMesh->mBones.size(); ++n) { if (curMesh->mBones[n].mName == bone) { me.first = n; break; @@ -445,10 +409,10 @@ void Parser::ParseLV1SoftSkinBlock() } if (-1 == me.first) { // We don't have this bone yet, so add it to the list - me.first = static_cast( curMesh->mBones.size() ); - curMesh->mBones.push_back( ASE::Bone( bone ) ); + me.first = static_cast(curMesh->mBones.size()); + curMesh->mBones.push_back(ASE::Bone(bone)); } - ParseLV4MeshFloat( me.second ); + ParseLV4MeshFloat(me.second); // Add the new bone weight to list vert.mBoneWeights.push_back(me); @@ -463,45 +427,38 @@ void Parser::ParseLV1SoftSkinBlock() } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV1SceneBlock() -{ +void Parser::ParseLV1SceneBlock() { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23)) + if (TokenMatch(filePtr, "SCENE_BACKGROUND_STATIC", 23)) { // parse a color triple and assume it is really the bg color - ParseLV4MeshFloatTriple( &m_clrBackground.r ); + ParseLV4MeshFloatTriple(&m_clrBackground.r); continue; } - if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20)) + if (TokenMatch(filePtr, "SCENE_AMBIENT_STATIC", 20)) { // parse a color triple and assume it is really the bg color - ParseLV4MeshFloatTriple( &m_clrAmbient.r ); + ParseLV4MeshFloatTriple(&m_clrAmbient.r); continue; } - if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16)) - { + if (TokenMatch(filePtr, "SCENE_FIRSTFRAME", 16)) { ParseLV4MeshLong(iFirstFrame); continue; } - if (TokenMatch(filePtr,"SCENE_LASTFRAME",15)) - { + if (TokenMatch(filePtr, "SCENE_LASTFRAME", 15)) { ParseLV4MeshLong(iLastFrame); continue; } - if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16)) - { + if (TokenMatch(filePtr, "SCENE_FRAMESPEED", 16)) { ParseLV4MeshLong(iFrameSpeed); continue; } - if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19)) - { + if (TokenMatch(filePtr, "SCENE_TICKSPERFRAME", 19)) { ParseLV4MeshLong(iTicksPerFrame); continue; } @@ -511,38 +468,32 @@ void Parser::ParseLV1SceneBlock() } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV1MaterialListBlock() -{ +void Parser::ParseLV1MaterialListBlock() { AI_ASE_PARSER_INIT(); unsigned int iMaterialCount = 0; unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"MATERIAL_COUNT",14)) - { + if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) { ParseLV4MeshLong(iMaterialCount); // now allocate enough storage to hold all materials - m_vMaterials.resize(iOldMaterialCount+iMaterialCount, Material("INVALID")); + m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID")); continue; } - if (TokenMatch(filePtr,"MATERIAL",8)) - { + if (TokenMatch(filePtr, "MATERIAL", 8)) { unsigned int iIndex = 0; ParseLV4MeshLong(iIndex); - if (iIndex >= iMaterialCount) - { + if (iIndex >= iMaterialCount) { LogWarning("Out of range: material index is too large"); - iIndex = iMaterialCount-1; + iIndex = iMaterialCount - 1; } // get a reference to the material - Material& sMat = m_vMaterials[iIndex+iOldMaterialCount]; + Material &sMat = m_vMaterials[iIndex + iOldMaterialCount]; // parse the material block ParseLV2MaterialBlock(sMat); continue; @@ -553,61 +504,44 @@ void Parser::ParseLV1MaterialListBlock() } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2MaterialBlock(ASE::Material& mat) -{ +void Parser::ParseLV2MaterialBlock(ASE::Material &mat) { AI_ASE_PARSER_INIT(); unsigned int iNumSubMaterials = 0; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"MATERIAL_NAME",13)) - { - if (!ParseString(mat.mName,"*MATERIAL_NAME")) + if (TokenMatch(filePtr, "MATERIAL_NAME", 13)) { + if (!ParseString(mat.mName, "*MATERIAL_NAME")) SkipToNextToken(); continue; } // ambient material color - if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16)) - { + if (TokenMatch(filePtr, "MATERIAL_AMBIENT", 16)) { ParseLV4MeshFloatTriple(&mat.mAmbient.r); continue; } // diffuse material color - if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) ) - { + if (TokenMatch(filePtr, "MATERIAL_DIFFUSE", 16)) { ParseLV4MeshFloatTriple(&mat.mDiffuse.r); continue; } // specular material color - if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17)) - { + if (TokenMatch(filePtr, "MATERIAL_SPECULAR", 17)) { ParseLV4MeshFloatTriple(&mat.mSpecular.r); continue; } // material shading type - if (TokenMatch(filePtr,"MATERIAL_SHADING",16)) - { - if (TokenMatch(filePtr,"Blinn",5)) - { + if (TokenMatch(filePtr, "MATERIAL_SHADING", 16)) { + if (TokenMatch(filePtr, "Blinn", 5)) { mat.mShading = Discreet3DS::Blinn; - } - else if (TokenMatch(filePtr,"Phong",5)) - { + } else if (TokenMatch(filePtr, "Phong", 5)) { mat.mShading = Discreet3DS::Phong; - } - else if (TokenMatch(filePtr,"Flat",4)) - { + } else if (TokenMatch(filePtr, "Flat", 4)) { mat.mShading = Discreet3DS::Flat; - } - else if (TokenMatch(filePtr,"Wire",4)) - { + } else if (TokenMatch(filePtr, "Wire", 4)) { mat.mShading = Discreet3DS::Wire; - } - else - { + } else { // assume gouraud shading mat.mShading = Discreet3DS::Gouraud; SkipToNextToken(); @@ -615,15 +549,13 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat) continue; } // material transparency - if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21)) - { + if (TokenMatch(filePtr, "MATERIAL_TRANSPARENCY", 21)) { ParseLV4MeshFloat(mat.mTransparency); - mat.mTransparency = ai_real( 1.0 ) - mat.mTransparency; + mat.mTransparency = ai_real(1.0) - mat.mTransparency; continue; } // material self illumination - if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18)) - { + if (TokenMatch(filePtr, "MATERIAL_SELFILLUM", 18)) { ai_real f = 0.0; ParseLV4MeshFloat(f); @@ -633,108 +565,94 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat) continue; } // material shininess - if (TokenMatch(filePtr,"MATERIAL_SHINE",14) ) - { + if (TokenMatch(filePtr, "MATERIAL_SHINE", 14)) { ParseLV4MeshFloat(mat.mSpecularExponent); mat.mSpecularExponent *= 15; continue; } // two-sided material - if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) ) - { + if (TokenMatch(filePtr, "MATERIAL_TWOSIDED", 17)) { mat.mTwoSided = true; continue; } // material shininess strength - if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22)) - { + if (TokenMatch(filePtr, "MATERIAL_SHINESTRENGTH", 22)) { ParseLV4MeshFloat(mat.mShininessStrength); continue; } // diffuse color map - if (TokenMatch(filePtr,"MAP_DIFFUSE",11)) - { + if (TokenMatch(filePtr, "MAP_DIFFUSE", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexDiffuse); continue; } // ambient color map - if (TokenMatch(filePtr,"MAP_AMBIENT",11)) - { + if (TokenMatch(filePtr, "MAP_AMBIENT", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexAmbient); continue; } // specular color map - if (TokenMatch(filePtr,"MAP_SPECULAR",12)) - { + if (TokenMatch(filePtr, "MAP_SPECULAR", 12)) { // parse the texture block ParseLV3MapBlock(mat.sTexSpecular); continue; } // opacity map - if (TokenMatch(filePtr,"MAP_OPACITY",11)) - { + if (TokenMatch(filePtr, "MAP_OPACITY", 11)) { // parse the texture block ParseLV3MapBlock(mat.sTexOpacity); continue; } // emissive map - if (TokenMatch(filePtr,"MAP_SELFILLUM",13)) - { + if (TokenMatch(filePtr, "MAP_SELFILLUM", 13)) { // parse the texture block ParseLV3MapBlock(mat.sTexEmissive); continue; } // bump map - if (TokenMatch(filePtr,"MAP_BUMP",8)) - { + if (TokenMatch(filePtr, "MAP_BUMP", 8)) { // parse the texture block ParseLV3MapBlock(mat.sTexBump); } // specular/shininess map - if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17)) - { + if (TokenMatch(filePtr, "MAP_SHINESTRENGTH", 17)) { // parse the texture block ParseLV3MapBlock(mat.sTexShininess); continue; } // number of submaterials - if (TokenMatch(filePtr,"NUMSUBMTLS",10)) - { + if (TokenMatch(filePtr, "NUMSUBMTLS", 10)) { ParseLV4MeshLong(iNumSubMaterials); // allocate enough storage mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL")); } // submaterial chunks - if (TokenMatch(filePtr,"SUBMATERIAL",11)) - { + if (TokenMatch(filePtr, "SUBMATERIAL", 11)) { unsigned int iIndex = 0; ParseLV4MeshLong(iIndex); - if (iIndex >= iNumSubMaterials) - { + if (iIndex >= iNumSubMaterials) { LogWarning("Out of range: submaterial index is too large"); - iIndex = iNumSubMaterials-1; + iIndex = iNumSubMaterials - 1; } // get a reference to the material - Material& sMat = mat.avSubMaterials[iIndex]; + Material &sMat = mat.avSubMaterials[iIndex]; // parse the material block ParseLV2MaterialBlock(sMat); continue; } } - AI_ASE_HANDLE_SECTION("2","*MATERIAL"); + AI_ASE_HANDLE_SECTION("2", "*MATERIAL"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MapBlock(Texture& map) -{ +void Parser::ParseLV3MapBlock(Texture &map) { AI_ASE_PARSER_INIT(); // *********************************************************** @@ -744,32 +662,26 @@ void Parser::ParseLV3MapBlock(Texture& map) // *********************************************************** bool parsePath = true; std::string temp; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // type of map - if (TokenMatch(filePtr,"MAP_CLASS" ,9)) - { + if (TokenMatch(filePtr, "MAP_CLASS", 9)) { temp.clear(); - if(!ParseString(temp,"*MAP_CLASS")) + if (!ParseString(temp, "*MAP_CLASS")) SkipToNextToken(); - if (temp != "Bitmap" && temp != "Normal Bump") - { + if (temp != "Bitmap" && temp != "Normal Bump") { ASSIMP_LOG_WARN_F("ASE: Skipping unknown map type: ", temp); parsePath = false; } continue; } // path to the texture - if (parsePath && TokenMatch(filePtr,"BITMAP" ,6)) - { - if(!ParseString(map.mMapName,"*BITMAP")) + if (parsePath && TokenMatch(filePtr, "BITMAP", 6)) { + if (!ParseString(map.mMapName, "*BITMAP")) SkipToNextToken(); - if (map.mMapName == "None") - { + if (map.mMapName == "None") { // Files with 'None' as map name are produced by // an Maja to ASE exporter which name I forgot .. ASSIMP_LOG_WARN("ASE: Skipping invalid map entry"); @@ -779,198 +691,157 @@ void Parser::ParseLV3MapBlock(Texture& map) continue; } // offset on the u axis - if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12)) - { + if (TokenMatch(filePtr, "UVW_U_OFFSET", 12)) { ParseLV4MeshFloat(map.mOffsetU); continue; } // offset on the v axis - if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12)) - { + if (TokenMatch(filePtr, "UVW_V_OFFSET", 12)) { ParseLV4MeshFloat(map.mOffsetV); continue; } // tiling on the u axis - if (TokenMatch(filePtr,"UVW_U_TILING" ,12)) - { + if (TokenMatch(filePtr, "UVW_U_TILING", 12)) { ParseLV4MeshFloat(map.mScaleU); continue; } // tiling on the v axis - if (TokenMatch(filePtr,"UVW_V_TILING" ,12)) - { + if (TokenMatch(filePtr, "UVW_V_TILING", 12)) { ParseLV4MeshFloat(map.mScaleV); continue; } // rotation around the z-axis - if (TokenMatch(filePtr,"UVW_ANGLE" ,9)) - { + if (TokenMatch(filePtr, "UVW_ANGLE", 9)) { ParseLV4MeshFloat(map.mRotation); continue; } // map blending factor - if (TokenMatch(filePtr,"MAP_AMOUNT" ,10)) - { + if (TokenMatch(filePtr, "MAP_AMOUNT", 10)) { ParseLV4MeshFloat(map.mTextureBlend); continue; } } - AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX"); + AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX"); } return; } // ------------------------------------------------------------------------------------------------ -bool Parser::ParseString(std::string& out,const char* szName) -{ +bool Parser::ParseString(std::string &out, const char *szName) { char szBuffer[1024]; - if (!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { - ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL",szName); + ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName); LogWarning(szBuffer); return false; } // there must be '"' - if ('\"' != *filePtr) - { + if ('\"' != *filePtr) { ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected " - "to be enclosed in double quotation marks",szName); + "to be enclosed in double quotation marks", + szName); LogWarning(szBuffer); return false; } ++filePtr; - const char* sz = filePtr; - while (true) - { - if ('\"' == *sz)break; - else if ('\0' == *sz) - { + const char *sz = filePtr; + while (true) { + if ('\"' == *sz) + break; + else if ('\0' == *sz) { ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected to " - "be enclosed in double quotation marks but EOF was reached before " - "a closing quotation mark was encountered",szName); + "be enclosed in double quotation marks but EOF was reached before " + "a closing quotation mark was encountered", + szName); LogWarning(szBuffer); return false; } sz++; } - out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr); - filePtr = sz+1; + out = std::string(filePtr, (uintptr_t)sz - (uintptr_t)filePtr); + filePtr = sz + 1; return true; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node) -{ +void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // first process common tokens such as node name and transform // name of the mesh/node - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { - if(!ParseString(node.mName,"*NODE_NAME")) + if (TokenMatch(filePtr, "NODE_NAME", 9)) { + if (!ParseString(node.mName, "*NODE_NAME")) SkipToNextToken(); continue; } // name of the parent of the node - if (TokenMatch(filePtr,"NODE_PARENT" ,11) ) - { - if(!ParseString(node.mParent,"*NODE_PARENT")) + if (TokenMatch(filePtr, "NODE_PARENT", 11)) { + if (!ParseString(node.mParent, "*NODE_PARENT")) SkipToNextToken(); continue; } // transformation matrix of the node - if (TokenMatch(filePtr,"NODE_TM" ,7)) - { + if (TokenMatch(filePtr, "NODE_TM", 7)) { ParseLV2NodeTransformBlock(node); continue; } // animation data of the node - if (TokenMatch(filePtr,"TM_ANIMATION" ,12)) - { + if (TokenMatch(filePtr, "TM_ANIMATION", 12)) { ParseLV2AnimationBlock(node); continue; } - if (node.mType == BaseNode::Light) - { + if (node.mType == BaseNode::Light) { // light settings - if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14)) - { - ParseLV2LightSettingsBlock((ASE::Light&)node); + if (TokenMatch(filePtr, "LIGHT_SETTINGS", 14)) { + ParseLV2LightSettingsBlock((ASE::Light &)node); continue; } // type of the light source - if (TokenMatch(filePtr,"LIGHT_TYPE" ,10)) - { - if (!ASSIMP_strincmp("omni",filePtr,4)) - { - ((ASE::Light&)node).mLightType = ASE::Light::OMNI; - } - else if (!ASSIMP_strincmp("target",filePtr,6)) - { - ((ASE::Light&)node).mLightType = ASE::Light::TARGET; - } - else if (!ASSIMP_strincmp("free",filePtr,4)) - { - ((ASE::Light&)node).mLightType = ASE::Light::FREE; - } - else if (!ASSIMP_strincmp("directional",filePtr,11)) - { - ((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL; - } - else - { + if (TokenMatch(filePtr, "LIGHT_TYPE", 10)) { + if (!ASSIMP_strincmp("omni", filePtr, 4)) { + ((ASE::Light &)node).mLightType = ASE::Light::OMNI; + } else if (!ASSIMP_strincmp("target", filePtr, 6)) { + ((ASE::Light &)node).mLightType = ASE::Light::TARGET; + } else if (!ASSIMP_strincmp("free", filePtr, 4)) { + ((ASE::Light &)node).mLightType = ASE::Light::FREE; + } else if (!ASSIMP_strincmp("directional", filePtr, 11)) { + ((ASE::Light &)node).mLightType = ASE::Light::DIRECTIONAL; + } else { LogWarning("Unknown kind of light source"); } continue; } - } - else if (node.mType == BaseNode::Camera) - { + } else if (node.mType == BaseNode::Camera) { // Camera settings - if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15)) - { - ParseLV2CameraSettingsBlock((ASE::Camera&)node); + if (TokenMatch(filePtr, "CAMERA_SETTINGS", 15)) { + ParseLV2CameraSettingsBlock((ASE::Camera &)node); continue; - } - else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11)) - { - if (!ASSIMP_strincmp("target",filePtr,6)) - { - ((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET; - } - else if (!ASSIMP_strincmp("free",filePtr,4)) - { - ((ASE::Camera&)node).mCameraType = ASE::Camera::FREE; - } - else - { + } else if (TokenMatch(filePtr, "CAMERA_TYPE", 11)) { + if (!ASSIMP_strincmp("target", filePtr, 6)) { + ((ASE::Camera &)node).mCameraType = ASE::Camera::TARGET; + } else if (!ASSIMP_strincmp("free", filePtr, 4)) { + ((ASE::Camera &)node).mCameraType = ASE::Camera::FREE; + } else { LogWarning("Unknown kind of camera"); } continue; } - } - else if (node.mType == BaseNode::Mesh) - { + } else if (node.mType == BaseNode::Mesh) { // mesh data // FIX: Older files use MESH_SOFTSKIN - if (TokenMatch(filePtr,"MESH" ,4) || - TokenMatch(filePtr,"MESH_SOFTSKIN",13)) - { - ParseLV2MeshBlock((ASE::Mesh&)node); + if (TokenMatch(filePtr, "MESH", 4) || + TokenMatch(filePtr, "MESH_SOFTSKIN", 13)) { + ParseLV2MeshBlock((ASE::Mesh &)node); continue; } // mesh material index - if (TokenMatch(filePtr,"MATERIAL_REF" ,12)) - { - ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex); + if (TokenMatch(filePtr, "MATERIAL_REF", 12)) { + ParseLV4MeshLong(((ASE::Mesh &)node).iMaterialIndex); continue; } } @@ -981,156 +852,131 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node) } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2CameraSettingsBlock(ASE::Camera& camera) -{ +void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"CAMERA_NEAR" ,11)) - { + if (TokenMatch(filePtr, "CAMERA_NEAR", 11)) { ParseLV4MeshFloat(camera.mNear); continue; } - if (TokenMatch(filePtr,"CAMERA_FAR" ,10)) - { + if (TokenMatch(filePtr, "CAMERA_FAR", 10)) { ParseLV4MeshFloat(camera.mFar); continue; } - if (TokenMatch(filePtr,"CAMERA_FOV" ,10)) - { + if (TokenMatch(filePtr, "CAMERA_FOV", 10)) { ParseLV4MeshFloat(camera.mFOV); continue; } } - AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS"); + AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2LightSettingsBlock(ASE::Light& light) -{ +void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"LIGHT_COLOR" ,11)) - { + if (TokenMatch(filePtr, "LIGHT_COLOR", 11)) { ParseLV4MeshFloatTriple(&light.mColor.r); continue; } - if (TokenMatch(filePtr,"LIGHT_INTENS" ,12)) - { + if (TokenMatch(filePtr, "LIGHT_INTENS", 12)) { ParseLV4MeshFloat(light.mIntensity); continue; } - if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13)) - { + if (TokenMatch(filePtr, "LIGHT_HOTSPOT", 13)) { ParseLV4MeshFloat(light.mAngle); continue; } - if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13)) - { + if (TokenMatch(filePtr, "LIGHT_FALLOFF", 13)) { ParseLV4MeshFloat(light.mFalloff); continue; } } - AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS"); + AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh) -{ +void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) { AI_ASE_PARSER_INIT(); - ASE::Animation* anim = &mesh.mAnim; - while (true) - { - if ('*' == *filePtr) - { + ASE::Animation *anim = &mesh.mAnim; + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { + if (TokenMatch(filePtr, "NODE_NAME", 9)) { std::string temp; - if(!ParseString(temp,"*NODE_NAME")) + if (!ParseString(temp, "*NODE_NAME")) SkipToNextToken(); // If the name of the node contains .target it // represents an animated camera or spot light // target. - if (std::string::npos != temp.find(".Target")) - { - if ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET) && - ( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET)) - { + if (std::string::npos != temp.find(".Target")) { + if ((mesh.mType != BaseNode::Camera || ((ASE::Camera &)mesh).mCameraType != ASE::Camera::TARGET) && + (mesh.mType != BaseNode::Light || ((ASE::Light &)mesh).mLightType != ASE::Light::TARGET)) { ASSIMP_LOG_ERROR("ASE: Found target animation channel " - "but the node is neither a camera nor a spot light"); - anim = NULL; - } - else anim = &mesh.mTargetAnim; + "but the node is neither a camera nor a spot light"); + anim = nullptr; + } else + anim = &mesh.mTargetAnim; } continue; } // position keyframes - if (TokenMatch(filePtr,"CONTROL_POS_TRACK" ,17) || - TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18) || - TokenMatch(filePtr,"CONTROL_POS_TCB" ,15)) - { - if (!anim)SkipSection(); - else ParseLV3PosAnimationBlock(*anim); + if (TokenMatch(filePtr, "CONTROL_POS_TRACK", 17) || + TokenMatch(filePtr, "CONTROL_POS_BEZIER", 18) || + TokenMatch(filePtr, "CONTROL_POS_TCB", 15)) { + if (!anim) + SkipSection(); + else + ParseLV3PosAnimationBlock(*anim); continue; } // scaling keyframes - if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK" ,19) || - TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) || - TokenMatch(filePtr,"CONTROL_SCALE_TCB" ,17)) - { - if (!anim || anim == &mesh.mTargetAnim) - { + if (TokenMatch(filePtr, "CONTROL_SCALE_TRACK", 19) || + TokenMatch(filePtr, "CONTROL_SCALE_BEZIER", 20) || + TokenMatch(filePtr, "CONTROL_SCALE_TCB", 17)) { + if (!anim || anim == &mesh.mTargetAnim) { // Target animation channels may have no rotation channels ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation"); SkipSection(); - } - else ParseLV3ScaleAnimationBlock(*anim); + } else + ParseLV3ScaleAnimationBlock(*anim); continue; } // rotation keyframes - if (TokenMatch(filePtr,"CONTROL_ROT_TRACK" ,17) || - TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) || - TokenMatch(filePtr,"CONTROL_ROT_TCB" ,15)) - { - if (!anim || anim == &mesh.mTargetAnim) - { + if (TokenMatch(filePtr, "CONTROL_ROT_TRACK", 17) || + TokenMatch(filePtr, "CONTROL_ROT_BEZIER", 18) || + TokenMatch(filePtr, "CONTROL_ROT_TCB", 15)) { + if (!anim || anim == &mesh.mTargetAnim) { // Target animation channels may have no rotation channels ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation"); SkipSection(); - } - else ParseLV3RotAnimationBlock(*anim); + } else + ParseLV3RotAnimationBlock(*anim); continue; } } - AI_ASE_HANDLE_SECTION("2","TM_ANIMATION"); + AI_ASE_HANDLE_SECTION("2", "TM_ANIMATION"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim) -{ +void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation &anim) { AI_ASE_PARSER_INIT(); unsigned int iIndex; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; bool b = false; @@ -1139,44 +985,37 @@ void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim) // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20)) - { + if (TokenMatch(filePtr, "CONTROL_SCALE_SAMPLE", 20)) { b = true; anim.mScalingType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24)) - { + if (TokenMatch(filePtr, "CONTROL_BEZIER_SCALE_KEY", 24)) { b = true; anim.mScalingType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21)) - { + if (TokenMatch(filePtr, "CONTROL_TCB_SCALE_KEY", 21)) { b = true; anim.mScalingType = ASE::Animation::TCB; } - if (b) - { + if (b) { anim.akeyScaling.push_back(aiVectorKey()); - aiVectorKey& key = anim.akeyScaling.back(); - ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); + aiVectorKey &key = anim.akeyScaling.back(); + ParseLV4MeshFloatTriple(&key.mValue.x, iIndex); key.mTime = (double)iIndex; } } - AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); + AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim) -{ +void Parser::ParseLV3PosAnimationBlock(ASE::Animation &anim) { AI_ASE_PARSER_INIT(); unsigned int iIndex; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; bool b = false; @@ -1185,44 +1024,37 @@ void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim) // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18)) - { + if (TokenMatch(filePtr, "CONTROL_POS_SAMPLE", 18)) { b = true; anim.mPositionType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22)) - { + if (TokenMatch(filePtr, "CONTROL_BEZIER_POS_KEY", 22)) { b = true; anim.mPositionType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19)) - { + if (TokenMatch(filePtr, "CONTROL_TCB_POS_KEY", 19)) { b = true; anim.mPositionType = ASE::Animation::TCB; } - if (b) - { + if (b) { anim.akeyPositions.push_back(aiVectorKey()); - aiVectorKey& key = anim.akeyPositions.back(); - ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); + aiVectorKey &key = anim.akeyPositions.back(); + ParseLV4MeshFloatTriple(&key.mValue.x, iIndex); key.mTime = (double)iIndex; } } - AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); + AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim) -{ +void Parser::ParseLV3RotAnimationBlock(ASE::Animation &anim) { AI_ASE_PARSER_INIT(); unsigned int iIndex; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; bool b = false; @@ -1231,150 +1063,126 @@ void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim) // we ignore the additional information for bezier's and TCBs // simple scaling keyframe - if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18)) - { + if (TokenMatch(filePtr, "CONTROL_ROT_SAMPLE", 18)) { b = true; anim.mRotationType = ASE::Animation::TRACK; } // Bezier scaling keyframe - if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22)) - { + if (TokenMatch(filePtr, "CONTROL_BEZIER_ROT_KEY", 22)) { b = true; anim.mRotationType = ASE::Animation::BEZIER; } // TCB scaling keyframe - if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19)) - { + if (TokenMatch(filePtr, "CONTROL_TCB_ROT_KEY", 19)) { b = true; anim.mRotationType = ASE::Animation::TCB; } - if (b) - { + if (b) { anim.akeyRotations.push_back(aiQuatKey()); - aiQuatKey& key = anim.akeyRotations.back(); - aiVector3D v;ai_real f; - ParseLV4MeshFloatTriple(&v.x,iIndex); + aiQuatKey &key = anim.akeyRotations.back(); + aiVector3D v; + ai_real f; + ParseLV4MeshFloatTriple(&v.x, iIndex); ParseLV4MeshFloat(f); key.mTime = (double)iIndex; - key.mValue = aiQuaternion(v,f); + key.mValue = aiQuaternion(v, f); } } - AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK"); + AI_ASE_HANDLE_SECTION("3", "*CONTROL_ROT_TRACK"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh) -{ +void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) { AI_ASE_PARSER_INIT(); - int mode = 0; - while (true) - { - if ('*' == *filePtr) - { + int mode = 0; + while (true) { + if ('*' == *filePtr) { ++filePtr; // name of the node - if (TokenMatch(filePtr,"NODE_NAME" ,9)) - { + if (TokenMatch(filePtr, "NODE_NAME", 9)) { std::string temp; - if(!ParseString(temp,"*NODE_NAME")) + if (!ParseString(temp, "*NODE_NAME")) SkipToNextToken(); std::string::size_type s; - if (temp == mesh.mName) - { + if (temp == mesh.mName) { mode = 1; - } - else if (std::string::npos != (s = temp.find(".Target")) && - mesh.mName == temp.substr(0,s)) - { + } else if (std::string::npos != (s = temp.find(".Target")) && + mesh.mName == temp.substr(0, s)) { // This should be either a target light or a target camera - if ( (mesh.mType == BaseNode::Light && ((ASE::Light&)mesh) .mLightType == ASE::Light::TARGET) || - (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET)) - { + if ((mesh.mType == BaseNode::Light && ((ASE::Light &)mesh).mLightType == ASE::Light::TARGET) || + (mesh.mType == BaseNode::Camera && ((ASE::Camera &)mesh).mCameraType == ASE::Camera::TARGET)) { mode = 2; - } - else { + } else { ASSIMP_LOG_ERROR("ASE: Ignoring target transform, " - "this is no spot light or target camera"); + "this is no spot light or target camera"); } - } - else - { + } else { ASSIMP_LOG_ERROR("ASE: Unknown node transformation: " + temp); // mode = 0 } continue; } - if (mode) - { + if (mode) { // fourth row of the transformation matrix - and also the // only information here that is interesting for targets - if (TokenMatch(filePtr,"TM_ROW3" ,7)) - { + if (TokenMatch(filePtr, "TM_ROW3", 7)) { ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x)); continue; } - if (mode == 1) - { + if (mode == 1) { // first row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW0" ,7)) - { + if (TokenMatch(filePtr, "TM_ROW0", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[0]); continue; } // second row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW1" ,7)) - { + if (TokenMatch(filePtr, "TM_ROW1", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[1]); continue; } // third row of the transformation matrix - if (TokenMatch(filePtr,"TM_ROW2" ,7)) - { + if (TokenMatch(filePtr, "TM_ROW2", 7)) { ParseLV4MeshFloatTriple(mesh.mTransform[2]); continue; } // inherited position axes - if (TokenMatch(filePtr,"INHERIT_POS" ,11)) - { + if (TokenMatch(filePtr, "INHERIT_POS", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); - for (unsigned int i = 0; i < 3;++i) + for (unsigned int i = 0; i < 3; ++i) mesh.inherit.abInheritPosition[i] = aiVal[i] != 0; continue; } // inherited rotation axes - if (TokenMatch(filePtr,"INHERIT_ROT" ,11)) - { + if (TokenMatch(filePtr, "INHERIT_ROT", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); - for (unsigned int i = 0; i < 3;++i) + for (unsigned int i = 0; i < 3; ++i) mesh.inherit.abInheritRotation[i] = aiVal[i] != 0; continue; } // inherited scaling axes - if (TokenMatch(filePtr,"INHERIT_SCL" ,11)) - { + if (TokenMatch(filePtr, "INHERIT_SCL", 11)) { unsigned int aiVal[3]; ParseLV4MeshLongTriple(aiVal); - for (unsigned int i = 0; i < 3;++i) + for (unsigned int i = 0; i < 3; ++i) mesh.inherit.abInheritScaling[i] = aiVal[i] != 0; continue; } } } } - AI_ASE_HANDLE_SECTION("2","*NODE_TM"); + AI_ASE_HANDLE_SECTION("2", "*NODE_TM"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh) -{ +void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); unsigned int iNumVertices = 0; @@ -1383,386 +1191,327 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh) unsigned int iNumTFaces = 0; unsigned int iNumCVertices = 0; unsigned int iNumCFaces = 0; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Number of vertices in the mesh - if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) - { + if (TokenMatch(filePtr, "MESH_NUMVERTEX", 14)) { ParseLV4MeshLong(iNumVertices); continue; } // Number of texture coordinates in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMTVERTEX", 15)) { ParseLV4MeshLong(iNumTVertices); continue; } // Number of vertex colors in the mesh - if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMCVERTEX", 15)) { ParseLV4MeshLong(iNumCVertices); continue; } // Number of regular faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMFACES" ,13)) - { + if (TokenMatch(filePtr, "MESH_NUMFACES", 13)) { ParseLV4MeshLong(iNumFaces); continue; } // Number of UVWed faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMTVFACES", 15)) { ParseLV4MeshLong(iNumTFaces); continue; } // Number of colored faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMCVFACES", 15)) { ParseLV4MeshLong(iNumCFaces); continue; } // mesh vertex list block - if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16)) - { - ParseLV3MeshVertexListBlock(iNumVertices,mesh); + if (TokenMatch(filePtr, "MESH_VERTEX_LIST", 16)) { + ParseLV3MeshVertexListBlock(iNumVertices, mesh); continue; } // mesh face list block - if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14)) - { - ParseLV3MeshFaceListBlock(iNumFaces,mesh); + if (TokenMatch(filePtr, "MESH_FACE_LIST", 14)) { + ParseLV3MeshFaceListBlock(iNumFaces, mesh); continue; } // mesh texture vertex list block - if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) - { - ParseLV3MeshTListBlock(iNumTVertices,mesh); + if (TokenMatch(filePtr, "MESH_TVERTLIST", 14)) { + ParseLV3MeshTListBlock(iNumTVertices, mesh); continue; } // mesh texture face block - if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) - { - ParseLV3MeshTFaceListBlock(iNumTFaces,mesh); + if (TokenMatch(filePtr, "MESH_TFACELIST", 14)) { + ParseLV3MeshTFaceListBlock(iNumTFaces, mesh); continue; } // mesh color vertex list block - if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14)) - { - ParseLV3MeshCListBlock(iNumCVertices,mesh); + if (TokenMatch(filePtr, "MESH_CVERTLIST", 14)) { + ParseLV3MeshCListBlock(iNumCVertices, mesh); continue; } // mesh color face block - if (TokenMatch(filePtr,"MESH_CFACELIST" ,14)) - { - ParseLV3MeshCFaceListBlock(iNumCFaces,mesh); + if (TokenMatch(filePtr, "MESH_CFACELIST", 14)) { + ParseLV3MeshCFaceListBlock(iNumCFaces, mesh); continue; } // mesh normals - if (TokenMatch(filePtr,"MESH_NORMALS" ,12)) - { + if (TokenMatch(filePtr, "MESH_NORMALS", 12)) { ParseLV3MeshNormalListBlock(mesh); continue; } // another mesh UV channel ... - if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19)) { - unsigned int iIndex( 0 ); + if (TokenMatch(filePtr, "MESH_MAPPINGCHANNEL", 19)) { + unsigned int iIndex(0); ParseLV4MeshLong(iIndex); - if ( 0 == iIndex ) { - LogWarning( "Mapping channel has an invalid index. Skipping UV channel" ); + if (0 == iIndex) { + LogWarning("Mapping channel has an invalid index. Skipping UV channel"); // skip it ... SkipSection(); } else { - if ( iIndex < 2 ) { - LogWarning( "Mapping channel has an invalid index. Skipping UV channel" ); + if (iIndex < 2) { + LogWarning("Mapping channel has an invalid index. Skipping UV channel"); // skip it ... SkipSection(); } - if ( iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS ) { - LogWarning( "Too many UV channels specified. Skipping channel .." ); + if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) { + LogWarning("Too many UV channels specified. Skipping channel .."); // skip it ... SkipSection(); } else { // parse the mapping channel - ParseLV3MappingChannel( iIndex - 1, mesh ); + ParseLV3MappingChannel(iIndex - 1, mesh); } continue; } } // mesh animation keyframe. Not supported - if (TokenMatch(filePtr,"MESH_ANIMATION" ,14)) - { + if (TokenMatch(filePtr, "MESH_ANIMATION", 14)) { LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. " - "Keyframe animation is not supported by Assimp, this element " - "will be ignored"); + "Keyframe animation is not supported by Assimp, this element " + "will be ignored"); //SkipSection(); continue; } - if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12)) - { - ParseLV3MeshWeightsBlock(mesh);continue; + if (TokenMatch(filePtr, "MESH_WEIGHTS", 12)) { + ParseLV3MeshWeightsBlock(mesh); + continue; } } - AI_ASE_HANDLE_SECTION("2","*MESH"); + AI_ASE_HANDLE_SECTION("2", "*MESH"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh) -{ +void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); unsigned int iNumVertices = 0, iNumBones = 0; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Number of bone vertices ... - if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) - { + if (TokenMatch(filePtr, "MESH_NUMVERTEX", 14)) { ParseLV4MeshLong(iNumVertices); continue; } // Number of bones - if (TokenMatch(filePtr,"MESH_NUMBONE" ,12)) - { + if (TokenMatch(filePtr, "MESH_NUMBONE", 12)) { ParseLV4MeshLong(iNumBones); continue; } // parse the list of bones - if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14)) - { - ParseLV4MeshBones(iNumBones,mesh); + if (TokenMatch(filePtr, "MESH_BONE_LIST", 14)) { + ParseLV4MeshBones(iNumBones, mesh); continue; } // parse the list of bones vertices - if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) ) - { - ParseLV4MeshBonesVertices(iNumVertices,mesh); + if (TokenMatch(filePtr, "MESH_BONE_VERTEX_LIST", 21)) { + ParseLV4MeshBonesVertices(iNumVertices, mesh); continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS"); + AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh) -{ +void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); mesh.mBones.resize(iNumBones, Bone("UNNAMED")); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Mesh bone with name ... - if (TokenMatch(filePtr,"MESH_BONE_NAME" ,14)) - { + if (TokenMatch(filePtr, "MESH_BONE_NAME", 14)) { // parse an index ... - if(SkipSpaces(&filePtr)) - { - unsigned int iIndex = strtoul10(filePtr,&filePtr); - if (iIndex >= iNumBones) - { + if (SkipSpaces(&filePtr)) { + unsigned int iIndex = strtoul10(filePtr, &filePtr); + if (iIndex >= iNumBones) { LogWarning("Bone index is out of bounds"); continue; } - if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME")) + if (!ParseString(mesh.mBones[iIndex].mName, "*MESH_BONE_NAME")) SkipToNextToken(); continue; } } } - AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_BONE_LIST"); } } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh& mesh) -{ +void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); mesh.mBoneVertices.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Mesh bone vertex - if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16)) - { + if (TokenMatch(filePtr, "MESH_BONE_VERTEX", 16)) { // read the vertex index - unsigned int iIndex = strtoul10(filePtr,&filePtr); - if (iIndex >= mesh.mPositions.size()) - { - iIndex = (unsigned int)mesh.mPositions.size()-1; + unsigned int iIndex = strtoul10(filePtr, &filePtr); + if (iIndex >= mesh.mPositions.size()) { + iIndex = (unsigned int)mesh.mPositions.size() - 1; LogWarning("Bone vertex index is out of bounds. Using the largest valid " - "bone vertex index instead"); + "bone vertex index instead"); } // --- ignored ai_real afVert[3]; ParseLV4MeshFloatTriple(afVert); - std::pair pairOut; - while (true) - { + std::pair pairOut; + while (true) { // first parse the bone index ... - if (!SkipSpaces(&filePtr))break; - pairOut.first = strtoul10(filePtr,&filePtr); + if (!SkipSpaces(&filePtr)) break; + pairOut.first = strtoul10(filePtr, &filePtr); // then parse the vertex weight - if (!SkipSpaces(&filePtr))break; - filePtr = fast_atoreal_move(filePtr,pairOut.second); + if (!SkipSpaces(&filePtr)) break; + filePtr = fast_atoreal_move(filePtr, pairOut.second); // -1 marks unused entries - if (-1 != pairOut.first) - { + if (-1 != pairOut.first) { mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut); } } continue; } } - AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX"); + AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX"); } return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshVertexListBlock( - unsigned int iNumVertices, ASE::Mesh& mesh) -{ + unsigned int iNumVertices, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); // allocate enough storage in the array mesh.mPositions.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Vertex entry - if (TokenMatch(filePtr,"MESH_VERTEX" ,11)) - { + if (TokenMatch(filePtr, "MESH_VERTEX", 11)) { aiVector3D vTemp; unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.x,iIndex); + ParseLV4MeshFloatTriple(&vTemp.x, iIndex); - if (iIndex >= iNumVertices) - { + if (iIndex >= iNumVertices) { LogWarning("Invalid vertex index. It will be ignored"); - } - else mesh.mPositions[iIndex] = vTemp; + } else + mesh.mPositions[iIndex] = vTemp; continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) -{ +void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); // allocate enough storage in the face array mesh.mFaces.resize(iNumFaces); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Face entry - if (TokenMatch(filePtr,"MESH_FACE" ,9)) - { + if (TokenMatch(filePtr, "MESH_FACE", 9)) { ASE::Face mFace; ParseLV4MeshFace(mFace); - if (mFace.iFace >= iNumFaces) - { + if (mFace.iFace >= iNumFaces) { LogWarning("Face has an invalid index. It will be ignored"); - } - else mesh.mFaces[mFace.iFace] = mFace; + } else + mesh.mFaces[mFace.iFace] = mFace; continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST"); } return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices, - ASE::Mesh& mesh, unsigned int iChannel) -{ + ASE::Mesh &mesh, unsigned int iChannel) { AI_ASE_PARSER_INIT(); // allocate enough storage in the array mesh.amTexCoords[iChannel].resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Vertex entry - if (TokenMatch(filePtr,"MESH_TVERT" ,10)) - { + if (TokenMatch(filePtr, "MESH_TVERT", 10)) { aiVector3D vTemp; unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.x,iIndex); + ParseLV4MeshFloatTriple(&vTemp.x, iIndex); - if (iIndex >= iNumVertices) - { + if (iIndex >= iNumVertices) { LogWarning("Tvertex has an invalid index. It will be ignored"); - } - else mesh.amTexCoords[iChannel][iIndex] = vTemp; + } else + mesh.amTexCoords[iChannel][iIndex] = vTemp; - if (0.0f != vTemp.z) - { + if (0.0f != vTemp.z) { // we need 3 coordinate channels mesh.mNumUVComponents[iChannel] = 3; } continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST"); } return; } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, - ASE::Mesh& mesh, unsigned int iChannel) -{ + ASE::Mesh &mesh, unsigned int iChannel) { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Face entry - if (TokenMatch(filePtr,"MESH_TFACE" ,10)) - { + if (TokenMatch(filePtr, "MESH_TFACE", 10)) { unsigned int aiValues[3]; unsigned int iIndex = 0; - ParseLV4MeshLongTriple(aiValues,iIndex); - if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) - { + ParseLV4MeshLongTriple(aiValues, iIndex); + if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) { LogWarning("UV-Face has an invalid index. It will be ignored"); - } - else - { + } else { // copy UV indices mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0]; mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1]; @@ -1771,108 +1520,89 @@ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh& mesh) -{ +void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); unsigned int iNumTVertices = 0; unsigned int iNumTFaces = 0; - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Number of texture coordinates in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMTVERTEX", 15)) { ParseLV4MeshLong(iNumTVertices); continue; } // Number of UVWed faces in the mesh - if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) - { + if (TokenMatch(filePtr, "MESH_NUMTVFACES", 15)) { ParseLV4MeshLong(iNumTFaces); continue; } // mesh texture vertex list block - if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) - { - ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel); + if (TokenMatch(filePtr, "MESH_TVERTLIST", 14)) { + ParseLV3MeshTListBlock(iNumTVertices, mesh, iChannel); continue; } // mesh texture face block - if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) - { - ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel); + if (TokenMatch(filePtr, "MESH_TFACELIST", 14)) { + ParseLV3MeshTFaceListBlock(iNumTFaces, mesh, iChannel); continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL"); + AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh& mesh) -{ +void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); // allocate enough storage in the array mesh.mVertexColors.resize(iNumVertices); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Vertex entry - if (TokenMatch(filePtr,"MESH_VERTCOL" ,12)) - { + if (TokenMatch(filePtr, "MESH_VERTCOL", 12)) { aiColor4D vTemp; vTemp.a = 1.0f; unsigned int iIndex; - ParseLV4MeshFloatTriple(&vTemp.r,iIndex); + ParseLV4MeshFloatTriple(&vTemp.r, iIndex); - if (iIndex >= iNumVertices) - { + if (iIndex >= iNumVertices) { LogWarning("Vertex color has an invalid index. It will be ignored"); - } - else mesh.mVertexColors[iIndex] = vTemp; + } else + mesh.mVertexColors[iIndex] = vTemp; continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) -{ +void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) { AI_ASE_PARSER_INIT(); - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; // Face entry - if (TokenMatch(filePtr,"MESH_CFACE" ,10)) - { + if (TokenMatch(filePtr, "MESH_CFACE", 10)) { unsigned int aiValues[3]; unsigned int iIndex = 0; - ParseLV4MeshLongTriple(aiValues,iIndex); - if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) - { + ParseLV4MeshLongTriple(aiValues, iIndex); + if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) { LogWarning("UV-Face has an invalid index. It will be ignored"); - } - else - { + } else { // copy color indices mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0]; mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1]; @@ -1881,17 +1611,16 @@ void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST"); + AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) -{ +void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) { AI_ASE_PARSER_INIT(); // Allocate enough storage for the normals - sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); + sMesh.mNormals.resize(sMesh.mFaces.size() * 3, aiVector3D(0.f, 0.f, 0.f)); unsigned int index, faceIdx = UINT_MAX; // FIXME: rewrite this and find out how to interpret the normals @@ -1899,34 +1628,34 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) // Smooth the vertex and face normals together. The result // will be edgy then, but otherwise everything would be soft ... - while (true) { - if ('*' == *filePtr) { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { + if (faceIdx != UINT_MAX && TokenMatch(filePtr, "MESH_VERTEXNORMAL", 17)) { aiVector3D vNormal; - ParseLV4MeshFloatTriple(&vNormal.x,index); - if (faceIdx >= sMesh.mFaces.size()) + ParseLV4MeshFloatTriple(&vNormal.x, index); + if (faceIdx >= sMesh.mFaces.size()) continue; // Make sure we assign it to the correct face - const ASE::Face& face = sMesh.mFaces[faceIdx]; + const ASE::Face &face = sMesh.mFaces[faceIdx]; if (index == face.mIndices[0]) index = 0; else if (index == face.mIndices[1]) index = 1; else if (index == face.mIndices[2]) index = 2; - else { + else { ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); continue; } // We'll renormalize later - sMesh.mNormals[faceIdx*3+index] += vNormal; + sMesh.mNormals[faceIdx * 3 + index] += vNormal; continue; } - if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) { + if (TokenMatch(filePtr, "MESH_FACENORMAL", 15)) { aiVector3D vNormal; - ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); + ParseLV4MeshFloatTriple(&vNormal.x, faceIdx); if (faceIdx >= sMesh.mFaces.size()) { ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_FACENORMAL section"); @@ -1934,53 +1663,47 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) } // We'll renormalize later - sMesh.mNormals[faceIdx*3] += vNormal; - sMesh.mNormals[faceIdx*3+1] += vNormal; - sMesh.mNormals[faceIdx*3+2] += vNormal; + sMesh.mNormals[faceIdx * 3] += vNormal; + sMesh.mNormals[faceIdx * 3 + 1] += vNormal; + sMesh.mNormals[faceIdx * 3 + 2] += vNormal; continue; } } - AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS"); + AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS"); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFace(ASE::Face& out) -{ +void Parser::ParseLV4MeshFace(ASE::Face &out) { // skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]"); SkipToNextToken(); return; } // parse the face index - out.iFace = strtoul10(filePtr,&filePtr); + out.iFace = strtoul10(filePtr, &filePtr); // next character should be ':' - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { // FIX: there are some ASE files which haven't got : here .... LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]"); SkipToNextToken(); return; } // FIX: There are some ASE files which haven't got ':' here - if(':' == *filePtr)++filePtr; + if (':' == *filePtr) ++filePtr; // Parse all mesh indices - for (unsigned int i = 0; i < 3;++i) - { + for (unsigned int i = 0; i < 3; ++i) { unsigned int iIndex = 0; - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL"); SkipToNextToken(); return; } - switch (*filePtr) - { + switch (*filePtr) { case 'A': case 'a': break; @@ -1994,38 +1717,34 @@ void Parser::ParseLV4MeshFace(ASE::Face& out) break; default: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " - "A,B or C expected [#3]"); + "A,B or C expected [#3]"); SkipToNextToken(); return; }; ++filePtr; // next character should be ':' - if(!SkipSpaces(&filePtr) || ':' != *filePtr) - { + if (!SkipSpaces(&filePtr) || ':' != *filePtr) { LogWarning("Unable to parse *MESH_FACE Element: " - "Unexpected EOL. \':\' expected [#2]"); + "Unexpected EOL. \':\' expected [#2]"); SkipToNextToken(); return; } ++filePtr; - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " - "Vertex index ecpected [#4]"); + "Vertex index ecpected [#4]"); SkipToNextToken(); return; } - out.mIndices[iIndex] = strtoul10(filePtr,&filePtr); + out.mIndices[iIndex] = strtoul10(filePtr, &filePtr); } // now we need to skip the AB, BC, CA blocks. - while (true) - { - if ('*' == *filePtr)break; - if (IsLineEnd(*filePtr)) - { + while (true) { + if ('*' == *filePtr) break; + if (IsLineEnd(*filePtr)) { //iLineNumber++; return; } @@ -2033,27 +1752,22 @@ void Parser::ParseLV4MeshFace(ASE::Face& out) } // parse the smoothing group of the face - if (TokenMatch(filePtr,"*MESH_SMOOTHING",15)) - { - if(!SkipSpaces(&filePtr)) - { + if (TokenMatch(filePtr, "*MESH_SMOOTHING", 15)) { + if (!SkipSpaces(&filePtr)) { LogWarning("Unable to parse *MESH_SMOOTHING Element: " - "Unexpected EOL. Smoothing group(s) expected [#5]"); + "Unexpected EOL. Smoothing group(s) expected [#5]"); SkipToNextToken(); return; } // Parse smoothing groups until we don't anymore see commas // FIX: There needn't always be a value, sad but true - while (true) - { - if (*filePtr < '9' && *filePtr >= '0') - { - out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr)); + while (true) { + if (*filePtr < '9' && *filePtr >= '0') { + out.iSmoothGroup |= (1 << strtoul10(filePtr, &filePtr)); } SkipSpaces(&filePtr); - if (',' != *filePtr) - { + if (',' != *filePtr) { break; } ++filePtr; @@ -2062,41 +1776,35 @@ void Parser::ParseLV4MeshFace(ASE::Face& out) } // *MESH_MTLID is optional, too - while (true) - { - if ('*' == *filePtr)break; - if (IsLineEnd(*filePtr)) - { + while (true) { + if ('*' == *filePtr) break; + if (IsLineEnd(*filePtr)) { return; } filePtr++; } - if (TokenMatch(filePtr,"*MESH_MTLID",11)) - { - if(!SkipSpaces(&filePtr)) - { + if (TokenMatch(filePtr, "*MESH_MTLID", 11)) { + if (!SkipSpaces(&filePtr)) { LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. " - "Material index expected [#6]"); + "Material index expected [#6]"); SkipToNextToken(); return; } - out.iMaterial = strtoul10(filePtr,&filePtr); + out.iMaterial = strtoul10(filePtr, &filePtr); } return; } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshLongTriple(unsigned int* apOut) -{ - ai_assert(NULL != apOut); +void Parser::ParseLV4MeshLongTriple(unsigned int *apOut) { + ai_assert(nullptr != apOut); - for (unsigned int i = 0; i < 3;++i) + for (unsigned int i = 0; i < 3; ++i) ParseLV4MeshLong(apOut[i]); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut) -{ - ai_assert(NULL != apOut); +void Parser::ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut) { + ai_assert(nullptr != apOut); // parse the index ParseLV4MeshLong(rIndexOut); @@ -2105,9 +1813,8 @@ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut ParseLV4MeshLongTriple(apOut); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut) -{ - ai_assert(NULL != apOut); +void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) { + ai_assert(nullptr != apOut); // parse the index ParseLV4MeshLong(rIndexOut); @@ -2116,19 +1823,16 @@ void Parser::ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut) ParseLV4MeshFloatTriple(apOut); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFloatTriple(ai_real* apOut) -{ - ai_assert(NULL != apOut); +void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) { + ai_assert(nullptr != apOut); - for (unsigned int i = 0; i < 3;++i) + for (unsigned int i = 0; i < 3; ++i) ParseLV4MeshFloat(apOut[i]); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFloat(ai_real& fOut) -{ +void Parser::ParseLV4MeshFloat(ai_real &fOut) { // skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { // LOG LogWarning("Unable to parse float: unexpected EOL [#1]"); fOut = 0.0; @@ -2136,14 +1840,12 @@ void Parser::ParseLV4MeshFloat(ai_real& fOut) return; } // parse the first float - filePtr = fast_atoreal_move(filePtr,fOut); + filePtr = fast_atoreal_move(filePtr, fOut); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshLong(unsigned int& iOut) -{ +void Parser::ParseLV4MeshLong(unsigned int &iOut) { // Skip spaces and tabs - if(!SkipSpaces(&filePtr)) - { + if (!SkipSpaces(&filePtr)) { // LOG LogWarning("Unable to parse long: unexpected EOL [#1]"); iOut = 0; @@ -2151,7 +1853,7 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut) return; } // parse the value - iOut = strtoul10(filePtr,&filePtr); + iOut = strtoul10(filePtr, &filePtr); } #endif // ASSIMP_BUILD_NO_3DS_IMPORTER diff --git a/code/ASE/ASEParser.h b/code/AssetLib/ASE/ASEParser.h similarity index 82% rename from code/ASE/ASEParser.h rename to code/AssetLib/ASE/ASEParser.h index aba37d38f..8df75c2dc 100644 --- a/code/ASE/ASEParser.h +++ b/code/AssetLib/ASE/ASEParser.h @@ -40,15 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - /** @file Defines the helper data structures for importing ASE files */ #ifndef AI_ASEFILEHELPER_H_INC #define AI_ASEFILEHELPER_H_INC // public ASSIMP headers -#include -#include #include +#include +#include #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER @@ -57,29 +56,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ASE is quite similar to 3ds. We can reuse some structures -#include "3DS/3DSLoader.h" +#include "AssetLib/3DS/3DSLoader.h" -namespace Assimp { -namespace ASE { +namespace Assimp { +namespace ASE { using namespace D3DS; // --------------------------------------------------------------------------- /** Helper structure representing an ASE material */ -struct Material : public D3DS::Material -{ +struct Material : public D3DS::Material { //! Default constructor has been deleted Material() = delete; //! Constructor with explicit name - explicit Material(const std::string &name) - : D3DS::Material(name) - , pcInstance(NULL) - , bNeed (false) { + explicit Material(const std::string &name) : + D3DS::Material(name), + pcInstance(nullptr), + bNeed(false) { // empty } - Material(const Material &other) = default; + Material(const Material &other) = default; Material &operator=(const Material &other) { if (this == &other) { @@ -93,19 +91,16 @@ struct Material : public D3DS::Material return *this; } - //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it Material(Material &&other) AI_NO_EXCEPT - : D3DS::Material(std::move(other)) - , avSubMaterials(std::move(other.avSubMaterials)) - , pcInstance(std::move(other.pcInstance)) - , bNeed(std::move(other.bNeed)) - { + : D3DS::Material(std::move(other)), + avSubMaterials(std::move(other.avSubMaterials)), + pcInstance(std::move(other.pcInstance)), + bNeed(std::move(other.bNeed)) { other.pcInstance = nullptr; } - - Material &operator=( Material &&other) AI_NO_EXCEPT { + Material &operator=(Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; } @@ -121,15 +116,13 @@ struct Material : public D3DS::Material return *this; } - ~Material() {} - //! Contains all sub materials of this material std::vector avSubMaterials; //! aiMaterial object - aiMaterial* pcInstance; + aiMaterial *pcInstance; //! Can we remove this material? bool bNeed; @@ -140,8 +133,8 @@ struct Material : public D3DS::Material struct Face : public FaceWithSmoothingGroup { //! Default constructor. Initializes everything with 0 Face() AI_NO_EXCEPT - : iMaterial(DEFAULT_MATINDEX) - , iFace(0) { + : iMaterial(DEFAULT_MATINDEX), + iFace(0) { // empty } @@ -172,8 +165,8 @@ struct Bone { Bone() = delete; //! Construction from an existing name - explicit Bone( const std::string& name) - : mName(name) { + explicit Bone(const std::string &name) : + mName(name) { // empty } @@ -186,33 +179,34 @@ struct Bone { struct BoneVertex { //! Bone and corresponding vertex weight. //! -1 for unrequired bones .... - std::vector > mBoneWeights; + std::vector> mBoneWeights; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file animation */ struct Animation { enum Type { - TRACK = 0x0, - BEZIER = 0x1, - TCB = 0x2 - } mRotationType, mScalingType, mPositionType; + TRACK = 0x0, + BEZIER = 0x1, + TCB = 0x2 + } mRotationType, + mScalingType, mPositionType; Animation() AI_NO_EXCEPT - : mRotationType (TRACK) - , mScalingType (TRACK) - , mPositionType (TRACK) { + : mRotationType(TRACK), + mScalingType(TRACK), + mPositionType(TRACK) { // empty } //! List of track rotation keyframes - std::vector< aiQuatKey > akeyRotations; + std::vector akeyRotations; //! List of track position keyframes - std::vector< aiVectorKey > akeyPositions; + std::vector akeyPositions; //! List of track scaling keyframes - std::vector< aiVectorKey > akeyScaling; + std::vector akeyScaling; }; // --------------------------------------------------------------------------- @@ -220,7 +214,7 @@ struct Animation { struct InheritanceInfo { //! Default constructor InheritanceInfo() AI_NO_EXCEPT { - for ( size_t i=0; i<3; ++i ) { + for (size_t i = 0; i < 3; ++i) { abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true; } } @@ -239,17 +233,15 @@ struct InheritanceInfo { /** Represents an ASE file node. Base class for mesh, light and cameras */ struct BaseNode { enum Type { - Light, - Camera, - Mesh, + Light, + Camera, + Mesh, Dummy } mType; //! Construction from an existing name - BaseNode(Type _mType, const std::string &name) - : mType (_mType) - , mName (name) - , mProcessed (false) { + BaseNode(Type _mType, const std::string &name) : + mType(_mType), mName(name), mProcessed(false) { // Set mTargetPosition to qnan const ai_real qnan = get_qnan(); mTargetPosition.x = qnan; @@ -289,14 +281,9 @@ struct Mesh : public MeshWithSmoothingGroups, public BaseNode { Mesh() = delete; //! Construction from an existing name - explicit Mesh(const std::string &name) - : BaseNode( BaseNode::Mesh, name ) - , mVertexColors() - , mBoneVertices() - , mBones() - , iMaterialIndex(Face::DEFAULT_MATINDEX) - , bSkip (false) { - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + explicit Mesh(const std::string &name) : + BaseNode(BaseNode::Mesh, name), mVertexColors(), mBoneVertices(), mBones(), iMaterialIndex(Face::DEFAULT_MATINDEX), bSkip(false) { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) { this->mNumUVComponents[c] = 2; } } @@ -325,10 +312,8 @@ struct Mesh : public MeshWithSmoothingGroups, public BaseNode { // --------------------------------------------------------------------------- /** Helper structure to represent an ASE light source */ -struct Light : public BaseNode -{ - enum LightType - { +struct Light : public BaseNode { + enum LightType { OMNI, TARGET, FREE, @@ -339,17 +324,13 @@ struct Light : public BaseNode Light() = delete; //! Construction from an existing name - explicit Light(const std::string &name) - : BaseNode (BaseNode::Light, name) - , mLightType (OMNI) - , mColor (1.f,1.f,1.f) - , mIntensity (1.f) // light is white by default - , mAngle (45.f) - , mFalloff (0.f) - { + explicit Light(const std::string &name) : + BaseNode(BaseNode::Light, name), mLightType(OMNI), mColor(1.f, 1.f, 1.f), mIntensity(1.f) // light is white by default + , + mAngle(45.f), + mFalloff(0.f) { } - LightType mLightType; aiColor3D mColor; ai_real mIntensity; @@ -359,10 +340,8 @@ struct Light : public BaseNode // --------------------------------------------------------------------------- /** Helper structure to represent an ASE camera */ -struct Camera : public BaseNode -{ - enum CameraType - { +struct Camera : public BaseNode { + enum CameraType { FREE, TARGET }; @@ -370,18 +349,16 @@ struct Camera : public BaseNode //! Default constructor has been deleted Camera() = delete; - //! Construction from an existing name - explicit Camera(const std::string &name) - : BaseNode (BaseNode::Camera, name) - , mFOV (0.75f) // in radians - , mNear (0.1f) - , mFar (1000.f) // could be zero - , mCameraType (FREE) - { + explicit Camera(const std::string &name) : + BaseNode(BaseNode::Camera, name), mFOV(0.75f) // in radians + , + mNear(0.1f), + mFar(1000.f) // could be zero + , + mCameraType(FREE) { } - ai_real mFOV, mNear, mFar; CameraType mCameraType; }; @@ -391,7 +368,7 @@ struct Camera : public BaseNode struct Dummy : public BaseNode { //! Constructor Dummy() AI_NO_EXCEPT - : BaseNode (BaseNode::Dummy, "DUMMY") { + : BaseNode(BaseNode::Dummy, "DUMMY") { // empty } }; @@ -414,7 +391,6 @@ private: } public: - // ------------------------------------------------------------------- //! Construct a parser from a given input file which is //! guaranteed to be terminated with zero. @@ -422,15 +398,13 @@ public: //! @param fileFormatDefault Assumed file format version. If the //! file format is specified in the file the new value replaces //! the default value. - Parser (const char* szFile, unsigned int fileFormatDefault); + Parser(const char *szFile, unsigned int fileFormatDefault); // ------------------------------------------------------------------- //! Parses the file into the parsers internal representation void Parse(); - private: - // ------------------------------------------------------------------- //! Parse the *SCENE block in a file void ParseLV1SceneBlock(); @@ -446,45 +420,45 @@ private: // ------------------------------------------------------------------- //! Parse a *OBJECT block in a file //! \param mesh Node to be filled - void ParseLV1ObjectBlock(BaseNode& mesh); + void ParseLV1ObjectBlock(BaseNode &mesh); // ------------------------------------------------------------------- //! Parse a *MATERIAL blocks in a material list //! \param mat Material structure to be filled - void ParseLV2MaterialBlock(Material& mat); + void ParseLV2MaterialBlock(Material &mat); // ------------------------------------------------------------------- //! Parse a *NODE_TM block in a file //! \param mesh Node (!) object to be filled - void ParseLV2NodeTransformBlock(BaseNode& mesh); + void ParseLV2NodeTransformBlock(BaseNode &mesh); // ------------------------------------------------------------------- //! Parse a *TM_ANIMATION block in a file //! \param mesh Mesh object to be filled - void ParseLV2AnimationBlock(BaseNode& mesh); - void ParseLV3PosAnimationBlock(ASE::Animation& anim); - void ParseLV3ScaleAnimationBlock(ASE::Animation& anim); - void ParseLV3RotAnimationBlock(ASE::Animation& anim); + void ParseLV2AnimationBlock(BaseNode &mesh); + void ParseLV3PosAnimationBlock(ASE::Animation &anim); + void ParseLV3ScaleAnimationBlock(ASE::Animation &anim); + void ParseLV3RotAnimationBlock(ASE::Animation &anim); // ------------------------------------------------------------------- //! Parse a *MESH block in a file //! \param mesh Mesh object to be filled - void ParseLV2MeshBlock(Mesh& mesh); + void ParseLV2MeshBlock(Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *LIGHT_SETTINGS block in a file //! \param light Light object to be filled - void ParseLV2LightSettingsBlock(Light& light); + void ParseLV2LightSettingsBlock(Light &light); // ------------------------------------------------------------------- //! Parse a *CAMERA_SETTINGS block in a file //! \param cam Camera object to be filled - void ParseLV2CameraSettingsBlock(Camera& cam); + void ParseLV2CameraSettingsBlock(Camera &cam); // ------------------------------------------------------------------- //! Parse the *MAP_XXXXXX blocks in a material //! \param map Texture structure to be filled - void ParseLV3MapBlock(Texture& map); + void ParseLV3MapBlock(Texture &map); // ------------------------------------------------------------------- //! Parse a *MESH_VERTEX_LIST block in a file @@ -493,7 +467,7 @@ private: //! A warning is sent to the logger if the validations fails. //! \param mesh Mesh object to be filled void ParseLV3MeshVertexListBlock( - unsigned int iNumVertices,Mesh& mesh); + unsigned int iNumVertices, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_FACE_LIST block in a file @@ -502,7 +476,7 @@ private: //! A warning is sent to the logger if the validations fails. //! \param mesh Mesh object to be filled void ParseLV3MeshFaceListBlock( - unsigned int iNumFaces,Mesh& mesh); + unsigned int iNumFaces, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_TVERT_LIST block in a file @@ -512,7 +486,7 @@ private: //! \param mesh Mesh object to be filled //! \param iChannel Output UVW channel void ParseLV3MeshTListBlock( - unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0); + unsigned int iNumVertices, Mesh &mesh, unsigned int iChannel = 0); // ------------------------------------------------------------------- //! Parse a *MESH_TFACELIST block in a file @@ -522,7 +496,7 @@ private: //! \param mesh Mesh object to be filled //! \param iChannel Output UVW channel void ParseLV3MeshTFaceListBlock( - unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0); + unsigned int iNumFaces, Mesh &mesh, unsigned int iChannel = 0); // ------------------------------------------------------------------- //! Parse an additional mapping channel @@ -530,7 +504,7 @@ private: //! \param iChannel Channel index to be filled //! \param mesh Mesh object to be filled void ParseLV3MappingChannel( - unsigned int iChannel, Mesh& mesh); + unsigned int iChannel, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_CVERTLIST block in a file @@ -539,7 +513,7 @@ private: //! A warning is sent to the logger if the validations fails. //! \param mesh Mesh object to be filled void ParseLV3MeshCListBlock( - unsigned int iNumVertices, Mesh& mesh); + unsigned int iNumVertices, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_CFACELIST block in a file @@ -548,70 +522,70 @@ private: //! A warning is sent to the logger if the validations fails. //! \param mesh Mesh object to be filled void ParseLV3MeshCFaceListBlock( - unsigned int iNumFaces, Mesh& mesh); + unsigned int iNumFaces, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_NORMALS block in a file //! \param mesh Mesh object to be filled - void ParseLV3MeshNormalListBlock(Mesh& mesh); + void ParseLV3MeshNormalListBlock(Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_WEIGHTSblock in a file //! \param mesh Mesh object to be filled - void ParseLV3MeshWeightsBlock(Mesh& mesh); + void ParseLV3MeshWeightsBlock(Mesh &mesh); // ------------------------------------------------------------------- //! Parse the bone list of a file //! \param mesh Mesh object to be filled //! \param iNumBones Number of bones in the mesh - void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh); + void ParseLV4MeshBones(unsigned int iNumBones, Mesh &mesh); // ------------------------------------------------------------------- //! Parse the bone vertices list of a file //! \param mesh Mesh object to be filled //! \param iNumVertices Number of vertices to be parsed - void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh); + void ParseLV4MeshBonesVertices(unsigned int iNumVertices, Mesh &mesh); // ------------------------------------------------------------------- //! Parse a *MESH_FACE block in a file //! \param out receive the face data - void ParseLV4MeshFace(ASE::Face& out); + void ParseLV4MeshFace(ASE::Face &out); // ------------------------------------------------------------------- //! Parse a *MESH_VERT block in a file //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) //! \param apOut Output buffer (3 floats) //! \param rIndexOut Output index - void ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut); + void ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut); // ------------------------------------------------------------------- //! Parse a *MESH_VERT block in a file //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) //! \param apOut Output buffer (3 floats) - void ParseLV4MeshFloatTriple(ai_real* apOut); + void ParseLV4MeshFloatTriple(ai_real *apOut); // ------------------------------------------------------------------- //! Parse a *MESH_TFACE block in a file //! (also works for MESH_CFACE) //! \param apOut Output buffer (3 ints) //! \param rIndexOut Output index - void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut); + void ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut); // ------------------------------------------------------------------- //! Parse a *MESH_TFACE block in a file //! (also works for MESH_CFACE) //! \param apOut Output buffer (3 ints) - void ParseLV4MeshLongTriple(unsigned int* apOut); + void ParseLV4MeshLongTriple(unsigned int *apOut); // ------------------------------------------------------------------- //! Parse a single float element //! \param fOut Output float - void ParseLV4MeshFloat(ai_real& fOut); + void ParseLV4MeshFloat(ai_real &fOut); // ------------------------------------------------------------------- //! Parse a single int element //! \param iOut Output integer - void ParseLV4MeshLong(unsigned int& iOut); + void ParseLV4MeshLong(unsigned int &iOut); // ------------------------------------------------------------------- //! Skip everything to the next: '*' or '\0' @@ -625,17 +599,17 @@ private: // ------------------------------------------------------------------- //! Output a warning to the logger //! \param szWarn Warn message - void LogWarning(const char* szWarn); + void LogWarning(const char *szWarn); // ------------------------------------------------------------------- //! Output a message to the logger //! \param szWarn Message - void LogInfo(const char* szWarn); + void LogInfo(const char *szWarn); // ------------------------------------------------------------------- //! Output an error to the logger //! \param szWarn Error message - AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX; + AI_WONT_RETURN void LogError(const char *szWarn) AI_WONT_RETURN_SUFFIX; // ------------------------------------------------------------------- //! Parse a string, enclosed in double quotation marks @@ -643,12 +617,11 @@ private: //! \param szName Name of the enclosing element -> used in error //! messages. //! \return false if an error occurred - bool ParseString(std::string& out,const char* szName); + bool ParseString(std::string &out, const char *szName); public: - //! Pointer to current data - const char* filePtr; + const char *filePtr; //! background color to be passed to the viewer //! QNAN if none was found @@ -695,9 +668,8 @@ public: unsigned int iFileFormat; }; - } // Namespace ASE -} // Namespace ASSIMP +} // namespace Assimp #endif // ASSIMP_BUILD_NO_3DS_IMPORTER diff --git a/code/Assbin/AssbinExporter.cpp b/code/AssetLib/Assbin/AssbinExporter.cpp similarity index 99% rename from code/Assbin/AssbinExporter.cpp rename to code/AssetLib/Assbin/AssbinExporter.cpp index 0b99afbda..e86a6526d 100644 --- a/code/Assbin/AssbinExporter.cpp +++ b/code/AssetLib/Assbin/AssbinExporter.cpp @@ -4,7 +4,6 @@ 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, diff --git a/code/Assbin/AssbinExporter.h b/code/AssetLib/Assbin/AssbinExporter.h similarity index 100% rename from code/Assbin/AssbinExporter.h rename to code/AssetLib/Assbin/AssbinExporter.h diff --git a/code/Assbin/AssbinFileWriter.cpp b/code/AssetLib/Assbin/AssbinFileWriter.cpp similarity index 95% rename from code/Assbin/AssbinFileWriter.cpp rename to code/AssetLib/Assbin/AssbinFileWriter.cpp index 7fceaa1ad..83a647a0b 100644 --- a/code/Assbin/AssbinFileWriter.cpp +++ b/code/AssetLib/Assbin/AssbinFileWriter.cpp @@ -4,7 +4,6 @@ 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, @@ -54,17 +53,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include +#include #else -# include "../contrib/zlib/zlib.h" +#include "../contrib/zlib/zlib.h" #endif #include -#ifdef _WIN32 -# pragma warning(push) -# pragma warning(disable : 4706) -#endif // _WIN32 +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4706) +#endif // _MSC_VER namespace Assimp { @@ -269,7 +268,7 @@ private: public: AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) : - buffer(NULL), + buffer(nullptr), magic(magic), container(container), cur_size(0), @@ -337,7 +336,7 @@ protected: void WriteBinaryNode(IOStream *container, const aiNode *node) { AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE); - unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); + unsigned int nb_metadata = (node->mMetaData != nullptr ? node->mMetaData->mNumProperties : 0); Write(&chunk, node->mName); Write(&chunk, node->mTransformation); @@ -362,32 +361,32 @@ protected: Write(&chunk, (uint16_t)type); switch (type) { - case AI_BOOL: - Write(&chunk, *((bool *)value)); - break; - case AI_INT32: - Write(&chunk, *((int32_t *)value)); - break; - case AI_UINT64: - Write(&chunk, *((uint64_t *)value)); - break; - case AI_FLOAT: - Write(&chunk, *((float *)value)); - break; - case AI_DOUBLE: - Write(&chunk, *((double *)value)); - break; - case AI_AISTRING: - Write(&chunk, *((aiString *)value)); - break; - case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D *)value)); - break; + case AI_BOOL: + Write(&chunk, *((bool *)value)); + break; + case AI_INT32: + Write(&chunk, *((int32_t *)value)); + break; + case AI_UINT64: + Write(&chunk, *((uint64_t *)value)); + break; + case AI_FLOAT: + Write(&chunk, *((float *)value)); + break; + case AI_DOUBLE: + Write(&chunk, *((double *)value)); + break; + case AI_AISTRING: + Write(&chunk, *((aiString *)value)); + break; + case AI_AIVECTOR3D: + Write(&chunk, *((aiVector3D *)value)); + break; #ifdef SWIG case FORCE_32BIT: #endif // SWIG - default: - break; + default: + break; } } } @@ -745,7 +744,7 @@ public: }; try { - time_t tt = time(NULL); + time_t tt = time(nullptr); #if _WIN32 tm *p = gmtime(&tt); #else @@ -791,7 +790,7 @@ public: // Up to here the data is uncompressed. For compressed files, the rest // is compressed using standard DEFLATE from zlib. if (compressed) { - AssbinChunkWriter uncompressedStream(NULL, 0); + AssbinChunkWriter uncompressedStream(nullptr, 0); WriteBinaryScene(&uncompressedStream, pScene); uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); @@ -826,8 +825,8 @@ void DumpSceneToAssbin( AssbinFileWriter fileWriter(shortened, compressed); fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); } -#ifdef _WIN32 -# pragma warning(pop) -#endif // _WIN32 +#if _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER } // end of namespace Assimp diff --git a/code/Assbin/AssbinFileWriter.h b/code/AssetLib/Assbin/AssbinFileWriter.h similarity index 92% rename from code/Assbin/AssbinFileWriter.h rename to code/AssetLib/Assbin/AssbinFileWriter.h index 25db6db2d..25cbc8106 100644 --- a/code/Assbin/AssbinFileWriter.h +++ b/code/AssetLib/Assbin/AssbinFileWriter.h @@ -4,7 +4,6 @@ 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, @@ -54,12 +53,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { void ASSIMP_API DumpSceneToAssbin( - const char* pFile, - const char* cmd, - IOSystem* pIOSystem, - const aiScene* pScene, - bool shortened, - bool compressed); + const char *pFile, + const char *cmd, + IOSystem *pIOSystem, + const aiScene *pScene, + bool shortened, + bool compressed); } diff --git a/code/Assbin/AssbinLoader.cpp b/code/AssetLib/Assbin/AssbinLoader.cpp similarity index 96% rename from code/Assbin/AssbinLoader.cpp rename to code/AssetLib/Assbin/AssbinLoader.cpp index 4293cae29..34021575c 100644 --- a/code/Assbin/AssbinLoader.cpp +++ b/code/AssetLib/Assbin/AssbinLoader.cpp @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER // internal headers -#include "Assbin/AssbinLoader.h" +#include "AssetLib/Assbin/AssbinLoader.h" #include "Common/assbin_chunks.h" #include #include @@ -253,32 +253,32 @@ void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *pa void *data = nullptr; switch (node->mMetaData->mValues[i].mType) { - case AI_BOOL: - data = new bool(Read(stream)); - break; - case AI_INT32: - data = new int32_t(Read(stream)); - break; - case AI_UINT64: - data = new uint64_t(Read(stream)); - break; - case AI_FLOAT: - data = new ai_real(Read(stream)); - break; - case AI_DOUBLE: - data = new double(Read(stream)); - break; - case AI_AISTRING: - data = new aiString(Read(stream)); - break; - case AI_AIVECTOR3D: - data = new aiVector3D(Read(stream)); - break; + case AI_BOOL: + data = new bool(Read(stream)); + break; + case AI_INT32: + data = new int32_t(Read(stream)); + break; + case AI_UINT64: + data = new uint64_t(Read(stream)); + break; + case AI_FLOAT: + data = new ai_real(Read(stream)); + break; + case AI_DOUBLE: + data = new double(Read(stream)); + break; + case AI_AISTRING: + data = new aiString(Read(stream)); + break; + case AI_AIVECTOR3D: + data = new aiVector3D(Read(stream)); + break; #ifndef SWIG - case FORCE_32BIT: + case FORCE_32BIT: #endif // SWIG - default: - break; + default: + break; } node->mMetaData->mValues[i].mData = data; @@ -604,7 +604,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) { // Read node graph //scene->mRootNode = new aiNode[1]; - ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL); + ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr); // Read all meshes if (scene->mNumMeshes) { diff --git a/code/Assbin/AssbinLoader.h b/code/AssetLib/Assbin/AssbinLoader.h similarity index 100% rename from code/Assbin/AssbinLoader.h rename to code/AssetLib/Assbin/AssbinLoader.h diff --git a/code/Assjson/cencode.c b/code/AssetLib/Assjson/cencode.c similarity index 94% rename from code/Assjson/cencode.c rename to code/AssetLib/Assjson/cencode.c index bd302100b..614a2671f 100644 --- a/code/Assjson/cencode.c +++ b/code/AssetLib/Assjson/cencode.c @@ -9,6 +9,11 @@ For details, see http://sourceforge.net/projects/libb64 const int CHARS_PER_LINE = 72; +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif // _MSC_VER + void base64_init_encodestate(base64_encodestate* state_in) { state_in->step = step_A; @@ -30,9 +35,9 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, char* codechar = code_out; char result; char fragment; - + result = state_in->result; - + switch (state_in->step) { while (1) @@ -71,7 +76,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); - + ++(state_in->stepcount); if (state_in->stepcount == CHARS_PER_LINE/4) { @@ -87,7 +92,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, int base64_encode_blockend(char* code_out, base64_encodestate* state_in) { char* codechar = code_out; - + switch (state_in->step) { case step_B: @@ -103,7 +108,10 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in) break; } *codechar++ = '\n'; - + return (int)(codechar - code_out); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER diff --git a/code/Assjson/cencode.h b/code/AssetLib/Assjson/cencode.h similarity index 95% rename from code/Assjson/cencode.h rename to code/AssetLib/Assjson/cencode.h index 6bf76724e..a7893c434 100644 --- a/code/Assjson/cencode.h +++ b/code/AssetLib/Assjson/cencode.h @@ -8,9 +8,9 @@ For details, see http://sourceforge.net/projects/libb64 #ifndef BASE64_CENCODE_H #define BASE64_CENCODE_H -#ifdef _WIN32 +#ifdef _MSC_VER #pragma warning(disable : 4127 ) -#endif // _WIN32 +#endif // _MSC_VER typedef enum { diff --git a/code/Assjson/json_exporter.cpp b/code/AssetLib/Assjson/json_exporter.cpp similarity index 81% rename from code/Assjson/json_exporter.cpp rename to code/AssetLib/Assjson/json_exporter.cpp index 4a8e4599e..b9099d392 100644 --- a/code/Assjson/json_exporter.cpp +++ b/code/AssetLib/Assjson/json_exporter.cpp @@ -9,30 +9,31 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER -#include +#include #include #include #include -#include +#include +#include -#include -#include #include +#include #include +#include #define CURRENT_FORMAT_VERSION 100 -// grab scoped_ptr from assimp to avoid a dependency on boost. +// grab scoped_ptr from assimp to avoid a dependency on boost. //#include #include "mesh_splitter.h" extern "C" { - #include "cencode.h" +#include "cencode.h" } namespace Assimp { -void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*); +void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *); // small utility class to simplify serializing the aiScene to Json class JSONWriter { @@ -42,10 +43,8 @@ public: Flag_WriteSpecialFloats = 0x2, }; - JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u) - : out(out) - , first() - , flags(flags) { + JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) : + out(out), first(), flags(flags) { // make sure that all formatting happens using the standard, C locale and not the user's current locale buff.imbue(std::locale("C")); } @@ -68,30 +67,30 @@ public: indent.erase(indent.end() - 1); } - void Key(const std::string& name) { + void Key(const std::string &name) { AddIndentation(); Delimit(); buff << '\"' + name + "\": "; } - template - void Element(const Literal& name) { + template + void Element(const Literal &name) { AddIndentation(); Delimit(); LiteralToString(buff, name) << '\n'; } - template - void SimpleValue(const Literal& s) { + template + void SimpleValue(const Literal &s) { LiteralToString(buff, s) << '\n'; } - void SimpleValue(const void* buffer, size_t len) { + void SimpleValue(const void *buffer, size_t len) { base64_encodestate s; base64_init_encodestate(&s); - char* const cur_out = new char[std::max(len * 2, static_cast(16u))]; + char *const cur_out = new char[std::max(len * 2, static_cast(16u))]; const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), cur_out, &s); cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0'; @@ -156,21 +155,20 @@ public: void Delimit() { if (!first) { buff << ','; - } - else { + } else { buff << ' '; first = false; } } private: - template - std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) { + template + std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) { stream << s; return stream; } - std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) { + std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) { std::string t; // escape backslashes and single quotes, both would render the JSON invalid if left as is @@ -189,10 +187,10 @@ private: return stream; } - std::stringstream& LiteralToString(std::stringstream& stream, float f) { + std::stringstream &LiteralToString(std::stringstream &stream, float f) { if (!std::numeric_limits::is_iec559) { // on a non IEEE-754 platform, we make no assumptions about the representation or existence - // of special floating-point numbers. + // of special floating-point numbers. stream << f; return stream; } @@ -228,7 +226,7 @@ private: } private: - Assimp::IOStream& out; + Assimp::IOStream &out; std::string indent, newline; std::stringstream buff; bool first; @@ -236,7 +234,7 @@ private: unsigned int flags; }; -void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) { out.StartArray(is_elem); out.Element(ai.x); out.Element(ai.y); @@ -244,7 +242,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) { out.EndArray(); } -void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) { out.StartArray(is_elem); out.Element(ai.w); out.Element(ai.x); @@ -253,7 +251,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) { out.EndArray(); } -void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) { out.StartArray(is_elem); out.Element(ai.r); out.Element(ai.g); @@ -261,7 +259,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) { out.EndArray(); } -void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) { out.StartArray(is_elem); for (unsigned int x = 0; x < 4; ++x) { for (unsigned int y = 0; y < 4; ++y) { @@ -271,7 +269,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) { out.EndArray(); } -void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -292,7 +290,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) { out.StartArray(is_elem); for (unsigned int i = 0; i < ai.mNumIndices; ++i) { out.Element(ai.mIndices[i]); @@ -300,7 +298,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) { out.EndArray(); } -void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -411,7 +409,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -441,13 +439,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("properties"); out.StartArray(); for (unsigned int i = 0; i < ai.mNumProperties; ++i) { - const aiMaterialProperty* const prop = ai.mProperties[i]; + const aiMaterialProperty *const prop = ai.mProperties[i]; out.StartObj(true); out.Key("key"); out.SimpleValue(prop->mKey); @@ -461,46 +459,41 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { out.Key("value"); switch (prop->mType) { - case aiPTI_Float: - if (prop->mDataLength / sizeof(float) > 1) { - out.StartArray(); - for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) { - out.Element(reinterpret_cast(prop->mData)[ii]); - } - out.EndArray(); + case aiPTI_Float: + if (prop->mDataLength / sizeof(float) > 1) { + out.StartArray(); + for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) { + out.Element(reinterpret_cast(prop->mData)[ii]); } - else { - out.SimpleValue(*reinterpret_cast(prop->mData)); - } - break; + out.EndArray(); + } else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; - case aiPTI_Integer: - if (prop->mDataLength / sizeof(int) > 1) { - out.StartArray(); - for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) { - out.Element(reinterpret_cast(prop->mData)[ii]); - } - out.EndArray(); - } else { - out.SimpleValue(*reinterpret_cast(prop->mData)); + case aiPTI_Integer: + if (prop->mDataLength / sizeof(int) > 1) { + out.StartArray(); + for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) { + out.Element(reinterpret_cast(prop->mData)[ii]); } - break; + out.EndArray(); + } else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; - case aiPTI_String: - { - aiString s; - aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); - out.SimpleValue(s); - } - break; - case aiPTI_Buffer: - { - // binary data is written as series of hex-encoded octets - out.SimpleValue(prop->mData, prop->mDataLength); - } - break; - default: - assert(false); + case aiPTI_String: { + aiString s; + aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); + out.SimpleValue(s); + } break; + case aiPTI_Buffer: { + // binary data is written as series of hex-encoded octets + out.SimpleValue(prop->mData, prop->mDataLength); + } break; + default: + assert(false); } out.EndObj(); @@ -510,7 +503,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("width"); @@ -525,13 +518,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { out.Key("data"); if (!ai.mHeight) { out.SimpleValue(ai.pcData, ai.mWidth); - } - else { + } else { out.StartArray(); for (unsigned int y = 0; y < ai.mHeight; ++y) { out.StartArray(true); for (unsigned int x = 0; x < ai.mWidth; ++x) { - const aiTexel& tx = ai.pcData[y*ai.mWidth + x]; + const aiTexel &tx = ai.pcData[y * ai.mWidth + x]; out.StartArray(true); out.Element(static_cast(tx.r)); out.Element(static_cast(tx.g)); @@ -547,7 +539,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { if (ai.mType != aiLightSource_POINT) { out.Key("direction"); Write(out, ai.mDirection, false); - } if (ai.mType != aiLightSource_DIRECTIONAL) { @@ -596,7 +587,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -612,7 +603,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { out.Key("positionkeys"); out.StartArray(); for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) { - const aiVectorKey& pos = ai.mPositionKeys[n]; + const aiVectorKey &pos = ai.mPositionKeys[n]; out.StartArray(true); out.Element(pos.mTime); Write(out, pos.mValue); @@ -625,7 +616,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { out.Key("rotationkeys"); out.StartArray(); for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) { - const aiQuatKey& rot = ai.mRotationKeys[n]; + const aiQuatKey &rot = ai.mRotationKeys[n]; out.StartArray(true); out.Element(rot.mTime); Write(out, rot.mValue); @@ -638,7 +629,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { out.Key("scalingkeys"); out.StartArray(); for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) { - const aiVectorKey& scl = ai.mScalingKeys[n]; + const aiVectorKey &scl = ai.mScalingKeys[n]; out.StartArray(true); out.Element(scl.mTime); Write(out, scl.mValue); @@ -649,7 +640,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -670,7 +661,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) { out.EndObj(); } -void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) { +void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) { out.StartObj(is_elem); out.Key("name"); @@ -697,7 +688,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) { out.EndObj(); } -void WriteFormatInfo(JSONWriter& out) { +void WriteFormatInfo(JSONWriter &out) { out.StartObj(); out.Key("format"); out.SimpleValue("\"assimp2json\""); @@ -706,7 +697,7 @@ void WriteFormatInfo(JSONWriter& out) { out.EndObj(); } -void Write(JSONWriter& out, const aiScene& ai) { +void Write(JSONWriter &out, const aiScene &ai) { out.StartObj(); out.Key("__metadata__"); @@ -774,15 +765,14 @@ void Write(JSONWriter& out, const aiScene& ai) { out.EndObj(); } - -void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) { +void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) { std::unique_ptr str(io->Open(file, "wt")); if (!str) { - //throw Assimp::DeadlyExportError("could not open output file"); + throw DeadlyExportError("could not open output file"); } // get a copy of the scene so we can modify it - aiScene* scenecopy_tmp; + aiScene *scenecopy_tmp; aiCopyScene(scene, &scenecopy_tmp); try { @@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats); Write(s, *scenecopy_tmp); - } - catch (...) { + } catch (...) { aiFreeScene(scenecopy_tmp); throw; } aiFreeScene(scenecopy_tmp); } -} +} // namespace Assimp #endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/Assjson/mesh_splitter.cpp b/code/AssetLib/Assjson/mesh_splitter.cpp similarity index 100% rename from code/Assjson/mesh_splitter.cpp rename to code/AssetLib/Assjson/mesh_splitter.cpp diff --git a/code/Assjson/mesh_splitter.h b/code/AssetLib/Assjson/mesh_splitter.h similarity index 100% rename from code/Assjson/mesh_splitter.h rename to code/AssetLib/Assjson/mesh_splitter.h diff --git a/code/Assxml/AssxmlExporter.cpp b/code/AssetLib/Assxml/AssxmlExporter.cpp similarity index 99% rename from code/Assxml/AssxmlExporter.cpp rename to code/AssetLib/Assxml/AssxmlExporter.cpp index 720fd5b40..ac2a433dd 100644 --- a/code/Assxml/AssxmlExporter.cpp +++ b/code/AssetLib/Assxml/AssxmlExporter.cpp @@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace Assimp { +namespace Assimp { void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { diff --git a/code/Assxml/AssxmlExporter.h b/code/AssetLib/Assxml/AssxmlExporter.h similarity index 100% rename from code/Assxml/AssxmlExporter.h rename to code/AssetLib/Assxml/AssxmlExporter.h diff --git a/code/AssetLib/Assxml/AssxmlFileWriter.cpp b/code/AssetLib/Assxml/AssxmlFileWriter.cpp new file mode 100644 index 000000000..05661d3fc --- /dev/null +++ b/code/AssetLib/Assxml/AssxmlFileWriter.cpp @@ -0,0 +1,659 @@ +/* +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 AssxmlFileWriter.cpp + * @brief Implementation of Assxml file writer. + */ + +#include "AssxmlFileWriter.h" + +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +#include +#else +#include +#endif + +#include +#include +#include + +using namespace Assimp; + +namespace Assimp { + +namespace AssxmlFileWriter { + +// ----------------------------------------------------------------------------------- +static int ioprintf(IOStream *io, const char *format, ...) { + using namespace std; + if (nullptr == io) { + return -1; + } + + static const int Size = 4096; + char sz[Size]; + ::memset(sz, '\0', Size); + va_list va; + va_start(va, format); + const unsigned int nSize = vsnprintf(sz, Size - 1, format, va); + ai_assert(nSize < Size); + va_end(va); + + io->Write(sz, sizeof(char), nSize); + + return nSize; +} + +// ----------------------------------------------------------------------------------- +// Convert a name to standard XML format +static void ConvertName(aiString &out, const aiString &in) { + out.length = 0; + for (unsigned int i = 0; i < in.length; ++i) { + switch (in.data[i]) { + case '<': + out.Append("<"); + break; + case '>': + out.Append(">"); + break; + case '&': + out.Append("&"); + break; + case '\"': + out.Append("""); + break; + case '\'': + out.Append("'"); + break; + default: + out.data[out.length++] = in.data[i]; + } + } + out.data[out.length] = 0; +} + +// ----------------------------------------------------------------------------------- +// Write a single node as text dump +static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) { + char prefix[512]; + for (unsigned int i = 0; i < depth; ++i) + prefix[i] = '\t'; + prefix[depth] = '\0'; + + const aiMatrix4x4 &m = node->mTransformation; + + aiString name; + ConvertName(name, node->mName); + ioprintf(io, "%s \n" + "%s\t \n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t \n", + prefix, name.data, prefix, + prefix, m.a1, m.a2, m.a3, m.a4, + prefix, m.b1, m.b2, m.b3, m.b4, + prefix, m.c1, m.c2, m.c3, m.c4, + prefix, m.d1, m.d2, m.d3, m.d4, prefix); + + if (node->mNumMeshes) { + ioprintf(io, "%s\t\n%s\t", + prefix, node->mNumMeshes, prefix); + + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + ioprintf(io, "%u ", node->mMeshes[i]); + } + ioprintf(io, "\n%s\t\n", prefix); + } + + if (node->mNumChildren) { + ioprintf(io, "%s\t\n", + prefix, node->mNumChildren); + + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + WriteNode(node->mChildren[i], io, depth + 2); + } + ioprintf(io, "%s\t\n", prefix); + } + ioprintf(io, "%s\n", prefix); +} + +// ----------------------------------------------------------------------------------- +// Some chuncks of text will need to be encoded for XML +// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 +static std::string encodeXML(const std::string &data) { + std::string buffer; + buffer.reserve(data.size()); + for (size_t pos = 0; pos != data.size(); ++pos) { + switch (data[pos]) { + case '&': buffer.append("&"); break; + case '\"': buffer.append("""); break; + case '\'': buffer.append("'"); break; + case '<': buffer.append("<"); break; + case '>': buffer.append(">"); break; + default: buffer.append(&data[pos], 1); break; + } + } + return buffer; +} + +// ----------------------------------------------------------------------------------- +// Write a text model dump +static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) { + time_t tt = ::time(nullptr); +#if _WIN32 + tm *p = gmtime(&tt); +#else + struct tm now; + tm *p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); + + std::string c = cmd; + std::string::size_type s; + + // https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632 + // -- not allowed in XML comments + while ((s = c.find("--")) != std::string::npos) { + c[s] = '?'; + } + + // write header + std::string header( + "\n" + "\n\n" + "" + " \n\n" + "\n"); + + const unsigned int majorVersion(aiGetVersionMajor()); + const unsigned int minorVersion(aiGetVersionMinor()); + const unsigned int rev(aiGetVersionRevision()); + const char *curtime(asctime(p)); + ioprintf(io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u); + + // write the node graph + WriteNode(scene->mRootNode, io, 0); + +#if 0 + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + aiCamera* cam = scene->mCameras[i]; + ConvertName(name,cam->mName); + + // camera header + ioprintf(io,"\t\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\n", + name.data, + cam->mUp.x,cam->mUp.y,cam->mUp.z, + cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, + cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, + cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + aiLight* l = scene->mLights[i]; + ConvertName(name,l->mName); + + // light header + ioprintf(io,"\t type=\"%s\"\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n", + name.data, + (l->mType == aiLightSource_DIRECTIONAL ? "directional" : + (l->mType == aiLightSource_POINT ? "point" : "spot" )), + l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, + l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, + l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); + + if (l->mType != aiLightSource_DIRECTIONAL) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n", + l->mPosition.x,l->mPosition.y,l->mPosition.z, + l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); + } + + if (l->mType != aiLightSource_POINT) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n", + l->mDirection.x,l->mDirection.y,l->mDirection.z); + } + + if (l->mType == aiLightSource_SPOT) { + ioprintf(io, + "\t\t %f \n" + "\t\t %f \n", + l->mAngleOuterCone,l->mAngleInnerCone); + } + ioprintf(io,"\t\n"); + } +#endif + aiString name; + + // write textures + if (scene->mNumTextures) { + ioprintf(io, "\n", scene->mNumTextures); + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { + aiTexture *tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); + + // mesh header + ioprintf(io, "\t \n", + (compressed ? -1 : tex->mWidth), (compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); + + if (compressed) { + ioprintf(io, "\t\t \n", tex->mWidth); + + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth; ++n) { + ioprintf(io, "\t\t\t%2x", reinterpret_cast(tex->pcData)[n]); + if (n && !(n % 50)) { + ioprintf(io, "\n"); + } + } + } + } else if (!shortened) { + ioprintf(io, "\t\t \n", tex->mWidth * tex->mHeight * 4); + + // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight; ++y) { + for (unsigned int x = 0; x < tex->mWidth; ++x) { + aiTexel *tx = tex->pcData + y * tex->mWidth + x; + unsigned int r = tx->r, g = tx->g, b = tx->b, a = tx->a; + ioprintf(io, "\t\t\t%2x %2x %2x %2x", r, g, b, a); + + // group by four for readability + if (0 == (x + y * tex->mWidth) % 4) { + ioprintf(io, "\n"); + } + } + } + } + ioprintf(io, "\t\t\n\t\n"); + } + ioprintf(io, "\n"); + } + + // write materials + if (scene->mNumMaterials) { + ioprintf(io, "\n", scene->mNumMaterials); + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + const aiMaterial *mat = scene->mMaterials[i]; + + ioprintf(io, "\t\n"); + ioprintf(io, "\t\t\n", mat->mNumProperties); + for (unsigned int n = 0; n < mat->mNumProperties; ++n) { + + const aiMaterialProperty *prop = mat->mProperties[n]; + const char *sz = ""; + if (prop->mType == aiPTI_Float) { + sz = "float"; + } else if (prop->mType == aiPTI_Integer) { + sz = "integer"; + } else if (prop->mType == aiPTI_String) { + sz = "string"; + } else if (prop->mType == aiPTI_Buffer) { + sz = "binary_buffer"; + } + + ioprintf(io, "\t\t\tmKey.data, sz, + ::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex); + + if (prop->mType == aiPTI_Float) { + ioprintf(io, " size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength / sizeof(float))); + + for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(float); ++pp) { + ioprintf(io, "%f ", *((float *)(prop->mData + pp * sizeof(float)))); + } + } else if (prop->mType == aiPTI_Integer) { + ioprintf(io, " size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength / sizeof(int))); + + for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(int); ++pp) { + ioprintf(io, "%i ", *((int *)(prop->mData + pp * sizeof(int)))); + } + } else if (prop->mType == aiPTI_Buffer) { + ioprintf(io, " size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength)); + + for (unsigned int pp = 0; pp < prop->mDataLength; ++pp) { + ioprintf(io, "%2x ", prop->mData[pp]); + if (pp && 0 == pp % 30) { + ioprintf(io, "\n\t\t\t\t"); + } + } + } else if (prop->mType == aiPTI_String) { + ioprintf(io, ">\n\t\t\t\t\"%s\"", encodeXML(prop->mData + 4).c_str() /* skip length */); + } + ioprintf(io, "\n\t\t\t\n"); + } + ioprintf(io, "\t\t\n"); + ioprintf(io, "\t\n"); + } + ioprintf(io, "\n"); + } + + // write animations + if (scene->mNumAnimations) { + ioprintf(io, "\n", scene->mNumAnimations); + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { + aiAnimation *anim = scene->mAnimations[i]; + + // anim header + ConvertName(name, anim->mName); + ioprintf(io, "\t\n", + name.data, anim->mDuration, anim->mTicksPerSecond); + + // write bone animation channels + if (anim->mNumChannels) { + ioprintf(io, "\t\t\n", anim->mNumChannels); + for (unsigned int n = 0; n < anim->mNumChannels; ++n) { + aiNodeAnim *nd = anim->mChannels[n]; + + // node anim header + ConvertName(name, nd->mNodeName); + ioprintf(io, "\t\t\t\n", name.data); + + if (!shortened) { + // write position keys + if (nd->mNumPositionKeys) { + ioprintf(io, "\t\t\t\t\n", nd->mNumPositionKeys); + for (unsigned int a = 0; a < nd->mNumPositionKeys; ++a) { + aiVectorKey *vc = nd->mPositionKeys + a; + ioprintf(io, "\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z); + } + ioprintf(io, "\t\t\t\t\n"); + } + + // write scaling keys + if (nd->mNumScalingKeys) { + ioprintf(io, "\t\t\t\t\n", nd->mNumScalingKeys); + for (unsigned int a = 0; a < nd->mNumScalingKeys; ++a) { + aiVectorKey *vc = nd->mScalingKeys + a; + ioprintf(io, "\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z); + } + ioprintf(io, "\t\t\t\t\n"); + } + + // write rotation keys + if (nd->mNumRotationKeys) { + ioprintf(io, "\t\t\t\t\n", nd->mNumRotationKeys); + for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) { + aiQuatKey *vc = nd->mRotationKeys + a; + ioprintf(io, "\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z, vc->mValue.w); + } + ioprintf(io, "\t\t\t\t\n"); + } + } + ioprintf(io, "\t\t\t\n"); + } + ioprintf(io, "\t\t\n"); + } + ioprintf(io, "\t\n"); + } + ioprintf(io, "\n"); + } + + // write meshes + if (scene->mNumMeshes) { + ioprintf(io, "\n", scene->mNumMeshes); + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + aiMesh *mesh = scene->mMeshes[i]; + // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1; + + // mesh header + ioprintf(io, "\t\n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mMaterialIndex); + + // bones + if (mesh->mNumBones) { + ioprintf(io, "\t\t\n", mesh->mNumBones); + + for (unsigned int n = 0; n < mesh->mNumBones; ++n) { + aiBone *bone = mesh->mBones[n]; + + ConvertName(name, bone->mName); + // bone header + ioprintf(io, "\t\t\t\n" + "\t\t\t\t \n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t \n", + name.data, + bone->mOffsetMatrix.a1, bone->mOffsetMatrix.a2, bone->mOffsetMatrix.a3, bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3, bone->mOffsetMatrix.d4); + + if (!shortened && bone->mNumWeights) { + ioprintf(io, "\t\t\t\t\n", bone->mNumWeights); + + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights; ++a) { + aiVertexWeight *wght = bone->mWeights + a; + + ioprintf(io, "\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", + wght->mVertexId, wght->mWeight); + } + ioprintf(io, "\t\t\t\t\n"); + } + ioprintf(io, "\t\t\t\n"); + } + ioprintf(io, "\t\t\n"); + } + + // faces + if (!shortened && mesh->mNumFaces) { + ioprintf(io, "\t\t\n", mesh->mNumFaces); + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace &f = mesh->mFaces[n]; + ioprintf(io, "\t\t\t\n" + "\t\t\t\t", + f.mNumIndices); + + for (unsigned int j = 0; j < f.mNumIndices; ++j) + ioprintf(io, "%u ", f.mIndices[j]); + + ioprintf(io, "\n\t\t\t\n"); + } + ioprintf(io, "\t\t\n"); + } + + // vertex positions + if (mesh->HasPositions()) { + ioprintf(io, "\t\t \n", mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } + } + ioprintf(io, "\t\t\n"); + } + + // vertex normals + if (mesh->HasNormals()) { + ioprintf(io, "\t\t \n", mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } + } + ioprintf(io, "\t\t\n"); + } + + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + ioprintf(io, "\t\t \n", mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z); + } + } + ioprintf(io, "\t\t\n"); + + ioprintf(io, "\t\t \n", mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n", + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + ioprintf(io, "\t\t\n"); + } + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + ioprintf(io, "\t\t \n", mesh->mNumVertices, + a, mesh->mNumUVComponents[a]); + + if (!shortened) { + if (mesh->mNumUVComponents[a] == 3) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } else { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y); + } + } + } + ioprintf(io, "\t\t\n"); + } + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + ioprintf(io, "\t\t \n", mesh->mNumVertices, a); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io, "\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + ioprintf(io, "\t\t\n"); + } + ioprintf(io, "\t\n"); + } + ioprintf(io, "\n"); + } + ioprintf(io, "\n"); +} + +} // end of namespace AssxmlFileWriter + +void DumpSceneToAssxml( + const char *pFile, const char *cmd, IOSystem *pIOSystem, + const aiScene *pScene, bool shortened) { + std::unique_ptr file(pIOSystem->Open(pFile, "wt")); + if (!file.get()) { + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + } + + AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened); +} + +} // end of namespace Assimp diff --git a/code/Assxml/AssxmlFileWriter.h b/code/AssetLib/Assxml/AssxmlFileWriter.h similarity index 100% rename from code/Assxml/AssxmlFileWriter.h rename to code/AssetLib/Assxml/AssxmlFileWriter.h diff --git a/code/AssetLib/B3D/B3DImporter.cpp b/code/AssetLib/B3D/B3DImporter.cpp new file mode 100644 index 000000000..25e484e02 --- /dev/null +++ b/code/AssetLib/B3D/B3DImporter.cpp @@ -0,0 +1,744 @@ +/* +--------------------------------------------------------------------------- +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 B3DImporter.cpp + * @brief Implementation of the b3d importer class + */ + +#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER + +// internal headers +#include "AssetLib/B3D/B3DImporter.h" +#include "PostProcessing/ConvertToLHProcess.h" +#include "PostProcessing/TextureTransform.h" + +#include +#include +#include +#include +#include +#include + +#include + +using namespace Assimp; +using namespace std; + +static const aiImporterDesc desc = { + "BlitzBasic 3D Importer", + "", + "", + "http://www.blitzbasic.com/", + aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "b3d" +}; + +#ifdef _MSC_VER +#pragma warning(disable : 4018) +#endif + +//#define DEBUG_B3D + +template +void DeleteAllBarePointers(std::vector &x) { + for (auto p : x) { + delete p; + } +} + +B3DImporter::~B3DImporter() { +} + +// ------------------------------------------------------------------------------------------------ +bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { + + size_t pos = pFile.find_last_of('.'); + if (pos == string::npos) { + return false; + } + + string ext = pFile.substr(pos + 1); + if (ext.size() != 3) { + return false; + } + + return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D'); +} + +// ------------------------------------------------------------------------------------------------ +// Loader meta information +const aiImporterDesc *B3DImporter::GetInfo() const { + return &desc; +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + std::unique_ptr file(pIOHandler->Open(pFile)); + + // Check whether we can read from the file + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open B3D file ", pFile, "."); + } + + // check whether the .b3d file is large enough to contain + // at least one chunk. + size_t fileSize = file->FileSize(); + if (fileSize < 8) { + throw DeadlyImportError("B3D File is too small."); + } + + _pos = 0; + _buf.resize(fileSize); + file->Read(&_buf[0], 1, fileSize); + _stack.clear(); + + ReadBB3D(pScene); +} + +// ------------------------------------------------------------------------------------------------ +AI_WONT_RETURN void B3DImporter::Oops() { + throw DeadlyImportError("B3D Importer - INTERNAL ERROR"); +} + +// ------------------------------------------------------------------------------------------------ +AI_WONT_RETURN void B3DImporter::Fail(string str) { +#ifdef DEBUG_B3D + ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str); +#endif + throw DeadlyImportError("B3D Importer - error in B3D file data: ", str); +} + +// ------------------------------------------------------------------------------------------------ +int B3DImporter::ReadByte() { + if (_pos > _buf.size()) { + Fail("EOF"); + } + + return _buf[_pos++]; +} + +// ------------------------------------------------------------------------------------------------ +int B3DImporter::ReadInt() { + if (_pos + 4 > _buf.size()) { + Fail("EOF"); + } + + int n; + memcpy(&n, &_buf[_pos], 4); + _pos += 4; + + return n; +} + +// ------------------------------------------------------------------------------------------------ +float B3DImporter::ReadFloat() { + if (_pos + 4 > _buf.size()) { + Fail("EOF"); + } + + float n; + memcpy(&n, &_buf[_pos], 4); + _pos += 4; + + return n; +} + +// ------------------------------------------------------------------------------------------------ +aiVector2D B3DImporter::ReadVec2() { + float x = ReadFloat(); + float y = ReadFloat(); + return aiVector2D(x, y); +} + +// ------------------------------------------------------------------------------------------------ +aiVector3D B3DImporter::ReadVec3() { + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + return aiVector3D(x, y, z); +} + +// ------------------------------------------------------------------------------------------------ +aiQuaternion B3DImporter::ReadQuat() { + // (aramis_acg) Fix to adapt the loader to changed quat orientation + float w = -ReadFloat(); + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + return aiQuaternion(w, x, y, z); +} + +// ------------------------------------------------------------------------------------------------ +string B3DImporter::ReadString() { + if (_pos > _buf.size()) { + Fail("EOF"); + } + string str; + while (_pos < _buf.size()) { + char c = (char)ReadByte(); + if (!c) { + return str; + } + str += c; + } + return string(); +} + +// ------------------------------------------------------------------------------------------------ +string B3DImporter::ReadChunk() { + string tag; + for (int i = 0; i < 4; ++i) { + tag += char(ReadByte()); + } +#ifdef DEBUG_B3D + ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag); +#endif + unsigned sz = (unsigned)ReadInt(); + _stack.push_back(_pos + sz); + return tag; +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ExitChunk() { + _pos = _stack.back(); + _stack.pop_back(); +} + +// ------------------------------------------------------------------------------------------------ +size_t B3DImporter::ChunkSize() { + return _stack.back() - _pos; +} +// ------------------------------------------------------------------------------------------------ + +template +T *B3DImporter::to_array(const vector &v) { + if (v.empty()) { + return 0; + } + T *p = new T[v.size()]; + for (size_t i = 0; i < v.size(); ++i) { + p[i] = v[i]; + } + return p; +} + +// ------------------------------------------------------------------------------------------------ +template +T **unique_to_array(vector> &v) { + if (v.empty()) { + return 0; + } + T **p = new T *[v.size()]; + for (size_t i = 0; i < v.size(); ++i) { + p[i] = v[i].release(); + } + return p; +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadTEXS() { + while (ChunkSize()) { + string name = ReadString(); + /*int flags=*/ReadInt(); + /*int blend=*/ReadInt(); + /*aiVector2D pos=*/ReadVec2(); + /*aiVector2D scale=*/ReadVec2(); + /*float rot=*/ReadFloat(); + + _textures.push_back(name); + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadBRUS() { + int n_texs = ReadInt(); + if (n_texs < 0 || n_texs > 8) { + Fail("Bad texture count"); + } + while (ChunkSize()) { + string name = ReadString(); + aiVector3D color = ReadVec3(); + float alpha = ReadFloat(); + float shiny = ReadFloat(); + /*int blend=**/ ReadInt(); + int fx = ReadInt(); + + std::unique_ptr mat(new aiMaterial); + + // Name + aiString ainame(name); + mat->AddProperty(&ainame, AI_MATKEY_NAME); + + // Diffuse color + mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE); + + // Opacity + mat->AddProperty(&alpha, 1, AI_MATKEY_OPACITY); + + // Specular color + aiColor3D speccolor(shiny, shiny, shiny); + mat->AddProperty(&speccolor, 1, AI_MATKEY_COLOR_SPECULAR); + + // Specular power + float specpow = shiny * 128; + mat->AddProperty(&specpow, 1, AI_MATKEY_SHININESS); + + // Double sided + if (fx & 0x10) { + int i = 1; + mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); + } + + //Textures + for (int i = 0; i < n_texs; ++i) { + int texid = ReadInt(); + if (texid < -1 || (texid >= 0 && texid >= static_cast(_textures.size()))) { + Fail("Bad texture id"); + } + if (i == 0 && texid >= 0) { + aiString texname(_textures[texid]); + mat->AddProperty(&texname, AI_MATKEY_TEXTURE_DIFFUSE(0)); + } + } + _materials.emplace_back(std::move(mat)); + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadVRTS() { + _vflags = ReadInt(); + _tcsets = ReadInt(); + _tcsize = ReadInt(); + if (_tcsets < 0 || _tcsets > 4 || _tcsize < 0 || _tcsize > 4) { + Fail("Bad texcoord data"); + } + + int sz = 12 + (_vflags & 1 ? 12 : 0) + (_vflags & 2 ? 16 : 0) + (_tcsets * _tcsize * 4); + size_t n_verts = ChunkSize() / sz; + + int v0 = static_cast(_vertices.size()); + _vertices.resize(v0 + n_verts); + + for (unsigned int i = 0; i < n_verts; ++i) { + Vertex &v = _vertices[v0 + i]; + + memset(v.bones, 0, sizeof(v.bones)); + memset(v.weights, 0, sizeof(v.weights)); + + v.vertex = ReadVec3(); + + if (_vflags & 1) { + v.normal = ReadVec3(); + } + + if (_vflags & 2) { + ReadQuat(); //skip v 4bytes... + } + + for (int j = 0; j < _tcsets; ++j) { + float t[4] = { 0, 0, 0, 0 }; + for (int k = 0; k < _tcsize; ++k) { + t[k] = ReadFloat(); + } + t[1] = 1 - t[1]; + if (!j) { + v.texcoords = aiVector3D(t[0], t[1], t[2]); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadTRIS(int v0) { + int matid = ReadInt(); + if (matid == -1) { + matid = 0; + } else if (matid < 0 || matid >= (int)_materials.size()) { +#ifdef DEBUG_B3D + ASSIMP_LOG_ERROR_F("material id=", matid); +#endif + Fail("Bad material id"); + } + + std::unique_ptr mesh(new aiMesh); + + mesh->mMaterialIndex = matid; + mesh->mNumFaces = 0; + mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + size_t n_tris = ChunkSize() / 12; + aiFace *face = mesh->mFaces = new aiFace[n_tris]; + + for (unsigned int i = 0; i < n_tris; ++i) { + int i0 = ReadInt() + v0; + int i1 = ReadInt() + v0; + int i2 = ReadInt() + v0; + if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { +#ifdef DEBUG_B3D + ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2); +#endif + Fail("Bad triangle index"); + continue; + } + face->mNumIndices = 3; + face->mIndices = new unsigned[3]; + face->mIndices[0] = i0; + face->mIndices[1] = i1; + face->mIndices[2] = i2; + ++mesh->mNumFaces; + ++face; + } + + _meshes.emplace_back(std::move(mesh)); +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadMESH() { + /*int matid=*/ReadInt(); + + int v0 = static_cast(_vertices.size()); + + while (ChunkSize()) { + string t = ReadChunk(); + if (t == "VRTS") { + ReadVRTS(); + } else if (t == "TRIS") { + ReadTRIS(v0); + } + ExitChunk(); + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadBONE(int id) { + while (ChunkSize()) { + int vertex = ReadInt(); + float weight = ReadFloat(); + if (vertex < 0 || vertex >= (int)_vertices.size()) { + Fail("Bad vertex index"); + } + + Vertex &v = _vertices[vertex]; + for (int i = 0; i < 4; ++i) { + if (!v.weights[i]) { + v.bones[i] = static_cast(id); + v.weights[i] = weight; + break; + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) { + vector trans, scale; + vector rot; + int flags = ReadInt(); + while (ChunkSize()) { + int frame = ReadInt(); + if (flags & 1) { + trans.push_back(aiVectorKey(frame, ReadVec3())); + } + if (flags & 2) { + scale.push_back(aiVectorKey(frame, ReadVec3())); + } + if (flags & 4) { + rot.push_back(aiQuatKey(frame, ReadQuat())); + } + } + + if (flags & 1) { + nodeAnim->mNumPositionKeys = static_cast(trans.size()); + nodeAnim->mPositionKeys = to_array(trans); + } + + if (flags & 2) { + nodeAnim->mNumScalingKeys = static_cast(scale.size()); + nodeAnim->mScalingKeys = to_array(scale); + } + + if (flags & 4) { + nodeAnim->mNumRotationKeys = static_cast(rot.size()); + nodeAnim->mRotationKeys = to_array(rot); + } +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadANIM() { + /*int flags=*/ReadInt(); + int frames = ReadInt(); + float fps = ReadFloat(); + + std::unique_ptr anim(new aiAnimation); + + anim->mDuration = frames; + anim->mTicksPerSecond = fps; + _animations.emplace_back(std::move(anim)); +} + +// ------------------------------------------------------------------------------------------------ +aiNode *B3DImporter::ReadNODE(aiNode *parent) { + + string name = ReadString(); + aiVector3D t = ReadVec3(); + aiVector3D s = ReadVec3(); + aiQuaternion r = ReadQuat(); + + aiMatrix4x4 trans, scale, rot; + + aiMatrix4x4::Translation(t, trans); + aiMatrix4x4::Scaling(s, scale); + rot = aiMatrix4x4(r.GetMatrix()); + + aiMatrix4x4 tform = trans * rot * scale; + + int nodeid = static_cast(_nodes.size()); + + aiNode *node = new aiNode(name); + _nodes.push_back(node); + + node->mParent = parent; + node->mTransformation = tform; + + std::unique_ptr nodeAnim; + vector meshes; + vector children; + + while (ChunkSize()) { + const string chunk = ReadChunk(); + if (chunk == "MESH") { + unsigned int n = static_cast(_meshes.size()); + ReadMESH(); + for (unsigned int i = n; i < static_cast(_meshes.size()); ++i) { + meshes.push_back(i); + } + } else if (chunk == "BONE") { + ReadBONE(nodeid); + } else if (chunk == "ANIM") { + ReadANIM(); + } else if (chunk == "KEYS") { + if (!nodeAnim) { + nodeAnim.reset(new aiNodeAnim); + nodeAnim->mNodeName = node->mName; + } + ReadKEYS(nodeAnim.get()); + } else if (chunk == "NODE") { + aiNode *child = ReadNODE(node); + children.push_back(child); + } + ExitChunk(); + } + + if (nodeAnim) { + _nodeAnims.emplace_back(std::move(nodeAnim)); + } + + node->mNumMeshes = static_cast(meshes.size()); + node->mMeshes = to_array(meshes); + + node->mNumChildren = static_cast(children.size()); + node->mChildren = to_array(children); + + return node; +} + +// ------------------------------------------------------------------------------------------------ +void B3DImporter::ReadBB3D(aiScene *scene) { + + _textures.clear(); + + _materials.clear(); + + _vertices.clear(); + + _meshes.clear(); + + DeleteAllBarePointers(_nodes); + _nodes.clear(); + + _nodeAnims.clear(); + + _animations.clear(); + + string t = ReadChunk(); + if (t == "BB3D") { + int version = ReadInt(); + + if (!DefaultLogger::isNullLogger()) { + char dmp[128]; + ai_snprintf(dmp, 128, "B3D file format version: %i", version); + ASSIMP_LOG_INFO(dmp); + } + + while (ChunkSize()) { + const string chunk = ReadChunk(); + if (chunk == "TEXS") { + ReadTEXS(); + } else if (chunk == "BRUS") { + ReadBRUS(); + } else if (chunk == "NODE") { + ReadNODE(0); + } + ExitChunk(); + } + } + ExitChunk(); + + if (!_nodes.size()) { + Fail("No nodes"); + } + + if (!_meshes.size()) { + Fail("No meshes"); + } + + // Fix nodes/meshes/bones + for (size_t i = 0; i < _nodes.size(); ++i) { + aiNode *node = _nodes[i]; + + for (size_t j = 0; j < node->mNumMeshes; ++j) { + aiMesh *mesh = _meshes[node->mMeshes[j]].get(); + + int n_tris = mesh->mNumFaces; + int n_verts = mesh->mNumVertices = n_tris * 3; + + aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = 0, *mc = 0; + if (_vflags & 1) { + mn = mesh->mNormals = new aiVector3D[n_verts]; + } + if (_tcsets) { + mc = mesh->mTextureCoords[0] = new aiVector3D[n_verts]; + } + + aiFace *face = mesh->mFaces; + + vector> vweights(_nodes.size()); + + for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) { + for (int faceIndex = 0; faceIndex < 3; ++faceIndex) { + Vertex &v = _vertices[face->mIndices[faceIndex]]; + + *mv++ = v.vertex; + if (mn) *mn++ = v.normal; + if (mc) *mc++ = v.texcoords; + + face->mIndices[faceIndex] = vertIdx + faceIndex; + + for (int k = 0; k < 4; ++k) { + if (!v.weights[k]) + break; + + int bone = v.bones[k]; + float weight = v.weights[k]; + + vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight)); + } + } + ++face; + } + + vector bones; + for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) { + vector &weights = vweights[weightIndx]; + if (!weights.size()) { + continue; + } + + aiBone *bone = new aiBone; + bones.push_back(bone); + + aiNode *bnode = _nodes[weightIndx]; + + bone->mName = bnode->mName; + bone->mNumWeights = static_cast(weights.size()); + bone->mWeights = to_array(weights); + + aiMatrix4x4 mat = bnode->mTransformation; + while (bnode->mParent) { + bnode = bnode->mParent; + mat = bnode->mTransformation * mat; + } + bone->mOffsetMatrix = mat.Inverse(); + } + mesh->mNumBones = static_cast(bones.size()); + mesh->mBones = to_array(bones); + } + } + + //nodes + scene->mRootNode = _nodes[0]; + _nodes.clear(); // node ownership now belongs to scene + + //material + if (!_materials.size()) { + _materials.emplace_back(std::unique_ptr(new aiMaterial)); + } + scene->mNumMaterials = static_cast(_materials.size()); + scene->mMaterials = unique_to_array(_materials); + + //meshes + scene->mNumMeshes = static_cast(_meshes.size()); + scene->mMeshes = unique_to_array(_meshes); + + //animations + if (_animations.size() == 1 && _nodeAnims.size()) { + + aiAnimation *anim = _animations.back().get(); + anim->mNumChannels = static_cast(_nodeAnims.size()); + anim->mChannels = unique_to_array(_nodeAnims); + + scene->mNumAnimations = static_cast(_animations.size()); + scene->mAnimations = unique_to_array(_animations); + } + + // convert to RH + MakeLeftHandedProcess makeleft; + makeleft.Execute(scene); + + FlipWindingOrderProcess flip; + flip.Execute(scene); +} + +#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER diff --git a/code/B3D/B3DImporter.h b/code/AssetLib/B3D/B3DImporter.h similarity index 100% rename from code/B3D/B3DImporter.h rename to code/AssetLib/B3D/B3DImporter.h diff --git a/code/AssetLib/BVH/BVHLoader.cpp b/code/AssetLib/BVH/BVHLoader.cpp new file mode 100644 index 000000000..3bea70c95 --- /dev/null +++ b/code/AssetLib/BVH/BVHLoader.cpp @@ -0,0 +1,537 @@ +/** Implementation of the BVH loader */ +/* +--------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER + +#include "BVHLoader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Assimp; +using namespace Assimp::Formatter; + +static const aiImporterDesc desc = { + "BVH Importer (MoCap)", + "", + "", + "", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "bvh" +}; + +// ------------------------------------------------------------------------------------------------ +// Aborts the file reading with an exception +template +AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) { + throw DeadlyImportError(mFileName, ":", mLine, " - ", args...); +} + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +BVHLoader::BVHLoader() : + mLine(), + mAnimTickDuration(), + mAnimNumFrames(), + noSkeletonMesh() {} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +BVHLoader::~BVHLoader() {} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the class can handle the format of the given file. +bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { + // check file extension + const std::string extension = GetExtension(pFile); + + if (extension == "bvh") + return true; + + if ((!extension.length() || cs) && pIOHandler) { + const char *tokens[] = { "HIERARCHY" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +void BVHLoader::SetupProperties(const Importer *pImp) { + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; +} + +// ------------------------------------------------------------------------------------------------ +// Loader meta information +const aiImporterDesc *BVHLoader::GetInfo() const { + return &desc; +} + +// ------------------------------------------------------------------------------------------------ +// Imports the given file into the given scene structure. +void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + mFileName = pFile; + + // read file into memory + std::unique_ptr file(pIOHandler->Open(pFile)); + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open file ", pFile, "."); + } + + size_t fileSize = file->FileSize(); + if (fileSize == 0) { + throw DeadlyImportError("File is too small."); + } + + mBuffer.resize(fileSize); + file->Read(&mBuffer.front(), 1, fileSize); + + // start reading + mReader = mBuffer.begin(); + mLine = 1; + ReadStructure(pScene); + + if (!noSkeletonMesh) { + // build a dummy mesh for the skeleton so that we see something at least + SkeletonMeshBuilder meshBuilder(pScene); + } + + // construct an animation from all the motion data we read + CreateAnimation(pScene); +} + +// ------------------------------------------------------------------------------------------------ +// Reads the file +void BVHLoader::ReadStructure(aiScene *pScene) { + // first comes hierarchy + std::string header = GetNextToken(); + if (header != "HIERARCHY") + ThrowException("Expected header string \"HIERARCHY\"."); + ReadHierarchy(pScene); + + // then comes the motion data + std::string motion = GetNextToken(); + if (motion != "MOTION") + ThrowException("Expected beginning of motion data \"MOTION\"."); + ReadMotion(pScene); +} + +// ------------------------------------------------------------------------------------------------ +// Reads the hierarchy +void BVHLoader::ReadHierarchy(aiScene *pScene) { + std::string root = GetNextToken(); + if (root != "ROOT") + ThrowException("Expected root node \"ROOT\"."); + + // Go read the hierarchy from here + pScene->mRootNode = ReadNode(); +} + +// ------------------------------------------------------------------------------------------------ +// Reads a node and recursively its childs and returns the created node; +aiNode *BVHLoader::ReadNode() { + // first token is name + std::string nodeName = GetNextToken(); + if (nodeName.empty() || nodeName == "{") + ThrowException("Expected node name, but found \"", nodeName, "\"."); + + // then an opening brace should follow + std::string openBrace = GetNextToken(); + if (openBrace != "{") + ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); + + // Create a node + aiNode *node = new aiNode(nodeName); + std::vector childNodes; + + // and create an bone entry for it + mNodes.push_back(Node(node)); + Node &internNode = mNodes.back(); + + // now read the node's contents + std::string siteToken; + while (1) { + std::string token = GetNextToken(); + + // node offset to parent node + if (token == "OFFSET") + ReadNodeOffset(node); + else if (token == "CHANNELS") + ReadNodeChannels(internNode); + else if (token == "JOINT") { + // child node follows + aiNode *child = ReadNode(); + child->mParent = node; + childNodes.push_back(child); + } else if (token == "End") { + // The real symbol is "End Site". Second part comes in a separate token + siteToken.clear(); + siteToken = GetNextToken(); + if (siteToken != "Site") + ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\"."); + + aiNode *child = ReadEndSite(nodeName); + child->mParent = node; + childNodes.push_back(child); + } else if (token == "}") { + // we're done with that part of the hierarchy + break; + } else { + // everything else is a parse error + ThrowException("Unknown keyword \"", token, "\"."); + } + } + + // add the child nodes if there are any + if (childNodes.size() > 0) { + node->mNumChildren = static_cast(childNodes.size()); + node->mChildren = new aiNode *[node->mNumChildren]; + std::copy(childNodes.begin(), childNodes.end(), node->mChildren); + } + + // and return the sub-hierarchy we built here + return node; +} + +// ------------------------------------------------------------------------------------------------ +// Reads an end node and returns the created node. +aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) { + // check opening brace + std::string openBrace = GetNextToken(); + if (openBrace != "{") + ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); + + // Create a node + aiNode *node = new aiNode("EndSite_" + pParentName); + + // now read the node's contents. Only possible entry is "OFFSET" + std::string token; + while (1) { + token.clear(); + token = GetNextToken(); + + // end node's offset + if (token == "OFFSET") { + ReadNodeOffset(node); + } else if (token == "}") { + // we're done with the end node + break; + } else { + // everything else is a parse error + ThrowException("Unknown keyword \"", token, "\"."); + } + } + + // and return the sub-hierarchy we built here + return node; +} +// ------------------------------------------------------------------------------------------------ +// Reads a node offset for the given node +void BVHLoader::ReadNodeOffset(aiNode *pNode) { + // Offset consists of three floats to read + aiVector3D offset; + offset.x = GetNextTokenAsFloat(); + offset.y = GetNextTokenAsFloat(); + offset.z = GetNextTokenAsFloat(); + + // build a transformation matrix from it + pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x, + 0.0f, 1.0f, 0.0f, offset.y, + 0.0f, 0.0f, 1.0f, offset.z, + 0.0f, 0.0f, 0.0f, 1.0f); +} + +// ------------------------------------------------------------------------------------------------ +// Reads the animation channels for the given node +void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) { + // number of channels. Use the float reader because we're lazy + float numChannelsFloat = GetNextTokenAsFloat(); + unsigned int numChannels = (unsigned int)numChannelsFloat; + + for (unsigned int a = 0; a < numChannels; a++) { + std::string channelToken = GetNextToken(); + + if (channelToken == "Xposition") + pNode.mChannels.push_back(Channel_PositionX); + else if (channelToken == "Yposition") + pNode.mChannels.push_back(Channel_PositionY); + else if (channelToken == "Zposition") + pNode.mChannels.push_back(Channel_PositionZ); + else if (channelToken == "Xrotation") + pNode.mChannels.push_back(Channel_RotationX); + else if (channelToken == "Yrotation") + pNode.mChannels.push_back(Channel_RotationY); + else if (channelToken == "Zrotation") + pNode.mChannels.push_back(Channel_RotationZ); + else + ThrowException("Invalid channel specifier \"", channelToken, "\"."); + } +} + +// ------------------------------------------------------------------------------------------------ +// Reads the motion data +void BVHLoader::ReadMotion(aiScene * /*pScene*/) { + // Read number of frames + std::string tokenFrames = GetNextToken(); + if (tokenFrames != "Frames:") + ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\"."); + + float numFramesFloat = GetNextTokenAsFloat(); + mAnimNumFrames = (unsigned int)numFramesFloat; + + // Read frame duration + std::string tokenDuration1 = GetNextToken(); + std::string tokenDuration2 = GetNextToken(); + if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") + ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\"."); + + mAnimTickDuration = GetNextTokenAsFloat(); + + // resize value vectors for each node + for (std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) + it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames); + + // now read all the data and store it in the corresponding node's value vector + for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) { + // on each line read the values for all nodes + for (std::vector::iterator it = mNodes.begin(); it != mNodes.end(); ++it) { + // get as many values as the node has channels + for (unsigned int c = 0; c < it->mChannels.size(); ++c) + it->mChannelValues.push_back(GetNextTokenAsFloat()); + } + + // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it + } +} + +// ------------------------------------------------------------------------------------------------ +// Retrieves the next token +std::string BVHLoader::GetNextToken() { + // skip any preceding whitespace + while (mReader != mBuffer.end()) { + if (!isspace(*mReader)) + break; + + // count lines + if (*mReader == '\n') + mLine++; + + ++mReader; + } + + // collect all chars till the next whitespace. BVH is easy in respect to that. + std::string token; + while (mReader != mBuffer.end()) { + if (isspace(*mReader)) + break; + + token.push_back(*mReader); + ++mReader; + + // little extra logic to make sure braces are counted correctly + if (token == "{" || token == "}") + break; + } + + // empty token means end of file, which is just fine + return token; +} + +// ------------------------------------------------------------------------------------------------ +// Reads the next token as a float +float BVHLoader::GetNextTokenAsFloat() { + std::string token = GetNextToken(); + if (token.empty()) + ThrowException("Unexpected end of file while trying to read a float"); + + // check if the float is valid by testing if the atof() function consumed every char of the token + const char *ctoken = token.c_str(); + float result = 0.0f; + ctoken = fast_atoreal_move(ctoken, result); + + if (ctoken != token.c_str() + token.length()) + ThrowException("Expected a floating point number, but found \"", token, "\"."); + + return result; +} + +// ------------------------------------------------------------------------------------------------ +// Constructs an animation for the motion data and stores it in the given scene +void BVHLoader::CreateAnimation(aiScene *pScene) { + // create the animation + pScene->mNumAnimations = 1; + pScene->mAnimations = new aiAnimation *[1]; + aiAnimation *anim = new aiAnimation; + pScene->mAnimations[0] = anim; + + // put down the basic parameters + anim->mName.Set("Motion"); + anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration); + anim->mDuration = double(mAnimNumFrames - 1); + + // now generate the tracks for all nodes + anim->mNumChannels = static_cast(mNodes.size()); + anim->mChannels = new aiNodeAnim *[anim->mNumChannels]; + + // FIX: set the array elements to nullptr to ensure proper deletion if an exception is thrown + for (unsigned int i = 0; i < anim->mNumChannels; ++i) + anim->mChannels[i] = nullptr; + + for (unsigned int a = 0; a < anim->mNumChannels; a++) { + const Node &node = mNodes[a]; + const std::string nodeName = std::string(node.mNode->mName.data); + aiNodeAnim *nodeAnim = new aiNodeAnim; + anim->mChannels[a] = nodeAnim; + nodeAnim->mNodeName.Set(nodeName); + std::map channelMap; + + //Build map of channels + for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) { + channelMap[node.mChannels[channel]] = channel; + } + + // translational part, if given + if (node.mChannels.size() == 6) { + nodeAnim->mNumPositionKeys = mAnimNumFrames; + nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; + aiVectorKey *poskey = nodeAnim->mPositionKeys; + for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) { + poskey->mTime = double(fr); + + // Now compute all translations + for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) { + //Find channel in node + std::map::iterator mapIter = channelMap.find(channel); + + if (mapIter == channelMap.end()) + throw DeadlyImportError("Missing position channel in node ", nodeName); + else { + int channelIdx = mapIter->second; + switch (channel) { + case Channel_PositionX: + poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + case Channel_PositionY: + poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + case Channel_PositionZ: + poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + + default: + break; + } + } + } + ++poskey; + } + } else { + // if no translation part is given, put a default sequence + aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); + nodeAnim->mNumPositionKeys = 1; + nodeAnim->mPositionKeys = new aiVectorKey[1]; + nodeAnim->mPositionKeys[0].mTime = 0.0; + nodeAnim->mPositionKeys[0].mValue = nodePos; + } + + // rotation part. Always present. First find value offsets + { + + // Then create the number of rotation keys + nodeAnim->mNumRotationKeys = mAnimNumFrames; + nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; + aiQuatKey *rotkey = nodeAnim->mRotationKeys; + for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) { + aiMatrix4x4 temp; + aiMatrix3x3 rotMatrix; + for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) { + switch (node.mChannels[channelIdx]) { + case Channel_RotationX: + { + const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; + aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); + } + break; + case Channel_RotationY: + { + const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; + aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); + } + break; + case Channel_RotationZ: + { + const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; + aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); + } + break; + default: + break; + } + } + rotkey->mTime = double(fr); + rotkey->mValue = aiQuaternion(rotMatrix); + ++rotkey; + } + } + + // scaling part. Always just a default track + { + nodeAnim->mNumScalingKeys = 1; + nodeAnim->mScalingKeys = new aiVectorKey[1]; + nodeAnim->mScalingKeys[0].mTime = 0.0; + nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f); + } + } +} + +#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER diff --git a/code/BVH/BVHLoader.h b/code/AssetLib/BVH/BVHLoader.h similarity index 82% rename from code/BVH/BVHLoader.h rename to code/AssetLib/BVH/BVHLoader.h index 93a3e5e83..3af3cbb31 100644 --- a/code/BVH/BVHLoader.h +++ b/code/AssetLib/BVH/BVHLoader.h @@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiNode; -namespace Assimp -{ +namespace Assimp { // -------------------------------------------------------------------------------- /** Loader class to read Motion Capturing data from a .bvh file. @@ -63,12 +62,10 @@ namespace Assimp * the hierarchy. It contains no actual mesh data, but we generate a dummy mesh * inside the loader just to be able to see something. */ -class BVHLoader : public BaseImporter -{ +class BVHLoader : public BaseImporter { /** Possible animation channels for which the motion data holds the values */ - enum ChannelType - { + enum ChannelType { Channel_PositionX, Channel_PositionY, Channel_PositionZ, @@ -78,61 +75,57 @@ class BVHLoader : public BaseImporter }; /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */ - struct Node - { - const aiNode* mNode; + struct Node { + const aiNode *mNode; std::vector mChannels; std::vector mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames - Node() - : mNode(nullptr) - { } + Node() : + mNode(nullptr) {} - explicit Node( const aiNode* pNode) : mNode( pNode) { } + explicit Node(const aiNode *pNode) : + mNode(pNode) {} }; public: - BVHLoader(); ~BVHLoader(); public: /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const; + bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const; - void SetupProperties(const Importer* pImp); - const aiImporterDesc* GetInfo () const; + void SetupProperties(const Importer *pImp); + const aiImporterDesc *GetInfo() const; protected: - - /** Imports the given file into the given scene structure. * See BaseImporter::InternReadFile() for details */ - void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); protected: /** Reads the file */ - void ReadStructure( aiScene* pScene); + void ReadStructure(aiScene *pScene); /** Reads the hierarchy */ - void ReadHierarchy( aiScene* pScene); + void ReadHierarchy(aiScene *pScene); /** Reads a node and recursively its childs and returns the created node. */ - aiNode* ReadNode(); + aiNode *ReadNode(); /** Reads an end node and returns the created node. */ - aiNode* ReadEndSite( const std::string& pParentName); + aiNode *ReadEndSite(const std::string &pParentName); /** Reads a node offset for the given node */ - void ReadNodeOffset( aiNode* pNode); + void ReadNodeOffset(aiNode *pNode); /** Reads the animation channels into the given node */ - void ReadNodeChannels( BVHLoader::Node& pNode); + void ReadNodeChannels(BVHLoader::Node &pNode); /** Reads the motion data */ - void ReadMotion( aiScene* pScene); + void ReadMotion(aiScene *pScene); /** Retrieves the next token */ std::string GetNextToken(); @@ -141,10 +134,11 @@ protected: float GetNextTokenAsFloat(); /** Aborts the file reading with an exception */ - AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX; + template + 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 */ - void CreateAnimation( aiScene* pScene); + void CreateAnimation(aiScene *pScene); protected: /** Filename, for a verbose error message */ diff --git a/code/Blender/BlenderBMesh.cpp b/code/AssetLib/Blender/BlenderBMesh.cpp similarity index 55% rename from code/Blender/BlenderBMesh.cpp rename to code/AssetLib/Blender/BlenderBMesh.cpp index 039302e12..d5412273e 100644 --- a/code/Blender/BlenderBMesh.cpp +++ b/code/AssetLib/Blender/BlenderBMesh.cpp @@ -42,165 +42,143 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Conversion of Blender's new BMesh stuff */ - #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER +#include "BlenderBMesh.h" #include "BlenderDNA.h" #include "BlenderScene.h" -#include "BlenderBMesh.h" #include "BlenderTessellator.h" -namespace Assimp -{ - template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix() - { - static auto prefix = "BLEND_BMESH: "; - return prefix; - } +namespace Assimp { +template <> +const char *LogFunctions::Prefix() { + static auto prefix = "BLEND_BMESH: "; + return prefix; } +} // namespace Assimp using namespace Assimp; using namespace Assimp::Blender; using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ -BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ): - BMesh( mesh ), - triMesh( NULL ) -{ +BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) : + BMesh(mesh), + triMesh(nullptr) { + ai_assert(nullptr != mesh); } // ------------------------------------------------------------------------------------------------ -BlenderBMeshConverter::~BlenderBMeshConverter( ) -{ - DestroyTriMesh( ); +BlenderBMeshConverter::~BlenderBMeshConverter() { + DestroyTriMesh(); } // ------------------------------------------------------------------------------------------------ -bool BlenderBMeshConverter::ContainsBMesh( ) const -{ +bool BlenderBMeshConverter::ContainsBMesh() const { // TODO - Should probably do some additional verification here return BMesh->totpoly && BMesh->totloop && BMesh->totvert; } // ------------------------------------------------------------------------------------------------ -const Mesh* BlenderBMeshConverter::TriangulateBMesh( ) -{ - AssertValidMesh( ); - AssertValidSizes( ); - PrepareTriMesh( ); +const Mesh *BlenderBMeshConverter::TriangulateBMesh() { + AssertValidMesh(); + AssertValidSizes(); + PrepareTriMesh(); - for ( int i = 0; i < BMesh->totpoly; ++i ) - { - const MPoly& poly = BMesh->mpoly[ i ]; - ConvertPolyToFaces( poly ); + for (int i = 0; i < BMesh->totpoly; ++i) { + const MPoly &poly = BMesh->mpoly[i]; + ConvertPolyToFaces(poly); } return triMesh; } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::AssertValidMesh( ) -{ - if ( !ContainsBMesh( ) ) - { - ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" ); +void BlenderBMeshConverter::AssertValidMesh() { + if (!ContainsBMesh()) { + ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first"); } } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::AssertValidSizes( ) -{ - if ( BMesh->totpoly != static_cast( BMesh->mpoly.size( ) ) ) - { - ThrowException( "BMesh poly array has incorrect size" ); +void BlenderBMeshConverter::AssertValidSizes() { + if (BMesh->totpoly != static_cast(BMesh->mpoly.size())) { + ThrowException("BMesh poly array has incorrect size"); } - if ( BMesh->totloop != static_cast( BMesh->mloop.size( ) ) ) - { - ThrowException( "BMesh loop array has incorrect size" ); + if (BMesh->totloop != static_cast(BMesh->mloop.size())) { + ThrowException("BMesh loop array has incorrect size"); } } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::PrepareTriMesh( ) -{ - if ( triMesh ) - { - DestroyTriMesh( ); +void BlenderBMeshConverter::PrepareTriMesh() { + if (triMesh) { + DestroyTriMesh(); } - triMesh = new Mesh( *BMesh ); + triMesh = new Mesh(*BMesh); triMesh->totface = 0; - triMesh->mface.clear( ); + triMesh->mface.clear(); } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::DestroyTriMesh( ) -{ +void BlenderBMeshConverter::DestroyTriMesh() { delete triMesh; - triMesh = NULL; + triMesh = nullptr; } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly ) -{ - const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ]; +void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) { + const MLoop *polyLoop = &BMesh->mloop[poly.loopstart]; - if ( poly.totloop == 3 || poly.totloop == 4 ) - { - AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 ); + if (poly.totloop == 3 || poly.totloop == 4) { + AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0); // UVs are optional, so only convert when present. - if ( BMesh->mloopuv.size() ) - { - if ( (poly.loopstart + poly.totloop ) > static_cast( BMesh->mloopuv.size() ) ) - { - ThrowException( "BMesh uv loop array has incorrect size" ); + if (BMesh->mloopuv.size()) { + if ((poly.loopstart + poly.totloop) > static_cast(BMesh->mloopuv.size())) { + ThrowException("BMesh uv loop array has incorrect size"); } - const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ]; - AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 ); + const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart]; + AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0); } - } - else if ( poly.totloop > 4 ) - { + } else if (poly.totloop > 4) { #if ASSIMP_BLEND_WITH_GLU_TESSELLATE - BlenderTessellatorGL tessGL( *this ); - tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); + BlenderTessellatorGL tessGL(*this); + tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert); #elif ASSIMP_BLEND_WITH_POLY_2_TRI - BlenderTessellatorP2T tessP2T( *this ); - tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); + BlenderTessellatorP2T tessP2T(*this); + tessP2T.Tessellate(polyLoop, poly.totloop, triMesh->mvert); #endif } } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 ) -{ +void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) { MFace face; face.v1 = v1; face.v2 = v2; face.v3 = v3; face.v4 = v4; + face.flag = 0; // TODO - Work out how materials work face.mat_nr = 0; - triMesh->mface.push_back( face ); - triMesh->totface = static_cast(triMesh->mface.size( )); + triMesh->mface.push_back(face); + triMesh->totface = static_cast(triMesh->mface.size()); } // ------------------------------------------------------------------------------------------------ -void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 ) -{ +void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) { MTFace mtface; - memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 ); - memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 ); - memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 ); + memcpy(&mtface.uv[0], uv1, sizeof(float) * 2); + memcpy(&mtface.uv[1], uv2, sizeof(float) * 2); + memcpy(&mtface.uv[2], uv3, sizeof(float) * 2); - if ( uv4 ) - { - memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 ); + if (uv4) { + memcpy(&mtface.uv[3], uv4, sizeof(float) * 2); } - triMesh->mtface.push_back( mtface ); + triMesh->mtface.push_back(mtface); } #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER diff --git a/code/Blender/BlenderBMesh.h b/code/AssetLib/Blender/BlenderBMesh.h similarity index 100% rename from code/Blender/BlenderBMesh.h rename to code/AssetLib/Blender/BlenderBMesh.h diff --git a/code/AssetLib/Blender/BlenderCustomData.cpp b/code/AssetLib/Blender/BlenderCustomData.cpp new file mode 100644 index 000000000..c74a6bb75 --- /dev/null +++ b/code/AssetLib/Blender/BlenderCustomData.cpp @@ -0,0 +1,181 @@ +#include "BlenderCustomData.h" +#include "BlenderDNA.h" +#include +#include + +namespace Assimp { +namespace Blender { +/** + * @brief read/convert of Structure array to memory + */ +template +bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) { + for (size_t i = 0; i < cnt; ++i) { + T read; + s.Convert(read, db); + *p = read; + p++; + } + return true; +} + +/** + * @brief pointer to function read memory for n CustomData types + */ +typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db); +typedef ElemBase *(*PCreate)(const size_t cnt); +typedef void (*PDestroy)(ElemBase *); + +#define IMPL_STRUCT_READ(ty) \ + bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \ + ty *ptr = dynamic_cast(v); \ + if (nullptr == ptr) { \ + return false; \ + } \ + return read(db.dna[#ty], ptr, cnt, db); \ + } + +#define IMPL_STRUCT_CREATE(ty) \ + ElemBase *create##ty(const size_t cnt) { \ + return new ty[cnt]; \ + } + +#define IMPL_STRUCT_DESTROY(ty) \ + void destroy##ty(ElemBase *pE) { \ + ty *p = dynamic_cast(pE); \ + delete[] p; \ + } + +/** + * @brief helper macro to define Structure functions + */ +#define IMPL_STRUCT(ty) \ + IMPL_STRUCT_READ(ty) \ + IMPL_STRUCT_CREATE(ty) \ + IMPL_STRUCT_DESTROY(ty) + +// supported structures for CustomData +IMPL_STRUCT(MVert) +IMPL_STRUCT(MEdge) +IMPL_STRUCT(MFace) +IMPL_STRUCT(MTFace) +IMPL_STRUCT(MTexPoly) +IMPL_STRUCT(MLoopUV) +IMPL_STRUCT(MLoopCol) +IMPL_STRUCT(MPoly) +IMPL_STRUCT(MLoop) + +/** + * @brief describes the size of data and the read function to be used for single CustomerData.type + */ +struct CustomDataTypeDescription { + PRead Read; ///< function to read one CustomData type element + PCreate Create; ///< function to allocate n type elements + PDestroy Destroy; + + CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) : + Read(read), Create(create), Destroy(destroy) {} +}; + +/** + * @brief helper macro to define Structure type specific CustomDataTypeDescription + * @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function + */ +#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \ + CustomDataTypeDescription { &read##ty, &create##ty, &destroy##ty } + +/** + * @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type + */ +#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \ + CustomDataTypeDescription { nullptr, nullptr, nullptr } + +/** + * @brief descriptors for data pointed to from CustomDataLayer.data + * @note some of the CustomData uses already well defined Structures + * other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures + * use a special readfunction for that cases + */ +std::array customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION } }; + +bool isValidCustomDataType(const int cdtype) { + return cdtype >= 0 && cdtype < CD_NUMTYPES; +} + +bool readCustomData(std::shared_ptr &out, const int cdtype, const size_t cnt, const FileDatabase &db) { + if (!isValidCustomDataType(cdtype)) { + throw Error("CustomData.type ", cdtype, " out of index"); + } + + const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; + if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) { + // allocate cnt elements and parse them from file + out.reset(cdtd.Create(cnt), cdtd.Destroy); + return cdtd.Read(out.get(), cnt, db); + } + return false; +} + +std::shared_ptr getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) { + for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) { + if (it->get()->type == cdtype && name == it->get()->name) { + return *it; + } + } + return nullptr; +} + +const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) { + const std::shared_ptr pLayer = getCustomDataLayer(customdata, cdtype, name); + if (pLayer && pLayer->data) { + return pLayer->data.get(); + } + return nullptr; +} +} // namespace Blender +} // namespace Assimp diff --git a/code/Blender/BlenderCustomData.h b/code/AssetLib/Blender/BlenderCustomData.h similarity index 100% rename from code/Blender/BlenderCustomData.h rename to code/AssetLib/Blender/BlenderCustomData.h diff --git a/code/Blender/BlenderDNA.cpp b/code/AssetLib/Blender/BlenderDNA.cpp similarity index 70% rename from code/Blender/BlenderDNA.cpp rename to code/AssetLib/Blender/BlenderDNA.cpp index 53fb84824..cd9bce66f 100644 --- a/code/Blender/BlenderDNA.cpp +++ b/code/AssetLib/Blender/BlenderDNA.cpp @@ -45,25 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * serialized set of data structures. */ - #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER #include "BlenderDNA.h" #include -#include #include +#include using namespace Assimp; using namespace Assimp::Blender; using namespace Assimp::Formatter; -static bool match4(StreamReaderAny& stream, const char* string) { - ai_assert( nullptr != string ); +static bool match4(StreamReaderAny &stream, const char *string) { + ai_assert(nullptr != string); char tmp[4]; - tmp[ 0 ] = ( stream ).GetI1(); - tmp[ 1 ] = ( stream ).GetI1(); - tmp[ 2 ] = ( stream ).GetI1(); - tmp[ 3 ] = ( stream ).GetI1(); - return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); + tmp[0] = (stream).GetI1(); + tmp[1] = (stream).GetI1(); + tmp[2] = (stream).GetI1(); + tmp[3] = (stream).GetI1(); + return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]); } struct Type { @@ -72,76 +71,74 @@ struct Type { }; // ------------------------------------------------------------------------------------------------ -void DNAParser::Parse () -{ - StreamReaderAny& stream = *db.reader.get(); - DNA& dna = db.dna; +void DNAParser::Parse() { + StreamReaderAny &stream = *db.reader.get(); + DNA &dna = db.dna; - if(!match4(stream,"SDNA")) { + if (!match4(stream, "SDNA")) { throw DeadlyImportError("BlenderDNA: Expected SDNA chunk"); } // name dictionary - if(!match4(stream,"NAME")) { + if (!match4(stream, "NAME")) { throw DeadlyImportError("BlenderDNA: Expected NAME field"); } - std::vector names (stream.GetI4()); - for(std::string& s : names) { + std::vector names(stream.GetI4()); + for (std::string &s : names) { while (char c = stream.GetI1()) { s += c; } } // type dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"TYPE")) { + for (; stream.GetCurrentPos() & 0x3; stream.GetI1()) + ; + if (!match4(stream, "TYPE")) { throw DeadlyImportError("BlenderDNA: Expected TYPE field"); } - std::vector types (stream.GetI4()); - for(Type& s : types) { + std::vector types(stream.GetI4()); + for (Type &s : types) { while (char c = stream.GetI1()) { s.name += c; } } // type length dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"TLEN")) { + for (; stream.GetCurrentPos() & 0x3; stream.GetI1()) + ; + if (!match4(stream, "TLEN")) { throw DeadlyImportError("BlenderDNA: Expected TLEN field"); } - for(Type& s : types) { + for (Type &s : types) { s.size = stream.GetI2(); } // structures dictionary - for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); - if(!match4(stream,"STRC")) { + for (; stream.GetCurrentPos() & 0x3; stream.GetI1()) + ; + if (!match4(stream, "STRC")) { throw DeadlyImportError("BlenderDNA: Expected STRC field"); } size_t end = stream.GetI4(), fields = 0; dna.structures.reserve(end); - for(size_t i = 0; i != end; ++i) { + for (size_t i = 0; i != end; ++i) { uint16_t n = stream.GetI2(); if (n >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure name" ,n, - " (there are only ", types.size(), " entries)" - )); + throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)"); } // maintain separate indexes dna.indices[types[n].name] = dna.structures.size(); dna.structures.push_back(Structure()); - Structure& s = dna.structures.back(); - s.name = types[n].name; - //s.index = dna.structures.size()-1; + Structure &s = dna.structures.back(); + s.name = types[n].name; n = stream.GetI2(); s.fields.reserve(n); @@ -151,13 +148,10 @@ void DNAParser::Parse () uint16_t j = stream.GetI2(); if (j >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure field ", j, - " (there are only ", types.size(), " entries)" - )); + throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)"); } s.fields.push_back(Field()); - Field& f = s.fields.back(); + Field &f = s.fields.back(); f.offset = offset; f.type = types[j].name; @@ -165,10 +159,7 @@ void DNAParser::Parse () j = stream.GetI2(); if (j >= names.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid name index in structure field ", j, - " (there are only ", names.size(), " entries)" - )); + throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)"); } f.name = names[j]; @@ -190,27 +181,24 @@ void DNAParser::Parse () if (*f.name.rbegin() == ']') { const std::string::size_type rb = f.name.find('['); if (rb == std::string::npos) { - throw DeadlyImportError((format(), - "BlenderDNA: Encountered invalid array declaration ", - f.name - )); + throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name); } f.flags |= FieldFlag_Array; - DNA::ExtractArraySize(f.name,f.array_sizes); - f.name = f.name.substr(0,rb); + DNA::ExtractArraySize(f.name, f.array_sizes); + f.name = f.name.substr(0, rb); f.size *= f.array_sizes[0] * f.array_sizes[1]; } // maintain separate indexes - s.indices[f.name] = s.fields.size()-1; + s.indices[f.name] = s.fields.size() - 1; offset += f.size; } s.size = offset; } - ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields"); + ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields"); #ifdef ASSIMP_BUILD_BLENDER_DEBUG dna.DumpToFile(); @@ -220,13 +208,11 @@ void DNAParser::Parse () dna.RegisterConverters(); } - #ifdef ASSIMP_BUILD_BLENDER_DEBUG #include // ------------------------------------------------------------------------------------------------ -void DNA :: DumpToFile() -{ +void DNA ::DumpToFile() { // we don't bother using the VFS here for this is only for debugging. // (and all your bases are belong to us). @@ -235,12 +221,14 @@ void DNA :: DumpToFile() ASSIMP_LOG_ERROR("Could not dump dna to dna.txt"); return; } - f << "Field format: type name offset size" << "\n"; - f << "Structure format: name size" << "\n"; + f << "Field format: type name offset size" + << "\n"; + f << "Structure format: name size" + << "\n"; - for(const Structure& s : structures) { + for (const Structure &s : structures) { f << s.name << " " << s.size << "\n\n"; - for(const Field& ff : s.fields) { + for (const Field &ff : s.fields) { f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n"; } f << "\n"; @@ -252,11 +240,9 @@ void DNA :: DumpToFile() #endif // ------------------------------------------------------------------------------------------------ -/*static*/ void DNA :: ExtractArraySize( - const std::string& out, - size_t array_sizes[2] -) -{ +/*static*/ void DNA ::ExtractArraySize( + const std::string &out, + size_t array_sizes[2]) { array_sizes[0] = array_sizes[1] = 1; std::string::size_type pos = out.find('['); if (pos++ == std::string::npos) { @@ -264,7 +250,7 @@ void DNA :: DumpToFile() } array_sizes[0] = strtoul10(&out[pos]); - pos = out.find('[',pos); + pos = out.find('[', pos); if (pos++ == std::string::npos) { return; } @@ -272,36 +258,32 @@ void DNA :: DumpToFile() } // ------------------------------------------------------------------------------------------------ -std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure( - const Structure& structure, - const FileDatabase& db -) const -{ - std::map::const_iterator it = converters.find(structure.name); +std::shared_ptr DNA ::ConvertBlobToStructure( + const Structure &structure, + const FileDatabase &db) const { + std::map::const_iterator it = converters.find(structure.name); if (it == converters.end()) { - return std::shared_ptr< ElemBase >(); + return std::shared_ptr(); } - std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))(); - (structure.*((*it).second.second))(ret,db); + std::shared_ptr ret = (structure.*((*it).second.first))(); + (structure.*((*it).second.second))(ret, db); return ret; } // ------------------------------------------------------------------------------------------------ -DNA::FactoryPair DNA :: GetBlobToStructureConverter( - const Structure& structure, - const FileDatabase& /*db*/ -) const -{ - std::map::const_iterator it = converters.find(structure.name); +DNA::FactoryPair DNA ::GetBlobToStructureConverter( + const Structure &structure, + const FileDatabase & /*db*/ +) const { + std::map::const_iterator it = converters.find(structure.name); return it == converters.end() ? FactoryPair() : (*it).second; } // basing on http://www.blender.org/development/architecture/notes-on-sdna/ // ------------------------------------------------------------------------------------------------ -void DNA :: AddPrimitiveStructures() -{ +void DNA ::AddPrimitiveStructures() { // NOTE: these are just dummies. Their presence enforces // Structure::Convert to be called on these // empty structures. These converters are special @@ -311,30 +293,27 @@ void DNA :: AddPrimitiveStructures() // in question. indices["int"] = structures.size(); - structures.push_back( Structure() ); + structures.push_back(Structure()); structures.back().name = "int"; structures.back().size = 4; indices["short"] = structures.size(); - structures.push_back( Structure() ); + structures.push_back(Structure()); structures.back().name = "short"; structures.back().size = 2; - indices["char"] = structures.size(); - structures.push_back( Structure() ); + structures.push_back(Structure()); structures.back().name = "char"; structures.back().size = 1; - indices["float"] = structures.size(); - structures.push_back( Structure() ); + structures.push_back(Structure()); structures.back().name = "float"; structures.back().size = 4; - indices["double"] = structures.size(); - structures.push_back( Structure() ); + structures.push_back(Structure()); structures.back().name = "double"; structures.back().size = 8; @@ -342,8 +321,7 @@ void DNA :: AddPrimitiveStructures() } // ------------------------------------------------------------------------------------------------ -void SectionParser :: Next() -{ +void SectionParser ::Next() { stream.SetCurrentPos(current.start + current.size); const char tmp[] = { @@ -352,7 +330,7 @@ void SectionParser :: Next() (const char)stream.GetI1(), (const char)stream.GetI1() }; - current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1); + current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1); current.size = stream.GetI4(); current.address.val = ptr64 ? stream.GetU8() : stream.GetU4(); @@ -366,10 +344,8 @@ void SectionParser :: Next() } #ifdef ASSIMP_BUILD_BLENDER_DEBUG - ASSIMP_LOG_DEBUG(current.id); + ASSIMP_LOG_VERBOSE_DEBUG(current.id); #endif } - - #endif diff --git a/code/Blender/BlenderDNA.h b/code/AssetLib/Blender/BlenderDNA.h similarity index 75% rename from code/Blender/BlenderDNA.h rename to code/AssetLib/Blender/BlenderDNA.h index 16ce960e2..25322a374 100644 --- a/code/Blender/BlenderDNA.h +++ b/code/AssetLib/Blender/BlenderDNA.h @@ -49,26 +49,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include -#include +#include #include +#include // enable verbose log output. really verbose, so be careful. #ifdef ASSIMP_BUILD_DEBUG -# define ASSIMP_BUILD_BLENDER_DEBUG +#define ASSIMP_BUILD_BLENDER_DEBUG #endif // #define ASSIMP_BUILD_BLENDER_NO_STATS -namespace Assimp { +namespace Assimp { -template class StreamReader; -typedef StreamReader StreamReaderAny; +template +class StreamReader; +typedef StreamReader StreamReaderAny; namespace Blender { -class FileDatabase; +class FileDatabase; struct FileBlockHead; template