diff --git a/.clang-format b/.clang-format index eba6d586f..c700d9700 100644 --- a/.clang-format +++ b/.clang-format @@ -70,8 +70,8 @@ IncludeCategories: - Regex: '^<.*' Priority: 3 # IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: true -# IndentPPDirectives: None +IndentCaseLabels: false +#IndentPPDirectives: AfterHash IndentWidth: 4 # IndentWrappedFunctionNames: false # JavaScriptQuotes: Leave @@ -108,7 +108,7 @@ IndentWidth: 4 # SpacesInParentheses: false # SpacesInSquareBrackets: false TabWidth: 4 -UseTab: Always +UseTab: Never --- ### C++ specific config ### Language: Cpp diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e750822ab..84e3123fe 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ patreon: assimp -ko_fi: kimkulling +custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4 +open_collective: assimp diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml new file mode 100644 index 000000000..08292d55f --- /dev/null +++ b/.github/workflows/ccpp.yml @@ -0,0 +1,59 @@ +name: C/C++ CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + job: + name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang] + # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux. + include: + - name: windows-msvc + os: windows-latest + cxx: cl.exe + cc: cl.exe + - name: ubuntu-clang + os: ubuntu-latest + cxx: clang++ + cc: clang + - name: macos-clang + os: macos-latest + cxx: clang++ + cc: clang + - name: ubuntu-gcc + os: ubuntu-latest + cxx: g++ + cc: gcc + + steps: + - uses: actions/checkout@v2 + + - uses: lukka/get-cmake@latest + + - uses: ilammy/msvc-dev-cmd@v1 + + - uses: lukka/set-shell-env@v1 + with: + CXX: ${{ matrix.cxx }} + CC: ${{ matrix.cc }} + + - name: configure and build + uses: lukka/run-cmake@v2 + with: + cmakeListsOrSettingsJson: CMakeListsTxtAdvanced + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release' + buildWithCMakeArgs: '-- -v' + buildDirectory: '${{ github.workspace }}/build/' + + - name: test + run: cd build/bin && ./unit + shell: bash diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml new file mode 100644 index 000000000..9bba5f6fd --- /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@v2 + 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/CMakeLists.txt b/CMakeLists.txt index 74154f9eb..39134d140 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,17 +39,17 @@ SET(CMAKE_POLICY_DEFAULT_CMP0074 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) -include("cmake/HunterGate.cmake") -HunterGate( +IF(ASSIMP_HUNTER_ENABLED) + include("cmake/HunterGate.cmake") + HunterGate( URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz" SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a" -) + ) -IF(HUNTER_ENABLED) add_definitions(-DASSIMP_USE_HUNTER) -ENDIF(HUNTER_ENABLED) +ENDIF() PROJECT( Assimp VERSION 5.0.1 ) @@ -60,7 +60,7 @@ OPTION( BUILD_SHARED_LIBS ON ) -OPTION( BUILD_FRAMEWORK +OPTION( ASSIMP_BUILD_FRAMEWORK "Build package as Mac OS X Framework bundle." OFF ) @@ -100,14 +100,14 @@ OPTION ( ASSIMP_COVERALLS "Enable this to measure test coverage." OFF ) +OPTION( ASSIMP_INSTALL + "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 @@ -116,30 +116,36 @@ OPTION ( ASSIMP_UBSAN "Enable Undefined Behavior sanitizer." OFF ) -OPTION ( SYSTEM_IRRXML +OPTION ( ASSIMP_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 (NOT CMAKE_BUILD_TYPE) + ENDIF () ADD_DEFINITIONS(-DENABLE_BITCODE) -ENDIF (IOS AND NOT HUNTER_ENABLED) +ENDIF () # Use subset of Windows.h if (WIN32) @@ -155,19 +161,19 @@ IF(MSVC) # Multibyte character set is deprecated since at least MSVC2015 (possibly earlier) ADD_DEFINITIONS( -DUNICODE -D_UNICODE ) ENDIF() -ENDIF(MSVC) +ENDIF() -IF (BUILD_FRAMEWORK) +IF (ASSIMP_BUILD_FRAMEWORK) SET (BUILD_SHARED_LIBS ON) MESSAGE(STATUS "Framework bundle building enabled") -ENDIF(BUILD_FRAMEWORK) +ENDIF() IF(NOT BUILD_SHARED_LIBS) MESSAGE(STATUS "Shared libraries disabled") SET(LINK_SEARCH_START_STATIC TRUE) ELSE() MESSAGE(STATUS "Shared libraries enabled") -ENDIF(NOT BUILD_SHARED_LIBS) +ENDIF() # Define here the needed parameters SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) @@ -177,12 +183,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 @@ -204,11 +210,11 @@ ENDIF() IF(NOT GIT_COMMIT_HASH) SET(GIT_COMMIT_HASH 0) -ENDIF(NOT GIT_COMMIT_HASH) +ENDIF() IF(ASSIMP_DOUBLE_PRECISION) ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) -ENDIF(ASSIMP_DOUBLE_PRECISION) +ENDIF() CONFIGURE_FILE( ${CMAKE_CURRENT_LIST_DIR}/revision.h.in @@ -238,33 +244,32 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") IF( UNIX ) # Use GNUInstallDirs for Unix predefined directories INCLUDE(GNUInstallDirs) -ENDIF( UNIX ) +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_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++) ELSEIF(MSVC) # enable multi-core compilation with MSVC - ADD_COMPILE_OPTIONS(/MP) - ADD_COMPILE_OPTIONS( /bigobj ) + ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX ) # 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}") + 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) @@ -272,7 +277,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() @@ -281,7 +286,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") @@ -290,7 +295,7 @@ IF ( IOS AND NOT HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") # Experimental for pdb generation ENDIF() -ENDIF( IOS AND NOT HUNTER_ENABLED) +ENDIF() IF (ASSIMP_COVERALLS) MESSAGE(STATUS "Coveralls enabled") @@ -309,16 +314,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") @@ -339,22 +334,18 @@ INCLUDE (PrecompiledHeader) # 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}/lib" ) + 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" ) -ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) - -# 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." ) +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 () 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") @@ -367,7 +358,7 @@ IF (NOT TARGET uninstall) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ENDIF() -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(INCLUDE_INSTALL_DIR "include") @@ -404,13 +395,35 @@ IF(HUNTER_ENABLED) NAMESPACE "${NAMESPACE}" DESTINATION "${CONFIG_INSTALL_DIR}" ) -ELSE(HUNTER_ENABLED) +ELSE() # cmake configuration files if(${BUILD_SHARED_LIBS}) set(BUILD_LIB_TYPE SHARED) else() set(BUILD_LIB_TYPE STATIC) endif() + + IF( UNIX ) + # Use GNUInstallDirs for Unix predefined directories + INCLUDE(GNUInstallDirs) + + SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) + SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR}) + ELSE() + # Cache these to allow the user to override them on non-Unix platforms + SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING + "Path the built library files are installed to." ) + SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING + "Path the header files are installed to." ) + SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING + "Path the tool executables are installed to." ) + + SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR}) + SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}) + SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR}) + ENDIF() + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) IF (is_multi_config) @@ -432,22 +445,20 @@ ELSE(HUNTER_ENABLED) "${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}) -ENDIF(HUNTER_ENABLED) +ENDIF() -FIND_PACKAGE( DirectX ) - -IF( BUILD_DOCS ) +IF( ASSIMP_BUILD_DOCS ) ADD_SUBDIRECTORY(doc) -ENDIF( BUILD_DOCS ) +ENDIF() # Look for system installed irrXML -IF ( SYSTEM_IRRXML ) +IF ( ASSIMP_SYSTEM_IRRXML ) FIND_PACKAGE( IrrXML REQUIRED ) -ENDIF( SYSTEM_IRRXML ) +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) @@ -455,10 +466,10 @@ IF(HUNTER_ENABLED) set(ZLIB_FOUND TRUE) set(ZLIB_LIBRARIES ZLIB::zlib) set(ASSIMP_BUILD_MINIZIP TRUE) -ELSE(HUNTER_ENABLED) +ELSE() IF ( NOT ASSIMP_BUILD_ZLIB ) FIND_PACKAGE(ZLIB) - ENDIF( NOT ASSIMP_BUILD_ZLIB ) + ENDIF() IF( NOT ZLIB_FOUND ) MESSAGE(STATUS "compiling zlib from sources") @@ -481,46 +492,46 @@ ELSE(HUNTER_ENABLED) SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) # need to ensure we don't link with system zlib or minizip as well. SET(ASSIMP_BUILD_MINIZIP 1) - ELSE(NOT ZLIB_FOUND) + ELSE() ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) SET(ZLIB_LIBRARIES_LINKED -lz) - ENDIF(NOT ZLIB_FOUND) + ENDIF() INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) -ENDIF(HUNTER_ENABLED) +ENDIF() IF( NOT IOS ) IF( NOT ASSIMP_BUILD_MINIZIP ) use_pkgconfig(UNZIP minizip) - ENDIF( NOT ASSIMP_BUILD_MINIZIP ) -ELSE ( NOT IOS ) + ENDIF() +ELSE () IF( NOT BUILD_SHARED_LIBS ) IF( NOT ASSIMP_BUILD_MINIZIP ) use_pkgconfig(UNZIP minizip) - ENDIF( NOT ASSIMP_BUILD_MINIZIP ) - ENDIF ( NOT BUILD_SHARED_LIBS ) -ENDIF ( NOT IOS ) + ENDIF() + ENDIF () +ENDIF () IF ( ASSIMP_NO_EXPORT ) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT) MESSAGE( STATUS "Build an import-only version of Assimp." ) -ENDIF( ASSIMP_NO_EXPORT ) +ENDIF() SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING "describe the current architecture." ) -IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") -ELSE ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") +IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") +ELSE() ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' ) -ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") +ENDIF() # ${CMAKE_GENERATOR} SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING "describe the current compiler." ) -IF ( ASSIMP_BUILD_COMPILER STREQUAL "") -ELSE ( ASSIMP_BUILD_COMPILER STREQUAL "") +IF( ASSIMP_BUILD_COMPILER STREQUAL "") +ELSE() ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' ) -ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "") +ENDIF() MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) @@ -566,91 +577,97 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) MESSAGE( FATAL_ERROR "C4D is currently only available on Windows with melange SDK installed in contrib/Melange" ) - ENDIF ( MSVC ) -ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) + ENDIF () +ELSE () ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) -ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ENDIF () -IF(NOT HUNTER_ENABLED) +IF(NOT ASSIMP_HUNTER_ENABLED) ADD_SUBDIRECTORY(contrib) -ENDIF(NOT HUNTER_ENABLED) +ENDIF() ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) # The viewer for windows only - IF ( WIN32 AND DirectX_D3DX9_LIBRARY ) - OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} ) + IF ( WIN32 ) + OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF ) IF ( ASSIMP_BUILD_ASSIMP_VIEW ) ADD_SUBDIRECTORY( tools/assimp_view/ ) - ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW ) - ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY ) - # Te command line tool + ENDIF () + ENDIF () + # The command line tool ADD_SUBDIRECTORY( tools/assimp_cmd/ ) -ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) +ENDIF () IF ( ASSIMP_BUILD_SAMPLES) + SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples ) + SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode ) IF ( WIN32 ) ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ ) ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 ) - ENDIF ( WIN32 ) + ENDIF () ADD_SUBDIRECTORY( samples/SimpleOpenGL/ ) -ENDIF ( ASSIMP_BUILD_SAMPLES ) +ENDIF () IF ( ASSIMP_BUILD_TESTS ) ADD_SUBDIRECTORY( test/ ) -ENDIF ( ASSIMP_BUILD_TESTS ) +ENDIF () # Generate a pkg-config .pc for the Assimp library. CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY ) -INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT}) +IF ( ASSIMP_INSTALL ) + INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT}) +ENDIF() -IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) - # Packing information - SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}") - SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.") - SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp") - SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}") - SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}") - SET(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" ) - SET(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}") - SET(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}") - SET(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}") - SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") - SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +IF ( ASSIMP_INSTALL ) + IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) + # Packing information + SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}") + SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.") + SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp") + SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}") + SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}") + SET(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" ) + SET(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}") + SET(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}") + SET(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}") + SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") + SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") - STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") - STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") + STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") + STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") - SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools") - SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" ) - SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries") - SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs") - SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" ) - SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" ) - SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" ) - SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config) + SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools") + SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" ) + SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries") + SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs") + SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" ) + SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" ) + SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" ) + SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config) - # debian - SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") - SET(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}") - SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" ) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}") - SET(CPACK_DEBIAN_PACKAGE_SUGGESTS) - set(cPACK_DEBIAN_PACKAGE_NAME "assimp") - SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging) - SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) - SET(CPACK_DEBIAN_CHANGELOG) - execute_process(COMMAND lsb_release -is - OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _lsb_release_failed) - SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton") - STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME) - IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" ) - SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release") + # debian + SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") + SET(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}") + SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" ) + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}") + SET(CPACK_DEBIAN_PACKAGE_SUGGESTS) + SET(cPACK_DEBIAN_PACKAGE_NAME "assimp") + SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging) + SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) + SET(CPACK_DEBIAN_CHANGELOG) + execute_process(COMMAND lsb_release -is + OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _lsb_release_failed) + SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton") + STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME) + IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" ) + SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release") + ENDIF() + SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources") + INCLUDE(CPack) + INCLUDE(DebSourcePPA) ENDIF() - SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources") - INCLUDE(CPack) - INCLUDE(DebSourcePPA) ENDIF() if(WIN32) @@ -671,7 +688,7 @@ if(WIN32) SET(ASSIMP_MSVC_VERSION "vc140") ELSEIF(MSVC15) SET(ASSIMP_MSVC_VERSION "vc141") - ENDIF(MSVC12) + ENDIF() ENDIF() IF(MSVC12 OR MSVC14 OR MSVC15 ) @@ -696,5 +713,5 @@ if(WIN32) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ENDIF() - ENDIF(MSVC12 OR MSVC14 OR MSVC15 ) -ENDIF (WIN32) + ENDIF() +ENDIF () 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 7e0a8cccc..15e76b9d2 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +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) @@ -178,6 +180,28 @@ 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 + + + +#### 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/appveyor.yml b/appveyor.yml index 299f42df6..4fb79dd69 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,10 +17,10 @@ matrix: image: - Visual Studio 2013 - - Visual Studio 2015 - - Visual Studio 2017 + #- Visual Studio 2015 + #- Visual Studio 2017 - Visual Studio 2019 - - MinGW + #- MinGW platform: - Win32 diff --git a/assimp.pc.in b/assimp.pc.in index c659e19f2..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@/../include/@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 index e4ccbfba9..b7efe71f9 100644 --- a/assimpTargets-debug.cmake.in +++ b/assimpTargets-debug.cmake.in @@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1) set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) +get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) + if(MSVC) if(MSVC_TOOLSET_VERSION) set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") @@ -35,8 +37,6 @@ if(MSVC) 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@") @@ -44,22 +44,22 @@ if(MSVC) # 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}" + IMPORTED_IMPLIB_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}" + IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_BINDIR@/${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}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${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}" + IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}") endif() else() @@ -73,25 +73,28 @@ else() else() set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") endif() + + # Import target "assimp::assimp" for configuration "Debug" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_DEBUG "${sharedLibraryName}" - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" + IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) else() set(staticLibraryName "libassimp${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}" + IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) endif() endif() - - - # Commands beyond this point should not need to know the version. set(CMAKE_IMPORT_FILE_VERSION) diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in index 79b643a9a..c716006dd 100644 --- a/assimpTargets-release.cmake.in +++ b/assimpTargets-release.cmake.in @@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1) set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) +get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) + if(MSVC) if(MSVC_TOOLSET_VERSION) set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") @@ -34,8 +36,6 @@ if(MSVC) 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@") @@ -44,22 +44,22 @@ if(MSVC) # 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}" + IMPORTED_IMPLIB_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}" + IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_BINDIR@/${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}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${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}" + IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}") endif() else() @@ -73,20 +73,25 @@ else() else() set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") endif() + + # Import target "assimp::assimp" for configuration "Release" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_RELEASE "${sharedLibraryName}" - - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" + IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" ) else() set(staticLibraryName "libassimp${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}" + IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" ) endif() endif() diff --git a/assimpTargets.cmake.in b/assimpTargets.cmake.in index b1c618c3a..897d00217 100644 --- a/assimpTargets.cmake.in +++ b/assimpTargets.cmake.in @@ -43,23 +43,13 @@ 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_INCLUDE_DIRECTORIES "@CMAKE_INSTALL_FULL_INCLUDEDIR@" #INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine" ) @@ -74,9 +64,6 @@ 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}} ) diff --git a/code/AMF/AMFImporter.cpp b/code/AMF/AMFImporter.cpp deleted file mode 100644 index f8dbd1b6e..000000000 --- a/code/AMF/AMFImporter.cpp +++ /dev/null @@ -1,701 +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 - -#include - -namespace Assimp { - -/// \var aiImporterDesc AMFImporter::Description -/// Constant 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 (AMFNodeElementBase *ne : mNodeElement_List) { - delete ne; - } - - mNodeElement_List.clear(); - } -} - -AMFImporter::~AMFImporter() { - if (mXmlParser != nullptr) { - delete mXmlParser; - mXmlParser = nullptr; - } - - // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. - Clear(); -} - -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; - XmlNode *root = mXmlParser->parse(file.get()); - if (nullptr == root) { - throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); - } - - // start reading - // search for root tag - - if (!root->find_child("amf")) { - throw DeadlyImportError("Root node \"amf\" not found."); - } - - ParseNode_Root(*root); - - delete mXmlParser; - mXmlParser = nullptr; -} - -// -// -// Root XML element. -// Multi elements - No. -void AMFImporter::ParseNode_Root(XmlNode &root) { - std::string unit, version; - AMFNodeElementBase *ne(nullptr); - - // Read attributes for node . - for (pugi::xml_attribute_iterator ait = root.attributes_begin(); ait != root.attributes_end(); ++ait) { - if (ait->name() == "unit") { - unit = ait->as_string(); - } else if (ait->name() == "version") { - version = ait->as_string(); - } - } - - // Check attributes - if (!mUnit.empty()) { - if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) { - throw DeadlyImportError("Root node does not contain any units."); - } - } - - // create root node element. - ne = new AMFRoot(nullptr); - - // set first "current" element - mNodeElement_Cur = ne; - - // and assign attributes values - ((AMFRoot *)ne)->Unit = unit; - ((AMFRoot *)ne)->Version = version; - - // Check for child nodes - for (pugi::xml_node child : node->children()) { - if (child.name() == "object") { - ParseNode_Object(child); - } else if (child.name() == "material") { - ParseNode_Material(child); - } else if (child.name() == "texture") { - ParseNode_Texture(child); - } else if (child.name() == "constellation") { - ParseNode_Constellation(child); - } else if (child.name() == "metadata") { - ParseNode_Metadata(child); - } - } - 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 &root) { - std::string id = root.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 - - for (pugi::xml_node &child : root.children()) { - if (child.name() == "instance") { - ParseNode_Instance(child); - } else if (child.name() == "metadata") { - ParseNode_Metadata(child); - } - } - - 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 &root) { - std::string objectid = root.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. - AMFNodeElementBase *ne = new AMFInstance(mNodeElement_Cur); - - AMFInstance &als = *((AMFInstance *)ne); // alias for convenience - - als.ObjectID = objectid; - // Check for child nodes - if (!mXmlParser->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(XmlNode &node) { - - std::string id; - for (pugi::xml_attribute_iterator ait = node.attributes_begin(); ait != node.attributes_end(); ++ait) { - if (ait->name() == "id") { - id = ait->as_string(); - } - } - // Read attributes for node . - - // create and if needed - define new geometry object. - AMFNodeElementBase *ne = new AMFObject(mNodeElement_Cur); - - AMFObject &als = *((AMFObject *)ne); // alias for convenience - - if (!id.empty()) { - als.ID = id; - } - - // Check for child nodes - for (pugi::xml_node_iterator it = node.children().begin(); it != node.children->end(); ++it) { - bool col_read = false; - if (it->name() == "mesh") { - ParseNode_Mesh(*it); - } else if (it->name() == "metadata") { - ParseNode_Metadata(*it); - } else if (it->name() == "color") { - ParseNode_Color(*it); - } - } - - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element -} - -// -// -// 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; - AMFNodeElementBase *ne(nullptr); - - // read attribute - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("type", type, mXmlParser->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - // and value of node. - value = mXmlParser->getNodeData(); - // Create node element and assign read data. - 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. -} - -/*********************************************************************************************************************************************/ -/******************************************************** 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[] = { " &extensionList) { - extensionList.insert("amf"); -} - -const aiImporterDesc *AMFImporter::GetInfo() const { - return &Description; -} - -void AMFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { - Clear(); - - ParseFile(pFile, pIOHandler); - - Postprocess_BuildScene(pScene); -} - -void AMFImporter::ParseNode_Mesh(XmlNode &node) { - AMFNodeElementBase *ne; - - if (node.empty()) { - return; - } - - for (pugi::xml_node &child : node.children()) { - if (child.name() == "vertices") { - ParseNode_Vertices(child); - } - } - // create new mesh object. - ne = new AMFMesh(mNodeElement_Cur); - // Check for child nodes - if (!mXmlParser->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 - 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(XmlNode &node) { - AMFNodeElementBase *ne = new AMFVertices(mNodeElement_Cur); - - for (pugi::xml_node &child : node.children()) { - if (child.name() == "vertices") { - ParseNode_Vertex(child); - } - } - // Check for child nodes - - 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() { - AMFNodeElementBase *ne; - - // create new mesh object. - ne = new AMFVertex(mNodeElement_Cur); - // Check for child nodes - if (!mXmlParser->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() { - AMFNodeElementBase *ne; - - // create new color object. - ne = new AMFCoordinates(mNodeElement_Cur); - - AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience - - // Check for child nodes - if (!mXmlParser->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; - AMFNodeElementBase *ne; - - // Read attributes for node . - MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mXmlParser->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("type", type, mXmlParser->getAttributeValue); - MACRO_ATTRREAD_LOOPEND; - - // create new object. - ne = new AMFVolume(mNodeElement_Cur); - // and assign read data - ((AMFVolume *)ne)->MaterialID = materialid; - ((AMFVolume *)ne)->Type = type; - // Check for child nodes - if (!mXmlParser->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() { - AMFNodeElementBase *ne; - - // create new color object. - ne = new AMFTriangle(mNodeElement_Cur); - - AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience - - // Check for child nodes - if (!mXmlParser->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/Assbin/AssbinExporter.cpp b/code/Assbin/AssbinExporter.cpp deleted file mode 100644 index 86a42c400..000000000 --- a/code/Assbin/AssbinExporter.cpp +++ /dev/null @@ -1,847 +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 AssbinExporter.cpp - * ASSBIN exporter main code - */ - -#ifndef ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER - -#include "Common/assbin_chunks.h" -#include "PostProcessing/ProcessHelper.h" - -#include -#include -#include -#include -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include "../contrib/zlib/zlib.h" -#endif - -#include - -namespace Assimp { - -template -size_t Write(IOStream * stream, const T& v) { - return stream->Write( &v, sizeof(T), 1 ); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiString -template <> -inline -size_t Write(IOStream * stream, const aiString& s) { - const size_t s2 = (uint32_t)s.length; - stream->Write(&s,4,1); - stream->Write(s.data,s2,1); - - return s2+4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint32_t -template <> -inline -size_t Write(IOStream * stream, const unsigned int& w) { - const uint32_t t = (uint32_t)w; - if (w > t) { - // this shouldn't happen, integers in Assimp data structures never exceed 2^32 - throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); - } - - stream->Write(&t,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint16_t -template <> -inline -size_t Write(IOStream * stream, const uint16_t& w) { - static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); - stream->Write(&w,2,1); - - return 2; -} - -// ----------------------------------------------------------------------------------- -// Serialize a float -template <> -inline -size_t Write(IOStream * stream, const float& f) { - static_assert(sizeof(float)==4, "sizeof(float)==4"); - stream->Write(&f,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize a double -template <> -inline -size_t Write(IOStream * stream, const double& f) { - static_assert(sizeof(double)==8, "sizeof(double)==8"); - stream->Write(&f,8,1); - - return 8; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vec3 -template <> -inline -size_t Write(IOStream * stream, const aiVector3D& v) { - size_t t = Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor3D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor4D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - t += Write(stream,v.a); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a quaternion -template <> -inline -size_t Write(IOStream * stream, const aiQuaternion& v) { - size_t t = Write(stream,v.w); - t += Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - ai_assert(t == 16); - - return 16; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vertex weight -template <> -inline -size_t Write(IOStream * stream, const aiVertexWeight& v) { - size_t t = Write(stream,v.mVertexId); - - return t+Write(stream,v.mWeight); -} - -// ----------------------------------------------------------------------------------- -// Serialize a mat4x4 -template <> -inline -size_t Write(IOStream * stream, const aiMatrix4x4& m) { - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - Write(stream,m[i][i2]); - } - } - - return 64; -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiVectorKey -template <> -inline -size_t Write(IOStream * stream, const aiVectorKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiQuatKey -template <> -inline -size_t Write(IOStream * stream, const aiQuatKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -template -inline -size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { - T minc, maxc; - ArrayBounds(in,size,minc,maxc); - - const size_t t = Write(stream,minc); - return t + Write(stream,maxc); -} - -// We use this to write out non-byte arrays so that we write using the specializations. -// This way we avoid writing out extra bytes that potentially come from struct alignment. -template -inline -size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { - size_t n = 0; - for (unsigned int i=0; i(stream,in[i]); - - return n; -} - -// ---------------------------------------------------------------------------------- -/** @class AssbinChunkWriter - * @brief Chunk writer mechanism for the .assbin file structure - * - * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), - * the difference being that this takes another IOStream as a "container" in the - * constructor, and when it is destroyed, it appends the magic number, the chunk size, - * and the chunk contents to the container stream. This allows relatively easy chunk - * chunk construction, even recursively. - */ -class AssbinChunkWriter : public IOStream -{ -private: - - uint8_t* buffer; - uint32_t magic; - IOStream * container; - size_t cur_size, cursor, initial; - -private: - // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); - - const uint8_t* const old = buffer; - buffer = new uint8_t[new_size]; - - if (old) { - memcpy(buffer,old,cur_size); - delete[] old; - } - - cur_size = new_size; - } - -public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { - } - - virtual ~AssbinChunkWriter() - { - if (container) { - container->Write( &magic, sizeof(uint32_t), 1 ); - container->Write( &cursor, sizeof(uint32_t), 1 ); - container->Write( buffer, 1, cursor ); - } - if (buffer) delete[] buffer; - } - - void * GetBufferPointer() { return buffer; } - - // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { - return 0; - } - virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { - return aiReturn_FAILURE; - } - virtual size_t Tell() const { - return cursor; - } - virtual void Flush() { - // not implemented - } - - virtual size_t FileSize() const { - return cursor; - } - - // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { - pSize *= pCount; - if (cursor + pSize > cur_size) { - Grow(cursor + pSize); - } - - memcpy(buffer+cursor, pvBuffer, pSize); - cursor += pSize; - - return pCount; - } - -}; - -// ---------------------------------------------------------------------------------- -/** @class AssbinExport - * @brief Assbin exporter class - * - * This class performs the .assbin exporting, and is responsible for the file layout. - */ -class AssbinExport -{ -private: - bool shortened; - bool compressed; - -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); - - Write(&chunk,node->mName); - Write(&chunk,node->mTransformation); - Write(&chunk,node->mNumChildren); - Write(&chunk,node->mNumMeshes); - Write(&chunk,nb_metadata); - - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - Write(&chunk,node->mMeshes[i]); - } - - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteBinaryNode( &chunk, node->mChildren[i] ); - } - - for (unsigned int i = 0; i < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; - aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; - - Write(&chunk, key); - Write(&chunk, 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; -#ifdef SWIG - case FORCE_32BIT: -#endif // SWIG - default: - break; - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); - - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); - // Write the texture format, but don't include the null terminator. - chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); - - if(!shortened) { - if (!tex->mHeight) { - chunk.Write(tex->pcData,1,tex->mWidth); - } - else { - chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); - } - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryBone(IOStream * container, const aiBone* b) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); - - Write(&chunk,b->mName); - Write(&chunk,b->mNumWeights); - Write(&chunk,b->mOffsetMatrix); - - // for the moment we write dumb min/max values for the bones, too. - // maybe I'll add a better, hash-like solution later - if (shortened) { - WriteBounds(&chunk,b->mWeights,b->mNumWeights); - } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); - - Write(&chunk,mesh->mPrimitiveTypes); - Write(&chunk,mesh->mNumVertices); - Write(&chunk,mesh->mNumFaces); - Write(&chunk,mesh->mNumBones); - Write(&chunk,mesh->mMaterialIndex); - - // first of all, write bits for all existent vertex components - unsigned int c = 0; - if (mesh->mVertices) { - c |= ASSBIN_MESH_HAS_POSITIONS; - } - if (mesh->mNormals) { - c |= ASSBIN_MESH_HAS_NORMALS; - } - if (mesh->mTangents && mesh->mBitangents) { - c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) { - break; - } - c |= ASSBIN_MESH_HAS_TEXCOORD(n); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) { - break; - } - c |= ASSBIN_MESH_HAS_COLOR(n); - } - Write(&chunk,c); - - aiVector3D minVec, maxVec; - if (mesh->mVertices) { - if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); - } - if (mesh->mNormals) { - if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); - } - if (mesh->mTangents && mesh->mBitangents) { - if (shortened) { - WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); - } // else write as usual - else { - WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); - } - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) - break; - - if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) - break; - - // write number of UV components - Write(&chunk,mesh->mNumUVComponents[n]); - - if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } - - // write faces. There are no floating-point calculations involved - // in these, so we can write a simple hash over the face data - // to the dump file. We generate a single 32 Bit hash for 512 faces - // using Assimp's standard hashing function. - if (shortened) { - unsigned int processed = 0; - for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { - - uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { - - const aiFace& f = mesh->mFaces[processed+a]; - uint32_t tmp = f.mNumIndices; - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); - tmp = static_cast( f.mIndices[i] ); - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - } - } - Write(&chunk,hash); - } - } - else // else write as usual - { - // if there are less than 2^16 vertices, we can simply use 16 bit integers ... - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; - - static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); - - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - Write(&chunk,f.mIndices[a]); - } - else Write(&chunk,f.mIndices[a]); - } - } - } - - // write bones - if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - WriteBinaryBone(&chunk,b); - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); - - Write(&chunk,prop->mKey); - Write(&chunk,prop->mSemantic); - Write(&chunk,prop->mIndex); - - Write(&chunk,prop->mDataLength); - Write(&chunk,(unsigned int)prop->mType); - chunk.Write(prop->mData,1,prop->mDataLength); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); - - Write(&chunk,mat->mNumProperties); - for (unsigned int i = 0; i < mat->mNumProperties;++i) { - WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); - - Write(&chunk,nd->mNodeName); - Write(&chunk,nd->mNumPositionKeys); - Write(&chunk,nd->mNumRotationKeys); - Write(&chunk,nd->mNumScalingKeys); - Write(&chunk,nd->mPreState); - Write(&chunk,nd->mPostState); - - if (nd->mPositionKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - } - if (nd->mRotationKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - } - if (nd->mScalingKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - } - } - - - // ----------------------------------------------------------------------------------- - void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); - - Write(&chunk,anim->mName); - Write(&chunk,anim->mDuration); - Write(&chunk,anim->mTicksPerSecond); - Write(&chunk,anim->mNumChannels); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - WriteBinaryNodeAnim(&chunk,nd); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryLight( IOStream * container, const aiLight* l ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); - - Write(&chunk,l->mName); - Write(&chunk,l->mType); - - if (l->mType != aiLightSource_DIRECTIONAL) { - Write(&chunk,l->mAttenuationConstant); - Write(&chunk,l->mAttenuationLinear); - Write(&chunk,l->mAttenuationQuadratic); - } - - Write(&chunk,l->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); - - if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); - - Write(&chunk,cam->mName); - Write(&chunk,cam->mPosition); - Write(&chunk,cam->mLookAt); - Write(&chunk,cam->mUp); - Write(&chunk,cam->mHorizontalFOV); - Write(&chunk,cam->mClipPlaneNear); - Write(&chunk,cam->mClipPlaneFar); - Write(&chunk,cam->mAspect); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryScene( IOStream * container, const aiScene* scene) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); - - // basic scene information - Write(&chunk,scene->mFlags); - Write(&chunk,scene->mNumMeshes); - Write(&chunk,scene->mNumMaterials); - Write(&chunk,scene->mNumAnimations); - Write(&chunk,scene->mNumTextures); - Write(&chunk,scene->mNumLights); - Write(&chunk,scene->mNumCameras); - - // write node graph - WriteBinaryNode( &chunk, scene->mRootNode ); - - // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteBinaryMesh( &chunk,mesh); - } - - // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - WriteBinaryMaterial(&chunk,mat); - } - - // write all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - const aiAnimation* anim = scene->mAnimations[i]; - WriteBinaryAnim(&chunk,anim); - } - - - // write all textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - const aiTexture* mesh = scene->mTextures[i]; - WriteBinaryTexture(&chunk,mesh); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - WriteBinaryLight(&chunk,l); - } - - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); - } - - } - -public: - AssbinExport() - : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters - { - } - - // ----------------------------------------------------------------------------------- - // Write a binary model dump - void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); - if (!out) return; - - time_t tt = time(NULL); -#if _WIN32 - tm* p = gmtime(&tt); -#else - struct tm now; - tm* p = gmtime_r(&tt, &now); -#endif - - // header - char s[64]; - memset( s, 0, 64 ); -#if _MSC_VER >= 1400 - sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); -#else - ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); -#endif - out->Write( s, 44, 1 ); - // == 44 bytes - - Write( out, ASSBIN_VERSION_MAJOR ); - Write( out, ASSBIN_VERSION_MINOR ); - Write( out, aiGetVersionRevision() ); - Write( out, aiGetCompileFlags() ); - Write( out, shortened ); - Write( out, compressed ); - // == 20 bytes - - char buff[256]; - strncpy(buff,pFile,256); - out->Write(buff,sizeof(char),256); - - char cmd[] = "\0"; - strncpy(buff,cmd,128); - out->Write(buff,sizeof(char),128); - - // leave 64 bytes free for future extensions - memset(buff,0xcd,64); - out->Write(buff,sizeof(char),64); - // == 435 bytes - - // ==== total header size: 512 bytes - ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); - - // 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 ); - WriteBinaryScene( &uncompressedStream, pScene ); - - uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); - uLongf compressedSize = (uLongf)compressBound(uncompressedSize); - uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; - - int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); - if(res != Z_OK) - { - delete [] compressedBuffer; - pIOSystem->Close(out); - throw DeadlyExportError("Compression failed."); - } - - out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); - out->Write( compressedBuffer, sizeof(char), compressedSize ); - - delete[] compressedBuffer; - } - else - { - WriteBinaryScene( out, pScene ); - } - - pIOSystem->Close( out ); - } -}; - -void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { - AssbinExport exporter; - exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); -} -} // end of namespace Assimp - -#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT 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 68% rename from code/3DS/3DSExporter.cpp rename to code/AssetLib/3DS/3DSExporter.cpp index 14810cbff..5f3d955da 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(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,28 +183,26 @@ 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); - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN); + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAIN); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_OBJMESH); WriteMaterials(); WriteMeshes(); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE); + ChunkWriter curChunk1(writer, Discreet3DS::CHUNK_MASTER_SCALE); writer.PutF4(1.0f); } } { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_KEYFRAMER); WriteHierarchy(*scene->mRootNode, -1, -1); } } @@ -217,15 +212,13 @@ 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 chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); // Assimp node names are unique and distinct from all mesh-node // names we generate; thus we can use them as-is @@ -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 = sibling_level; + hierarchy_pos = (uint16_t)sibling_level; } // Write the hierarchy position @@ -260,9 +253,9 @@ 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 chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO); { ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); WriteString(GetMeshName(mesh, mesh_idx, node)); @@ -276,36 +269,35 @@ 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 chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); - const aiMaterial& mat = *scene->mMaterials[i]; + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); + 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); } aiColor3D color; if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); WriteColor(color); } @@ -314,7 +306,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,7 +333,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); @@ -370,8 +361,7 @@ 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 @@ -389,19 +379,18 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type ChunkWriter chunk(writer, chunk_flags); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPFILE); WriteString(path); } WritePercentChunk(blend); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); 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 +399,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,36 +411,35 @@ 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); // Vertices in world space { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_VERTLIST); 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); @@ -461,12 +448,12 @@ void Discreet3DSExporter::WriteMeshes() // UV coordinates if (mesh.HasTextureCoords(0)) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPLIST); const uint16_t count = static_cast(mesh.mNumVertices); 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); } @@ -474,14 +461,14 @@ void Discreet3DSExporter::WriteMeshes() // Faces (indices) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACELIST); ai_assert(mesh.mNumFaces <= 0xffff); // 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 +479,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; } @@ -513,7 +500,7 @@ void Discreet3DSExporter::WriteMeshes() // Transformation matrix by which the mesh vertices have been pre-transformed with. { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX); for (unsigned int r = 0; r < 4; ++r) { for (unsigned int c = 0; c < 3; ++c) { writer.PutF4(trafo[r][c]); @@ -524,10 +511,9 @@ void Discreet3DSExporter::WriteMeshes() } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) -{ - ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT); - const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); +void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) { + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT); + const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); WriteString(name); // Because assimp splits meshes by material, only a single @@ -542,7 +528,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 +536,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,8 +544,8 @@ void Discreet3DSExporter::WriteString(const aiString& s) { } // ------------------------------------------------------------------------------------------------ -void Discreet3DSExporter::WriteColor(const aiColor3D& color) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF); +void Discreet3DSExporter::WriteColor(const aiColor3D &color) { + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF); writer.PutF4(color.r); writer.PutF4(color.g); writer.PutF4(color.b); @@ -567,16 +553,15 @@ void Discreet3DSExporter::WriteColor(const aiColor3D& color) { // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WritePercentChunk(float f) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_PERCENTF); writer.PutF4(f); } // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WritePercentChunk(double f) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTD); + ChunkWriter ccurChunkhunk(writer, Discreet3DS::CHUNK_PERCENTD); 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 51% rename from code/3DS/3DSHelper.h rename to code/AssetLib/3DS/3DSHelper.h index e483f1a25..e348c090d 100644 --- a/code/3DS/3DSHelper.h +++ b/code/AssetLib/3DS/3DSHelper.h @@ -45,18 +45,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_3DSFILEHELPER_H_INC #define AI_3DSFILEHELPER_H_INC -#include #include +#include #include -#include -#include +#include #include #include -#include +#include +#include #include //sprintf -namespace Assimp { -namespace D3DS { +namespace Assimp { +namespace D3DS { #include @@ -77,15 +77,13 @@ private: public: //! data structure for a single chunk in a .3ds file struct Chunk { - uint16_t Flag; - uint32_t Size; + uint16_t Flag; + uint32_t Size; } PACK_STRUCT; - //! Used for shading field in material3ds structure //! From AutoDesk 3ds SDK - typedef enum - { + typedef enum { // translated to gouraud shading with wireframe active Wire = 0x0, @@ -109,59 +107,57 @@ public: } shadetype3ds; // Flags for animated keys - enum - { - KEY_USE_TENS = 0x1, - KEY_USE_CONT = 0x2, - KEY_USE_BIAS = 0x4, - KEY_USE_EASE_TO = 0x8, - KEY_USE_EASE_FROM = 0x10 - } ; + enum { + KEY_USE_TENS = 0x1, + KEY_USE_CONT = 0x2, + KEY_USE_BIAS = 0x4, + KEY_USE_EASE_TO = 0x8, + KEY_USE_EASE_FROM = 0x10 + }; - enum - { + enum { // ******************************************************************** // Basic chunks which can be found everywhere in the file - CHUNK_VERSION = 0x0002, - CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B - CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B + CHUNK_VERSION = 0x0002, + CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B + CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B // Linear color values (gamma = 2.2?) - CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B - CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B + CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B + CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B - CHUNK_PERCENTW = 0x0030, // int2 percentage - CHUNK_PERCENTF = 0x0031, // float4 percentage - CHUNK_PERCENTD = 0x0032, // float8 percentage + CHUNK_PERCENTW = 0x0030, // int2 percentage + CHUNK_PERCENTF = 0x0031, // float4 percentage + CHUNK_PERCENTD = 0x0032, // float8 percentage // ******************************************************************** // Prj master chunk - CHUNK_PRJ = 0xC23D, + CHUNK_PRJ = 0xC23D, // MDLI master chunk - CHUNK_MLI = 0x3DAA, + CHUNK_MLI = 0x3DAA, // Primary main chunk of the .3ds file - CHUNK_MAIN = 0x4D4D, + CHUNK_MAIN = 0x4D4D, // Mesh main chunk - CHUNK_OBJMESH = 0x3D3D, + CHUNK_OBJMESH = 0x3D3D, // Specifies the background color of the .3ds file // This is passed through the material system for // viewing purposes. - CHUNK_BKGCOLOR = 0x1200, + CHUNK_BKGCOLOR = 0x1200, // Specifies the ambient base color of the scene. // This is added to all materials in the file - CHUNK_AMBCOLOR = 0x2100, + CHUNK_AMBCOLOR = 0x2100, // Specifies the background image for the whole scene // This value is passed through the material system // to the viewer - CHUNK_BIT_MAP = 0x1100, - CHUNK_BIT_MAP_EXISTS = 0x1101, + CHUNK_BIT_MAP = 0x1100, + CHUNK_BIT_MAP_EXISTS = 0x1101, // ******************************************************************** // Viewport related stuff. Ignored @@ -177,171 +173,222 @@ public: // ******************************************************************** // Mesh chunks - CHUNK_OBJBLOCK = 0x4000, - CHUNK_TRIMESH = 0x4100, - CHUNK_VERTLIST = 0x4110, + CHUNK_OBJBLOCK = 0x4000, + CHUNK_TRIMESH = 0x4100, + CHUNK_VERTLIST = 0x4110, CHUNK_VERTFLAGS = 0x4111, - CHUNK_FACELIST = 0x4120, - CHUNK_FACEMAT = 0x4130, - CHUNK_MAPLIST = 0x4140, - CHUNK_SMOOLIST = 0x4150, - CHUNK_TRMATRIX = 0x4160, + CHUNK_FACELIST = 0x4120, + CHUNK_FACEMAT = 0x4130, + CHUNK_MAPLIST = 0x4140, + CHUNK_SMOOLIST = 0x4150, + CHUNK_TRMATRIX = 0x4160, CHUNK_MESHCOLOR = 0x4165, - CHUNK_TXTINFO = 0x4170, - CHUNK_LIGHT = 0x4600, - CHUNK_CAMERA = 0x4700, + CHUNK_TXTINFO = 0x4170, + CHUNK_LIGHT = 0x4600, + CHUNK_CAMERA = 0x4700, CHUNK_HIERARCHY = 0x4F00, // Specifies the global scaling factor. This is applied // to the root node's transformation matrix - CHUNK_MASTER_SCALE = 0x0100, + CHUNK_MASTER_SCALE = 0x0100, // ******************************************************************** // Material chunks - CHUNK_MAT_MATERIAL = 0xAFFF, + CHUNK_MAT_MATERIAL = 0xAFFF, - // asciiz containing the name of the material - CHUNK_MAT_MATNAME = 0xA000, - CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk - CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk - CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk + // asciiz containing the name of the material + CHUNK_MAT_MATNAME = 0xA000, + CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk + CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk + CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk - // Specifies the shininess of the material - // followed by percentage chunk - CHUNK_MAT_SHININESS = 0xA040, - CHUNK_MAT_SHININESS_PERCENT = 0xA041 , + // Specifies the shininess of the material + // followed by percentage chunk + CHUNK_MAT_SHININESS = 0xA040, + CHUNK_MAT_SHININESS_PERCENT = 0xA041, - // Specifies the shading mode to be used - // followed by a short - CHUNK_MAT_SHADING = 0xA100, + // Specifies the shading mode to be used + // followed by a short + CHUNK_MAT_SHADING = 0xA100, - // NOTE: Emissive color (self illumination) seems not - // to be a color but a single value, type is unknown. - // Make the parser accept both of them. - // followed by percentage chunk (?) - CHUNK_MAT_SELF_ILLUM = 0xA080, + // NOTE: Emissive color (self illumination) seems not + // to be a color but a single value, type is unknown. + // Make the parser accept both of them. + // followed by percentage chunk (?) + CHUNK_MAT_SELF_ILLUM = 0xA080, - // Always followed by percentage chunk (?) - CHUNK_MAT_SELF_ILPCT = 0xA084, + // Always followed by percentage chunk (?) + CHUNK_MAT_SELF_ILPCT = 0xA084, - // Always followed by percentage chunk - CHUNK_MAT_TRANSPARENCY = 0xA050, + // Always followed by percentage chunk + CHUNK_MAT_TRANSPARENCY = 0xA050, - // Diffuse texture channel 0 - CHUNK_MAT_TEXTURE = 0xA200, + // Diffuse texture channel 0 + CHUNK_MAT_TEXTURE = 0xA200, - // Contains opacity information for each texel - CHUNK_MAT_OPACMAP = 0xA210, + // Contains opacity information for each texel + CHUNK_MAT_OPACMAP = 0xA210, - // Contains a reflection map to be used to reflect - // the environment. This is partially supported. - CHUNK_MAT_REFLMAP = 0xA220, + // Contains a reflection map to be used to reflect + // the environment. This is partially supported. + CHUNK_MAT_REFLMAP = 0xA220, - // Self Illumination map (emissive colors) - CHUNK_MAT_SELFIMAP = 0xA33d, + // Self Illumination map (emissive colors) + CHUNK_MAT_SELFIMAP = 0xA33d, - // Bumpmap. Not specified whether it is a heightmap - // or a normal map. Assme it is a heightmap since - // artist normally prefer this format. - CHUNK_MAT_BUMPMAP = 0xA230, + // Bumpmap. Not specified whether it is a heightmap + // or a normal map. Assme it is a heightmap since + // artist normally prefer this format. + CHUNK_MAT_BUMPMAP = 0xA230, - // Specular map. Seems to influence the specular color - CHUNK_MAT_SPECMAP = 0xA204, + // Specular map. Seems to influence the specular color + CHUNK_MAT_SPECMAP = 0xA204, - // Holds shininess data. - CHUNK_MAT_MAT_SHINMAP = 0xA33C, + // Holds shininess data. + CHUNK_MAT_MAT_SHINMAP = 0xA33C, - // Scaling in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_USCALE = 0xA354, - CHUNK_MAT_MAP_VSCALE = 0xA356, + // Scaling in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_USCALE = 0xA354, + CHUNK_MAT_MAP_VSCALE = 0xA356, - // Translation in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_UOFFSET = 0xA358, - CHUNK_MAT_MAP_VOFFSET = 0xA35a, + // Translation in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_UOFFSET = 0xA358, + CHUNK_MAT_MAP_VOFFSET = 0xA35a, - // UV-coordinates rotation around the z-axis - // Assumed to be in radians. - CHUNK_MAT_MAP_ANG = 0xA35C, + // UV-coordinates rotation around the z-axis + // Assumed to be in radians. + CHUNK_MAT_MAP_ANG = 0xA35C, - // Tiling flags for 3DS files - CHUNK_MAT_MAP_TILING = 0xa351, + // Tiling flags for 3DS files + CHUNK_MAT_MAP_TILING = 0xa351, - // Specifies the file name of a texture - CHUNK_MAPFILE = 0xA300, + // Specifies the file name of a texture + CHUNK_MAPFILE = 0xA300, - // Specifies whether a materail requires two-sided rendering - CHUNK_MAT_TWO_SIDE = 0xA081, + // Specifies whether a materail requires two-sided rendering + CHUNK_MAT_TWO_SIDE = 0xA081, // ******************************************************************** // Main keyframer chunk. Contains translation/rotation/scaling data - CHUNK_KEYFRAMER = 0xB000, + CHUNK_KEYFRAMER = 0xB000, // Supported sub chunks - CHUNK_TRACKINFO = 0xB002, - CHUNK_TRACKOBJNAME = 0xB010, - CHUNK_TRACKDUMMYOBJNAME = 0xB011, - CHUNK_TRACKPIVOT = 0xB013, - CHUNK_TRACKPOS = 0xB020, - CHUNK_TRACKROTATE = 0xB021, - CHUNK_TRACKSCALE = 0xB022, + CHUNK_TRACKINFO = 0xB002, + CHUNK_TRACKOBJNAME = 0xB010, + CHUNK_TRACKDUMMYOBJNAME = 0xB011, + CHUNK_TRACKPIVOT = 0xB013, + CHUNK_TRACKPOS = 0xB020, + CHUNK_TRACKROTATE = 0xB021, + CHUNK_TRACKSCALE = 0xB022, // ******************************************************************** // Keyframes for various other stuff in the file // Partially ignored - CHUNK_AMBIENTKEY = 0xB001, - CHUNK_TRACKMORPH = 0xB026, - CHUNK_TRACKHIDE = 0xB029, - CHUNK_OBJNUMBER = 0xB030, - CHUNK_TRACKCAMERA = 0xB003, - CHUNK_TRACKFOV = 0xB023, - CHUNK_TRACKROLL = 0xB024, - CHUNK_TRACKCAMTGT = 0xB004, - CHUNK_TRACKLIGHT = 0xB005, - CHUNK_TRACKLIGTGT = 0xB006, - CHUNK_TRACKSPOTL = 0xB007, - CHUNK_FRAMES = 0xB008, + CHUNK_AMBIENTKEY = 0xB001, + CHUNK_TRACKMORPH = 0xB026, + CHUNK_TRACKHIDE = 0xB029, + CHUNK_OBJNUMBER = 0xB030, + CHUNK_TRACKCAMERA = 0xB003, + CHUNK_TRACKFOV = 0xB023, + CHUNK_TRACKROLL = 0xB024, + CHUNK_TRACKCAMTGT = 0xB004, + CHUNK_TRACKLIGHT = 0xB005, + CHUNK_TRACKLIGTGT = 0xB006, + CHUNK_TRACKSPOTL = 0xB007, + CHUNK_FRAMES = 0xB008, // ******************************************************************** // light sub-chunks - CHUNK_DL_OFF = 0x4620, - CHUNK_DL_OUTER_RANGE = 0x465A, - CHUNK_DL_INNER_RANGE = 0x4659, - CHUNK_DL_MULTIPLIER = 0x465B, - CHUNK_DL_EXCLUDE = 0x4654, - CHUNK_DL_ATTENUATE = 0x4625, - CHUNK_DL_SPOTLIGHT = 0x4610, + CHUNK_DL_OFF = 0x4620, + CHUNK_DL_OUTER_RANGE = 0x465A, + CHUNK_DL_INNER_RANGE = 0x4659, + CHUNK_DL_MULTIPLIER = 0x465B, + CHUNK_DL_EXCLUDE = 0x4654, + CHUNK_DL_ATTENUATE = 0x4625, + CHUNK_DL_SPOTLIGHT = 0x4610, // camera sub-chunks - CHUNK_CAM_RANGES = 0x4720 + CHUNK_CAM_RANGES = 0x4720 }; }; // --------------------------------------------------------------------------- /** Helper structure representing a 3ds mesh face */ -struct Face : public FaceWithSmoothingGroup -{ +struct Face : public FaceWithSmoothingGroup { }; +#ifdef _WIN32 +#pragma warning(disable : 4315) +#endif + // --------------------------------------------------------------------------- /** Helper structure representing a texture */ struct Texture { //! Default constructor Texture() AI_NO_EXCEPT - : mOffsetU (0.0) - , mOffsetV (0.0) - , mScaleU (1.0) - , mScaleV (1.0) - , mRotation (0.0) - , mMapMode (aiTextureMapMode_Wrap) - , bPrivate() - , iUVSrc (0) { + : mTextureBlend(0.0f), + mMapName(), + mOffsetU(0.0), + mOffsetV(0.0), + mScaleU(1.0), + mScaleV(1.0), + mRotation(0.0), + mMapMode(aiTextureMapMode_Wrap), + bPrivate(), + iUVSrc(0) { mTextureBlend = get_qnan(); } + Texture(const Texture &other) : + mTextureBlend(other.mTextureBlend), + mMapName(other.mMapName), + mOffsetU(other.mOffsetU), + mOffsetV(other.mOffsetV), + mScaleU(other.mScaleU), + mScaleV(other.mScaleV), + mRotation(other.mRotation), + mMapMode(other.mMapMode), + bPrivate(other.bPrivate), + iUVSrc(other.iUVSrc) { + // empty + } + + Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)), + mMapName(std::move(other.mMapName)), + mOffsetU(std::move(other.mOffsetU)), + mOffsetV(std::move(other.mOffsetV)), + mScaleU(std::move(other.mScaleU)), + mScaleV(std::move(other.mScaleV)), + mRotation(std::move(other.mRotation)), + mMapMode(std::move(other.mMapMode)), + bPrivate(std::move(other.bPrivate)), + iUVSrc(std::move(other.iUVSrc)) { + // empty + } + + Texture &operator=(Texture &&other) AI_NO_EXCEPT { + if (this == &other) { + return *this; + } + + mTextureBlend = std::move(other.mTextureBlend); + mMapName = std::move(other.mMapName); + mOffsetU = std::move(other.mOffsetU); + mOffsetV = std::move(other.mOffsetV); + mScaleU = std::move(other.mScaleU); + mScaleV = std::move(other.mScaleV); + mRotation = std::move(other.mRotation); + mMapMode = std::move(other.mMapMode); + bPrivate = std::move(other.bPrivate); + iUVSrc = std::move(other.iUVSrc); + + return *this; + } + //! Specifies the blend factor for the texture ai_real mTextureBlend; @@ -367,55 +414,81 @@ struct Texture { // --------------------------------------------------------------------------- /** Helper structure representing a 3ds material */ -struct Material -{ +struct Material { //! Default constructor has been deleted - Material() = delete; - + Material() : + mName(), + mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)), + mSpecularExponent(ai_real(0.0)), + mShininessStrength(ai_real(1.0)), + mShading(Discreet3DS::Gouraud), + mTransparency(ai_real(1.0)), + mBumpHeight(ai_real(1.0)), + mTwoSided(false) { + // empty + } //! Constructor with explicit name - explicit Material(const std::string &name) - : mName(name) - , mDiffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black - , mSpecularExponent ( ai_real( 0.0 ) ) - , mShininessStrength ( ai_real( 1.0 ) ) - , mShading(Discreet3DS::Gouraud) - , mTransparency ( ai_real( 1.0 ) ) - , mBumpHeight ( ai_real( 1.0 ) ) - , mTwoSided (false) - { + explicit Material(const std::string &name) : + mName(name), + mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)), + mSpecularExponent(ai_real(0.0)), + mShininessStrength(ai_real(1.0)), + mShading(Discreet3DS::Gouraud), + mTransparency(ai_real(1.0)), + mBumpHeight(ai_real(1.0)), + mTwoSided(false) { + // empty } + 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 - Material(const Material &other) = default; - Material &operator=(const Material &other) = default; - + } //! 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 { if (this == &other) { return *this; @@ -444,9 +517,9 @@ struct Material return *this; } - - virtual ~Material() {} - + virtual ~Material() { + // empty + } //! Name of the material std::string mName; @@ -491,18 +564,15 @@ struct Material // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file mesh */ -struct Mesh : public MeshWithSmoothingGroups -{ +struct Mesh : public MeshWithSmoothingGroups { //! Default constructor has been deleted Mesh() = delete; //! Constructor with explicit name - explicit Mesh(const std::string &name) - : mName(name) - { + explicit Mesh(const std::string &name) : + mName(name) { } - //! Name of the mesh std::string mName; @@ -519,62 +589,48 @@ struct Mesh : public MeshWithSmoothingGroups // --------------------------------------------------------------------------- /** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the C-API, so it would be difficult to make them a template. */ -struct aiFloatKey -{ - double mTime; ///< The time of this key - ai_real mValue; ///< The value of this key +struct aiFloatKey { + double mTime; ///< The time of this key + ai_real mValue; ///< The value of this key #ifdef __cplusplus // time is not compared - bool operator == (const aiFloatKey& o) const - {return o.mValue == this->mValue;} + bool operator==(const aiFloatKey &o) const { return o.mValue == this->mValue; } - bool operator != (const aiFloatKey& o) const - {return o.mValue != this->mValue;} + bool operator!=(const aiFloatKey &o) const { return o.mValue != this->mValue; } // Only time is compared. This operator is defined // for use with std::sort - bool operator < (const aiFloatKey& o) const - {return mTime < o.mTime;} + bool operator<(const aiFloatKey &o) const { return mTime < o.mTime; } - bool operator > (const aiFloatKey& o) const - {return mTime > o.mTime;} + bool operator>(const aiFloatKey &o) const { return mTime > o.mTime; } #endif }; // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file node */ -struct Node -{ +struct Node { Node() = delete; - explicit Node(const std::string &name) - : mParent(NULL) - , mName(name) - , mInstanceNumber(0) - , mHierarchyPos (0) - , mHierarchyIndex (0) - , mInstanceCount (1) - { - aRotationKeys.reserve (20); - aPositionKeys.reserve (20); - aScalingKeys.reserve (20); + explicit Node(const std::string &name) : + mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) { + aRotationKeys.reserve(20); + aPositionKeys.reserve(20); + aScalingKeys.reserve(20); } - - ~Node() - { - for (unsigned int i = 0; i < mChildren.size();++i) + ~Node() { + for (unsigned int i = 0; i < mChildren.size(); ++i) delete mChildren[i]; } //! Pointer to the parent node - Node* mParent; + Node *mParent; //! Holds all child nodes - std::vector mChildren; + std::vector mChildren; //! Name of the node std::string mName; @@ -600,13 +656,12 @@ struct Node //! Scaling keys loaded from the file std::vector aScalingKeys; - // For target lights (spot lights and directional lights): // The position of the target - std::vector< aiVectorKey > aTargetPositionKeys; + std::vector aTargetPositionKeys; // For cameras: the camera roll angle - std::vector< aiFloatKey > aCameraRollKeys; + std::vector aCameraRollKeys; //! Pivot position loaded from the file aiVector3D vPivot; @@ -616,8 +671,7 @@ struct Node //! Add a child node, setup the right parent node for it //! \param pc Node to be 'adopted' - inline Node& push_back(Node* pc) - { + inline Node &push_back(Node *pc) { mChildren.push_back(pc); pc->mParent = this; return *this; @@ -625,8 +679,7 @@ struct Node }; // --------------------------------------------------------------------------- /** Helper structure analogue to aiScene */ -struct Scene -{ +struct Scene { //! List of all materials loaded //! NOTE: 3ds references materials globally std::vector mMaterials; @@ -635,17 +688,16 @@ struct Scene std::vector mMeshes; //! List of all cameras loaded - std::vector mCameras; + std::vector mCameras; //! List of all lights loaded - std::vector mLights; + std::vector mLights; //! Pointer to the root node of the scene // --- moved to main class // Node* pcRootNode; }; - } // end of namespace D3DS } // end of namespace Assimp 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 3e8e08967..e1a6d0f89 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,37 +122,34 @@ 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 stream(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 (stream.GetRemainingSize() < 16) { + if (theStream.GetRemainingSize() < 16) { throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); } - this->stream = &stream; + this->stream = &theStream; // Allocate our temporary 3DS representation D3DS::Scene _scene; @@ -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) { + 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,49 +540,49 @@ 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) -{ - if (root->mName == 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) { - D3DS::Node* nd; - if (( nd = FindNode(*it,name))) - return nd; } - return NULL; + + for (std::vector::iterator it = root->mChildren.begin(); it != root->mChildren.end(); ++it) { + D3DS::Node *nd = FindNode(*it, name); + if (nullptr != nd) { + return nd; + } + } + + return nullptr; } // ------------------------------------------------------------------------------------------------ // 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) { @@ -652,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; @@ -726,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; } @@ -739,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; } @@ -751,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 @@ -790,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 @@ -832,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(); @@ -878,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) @@ -888,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(); @@ -931,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(); @@ -943,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(); @@ -1043,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(); @@ -1078,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 @@ -1186,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: @@ -1252,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: @@ -1283,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; } @@ -1298,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; } @@ -1317,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) @@ -1332,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(); @@ -1357,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); @@ -1372,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; } @@ -1389,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: @@ -1413,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; @@ -1422,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 100% rename from code/3MF/3MFXmlTags.h rename to code/AssetLib/3MF/3MFXmlTags.h 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 9d71a54f2..5b85d275b 100644 --- a/code/3MF/D3MFExporter.cpp +++ b/code/AssetLib/3MF/D3MFExporter.cpp @@ -44,81 +44,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 +119,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 +138,7 @@ bool D3MFExporter::exportContentTypes() { mContentOutput << std::endl; mContentOutput << ""; mContentOutput << std::endl; - exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE ); + exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE); return true; } @@ -157,20 +150,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" ); + writeRelInfoToFile("_rels", ".rels"); mRelOutput.flush(); return true; @@ -181,8 +174,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 +185,6 @@ bool D3MFExporter::export3DModel() { writeObjects(); - mModelOutput << ""; mModelOutput << std::endl; writeBuild(); @@ -203,36 +195,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" ); + writeModelToArchive("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 +233,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( color.r ); - hexDiffuseColor += tmp; - tmp = DecimalToHexa( color.g ); - hexDiffuseColor += tmp; - tmp = DecimalToHexa( color.b ); - hexDiffuseColor += tmp; - tmp = DecimalToHexa( 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,54 +350,53 @@ 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." ); +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() ); + zip_entry_open(m_zipArchive, entry.c_str()); - const std::string &exportTxt( mContentOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); + const std::string &exportTxt(mContentOutput.str()); + zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - zip_entry_close( m_zipArchive ); + zip_entry_close(m_zipArchive); } -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::writeModelToArchive(const std::string &folder, const std::string &modelName) { + if (nullptr == m_zipArchive) { + throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); } const std::string entry = folder + "/" + modelName; - zip_entry_open( m_zipArchive, entry.c_str() ); + zip_entry_open(m_zipArchive, entry.c_str()); - const std::string &exportTxt( mModelOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); + const std::string &exportTxt(mModelOutput.str()); + zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - zip_entry_close( m_zipArchive ); + zip_entry_close(m_zipArchive); } -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::writeRelInfoToFile(const std::string &folder, const std::string &relName) { + if (nullptr == m_zipArchive) { + throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); } const std::string entry = folder + "/" + relName; - zip_entry_open( m_zipArchive, entry.c_str() ); + zip_entry_open(m_zipArchive, entry.c_str()); - const std::string &exportTxt( mRelOutput.str() ); - zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() ); + const std::string &exportTxt(mRelOutput.str()); + zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - zip_entry_close( m_zipArchive ); + zip_entry_close(m_zipArchive); } - } // Namespace D3MF } // Namespace Assimp diff --git a/code/3MF/D3MFExporter.h b/code/AssetLib/3MF/D3MFExporter.h similarity index 100% rename from code/3MF/D3MFExporter.h rename to code/AssetLib/3MF/D3MFExporter.h diff --git a/code/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp similarity index 58% rename from code/3MF/D3MFImporter.cpp rename to code/AssetLib/3MF/D3MFImporter.cpp index 2f30c4fc0..9fc9a653d 100644 --- a/code/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -44,24 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "D3MFImporter.h" -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include "D3MFOpcPackage.h" -#include #include "3MFXmlTags.h" +#include "D3MFOpcPackage.h" #include +#include #include @@ -70,90 +70,90 @@ namespace D3MF { class XmlSerializer { public: - using MatArray = std::vector; + using MatArray = std::vector; using MatId2MatArray = std::map>; - XmlSerializer(XmlReader* xmlReader) - : mMeshes() - , mMatArray() - , mActiveMatGroup( 99999999 ) - , mMatId2MatArray() - , xmlReader(xmlReader){ - // empty + XmlSerializer(XmlReader *xmlReader) : + mMeshes(), + mMatArray(), + mActiveMatGroup(99999999), + mMatId2MatArray(), + xmlReader(xmlReader) { + // empty } ~XmlSerializer() { // empty } - void ImportXml(aiScene* scene) { - if ( nullptr == scene ) { + void ImportXml(aiScene *scene) { + if (nullptr == scene) { return; } scene->mRootNode = new aiNode(); - std::vector children; + std::vector children; std::string nodeName; - while(ReadToEndElement(D3MF::XmlTag::model)) { + while (ReadToEndElement(D3MF::XmlTag::model)) { nodeName = xmlReader->getNodeName(); - if( nodeName == D3MF::XmlTag::object) { + if (nodeName == D3MF::XmlTag::object) { children.push_back(ReadObject(scene)); - } else if( nodeName == D3MF::XmlTag::build) { - // - } else if ( nodeName == D3MF::XmlTag::basematerials ) { + } else if (nodeName == D3MF::XmlTag::build) { + // + } else if (nodeName == D3MF::XmlTag::basematerials) { ReadBaseMaterials(); - } else if ( nodeName == D3MF::XmlTag::meta ) { + } else if (nodeName == D3MF::XmlTag::meta) { ReadMetadata(); } } - if ( scene->mRootNode->mName.length == 0 ) { - scene->mRootNode->mName.Set( "3MF" ); + 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 ); + 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); + 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 ); + 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](); + scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren](); std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); } private: - aiNode* ReadObject(aiScene* scene) { + aiNode *ReadObject(aiScene *scene) { std::unique_ptr node(new aiNode()); std::vector meshIds; - const char *attrib( nullptr ); + const char *attrib(nullptr); std::string name, type; - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() ); - if ( nullptr != attrib ) { + attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str()); + if (nullptr != attrib) { name = attrib; } - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() ); - if ( nullptr != attrib ) { + attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str()); + if (nullptr != attrib) { type = attrib; } @@ -162,8 +162,8 @@ private: size_t meshIdx = mMeshes.size(); - while(ReadToEndElement(D3MF::XmlTag::object)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) { + while (ReadToEndElement(D3MF::XmlTag::object)) { + if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) { auto mesh = ReadMesh(); mesh->mName.Set(name); @@ -183,11 +183,11 @@ private: } aiMesh *ReadMesh() { - aiMesh* mesh = new aiMesh(); - while(ReadToEndElement(D3MF::XmlTag::mesh)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) { + aiMesh *mesh = new aiMesh(); + while (ReadToEndElement(D3MF::XmlTag::mesh)) { + if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) { ImportVertices(mesh); - } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) { + } else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) { ImportTriangles(mesh); } } @@ -196,24 +196,24 @@ private: } void ReadMetadata() { - const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() ); + const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str()); xmlReader->read(); const std::string value = xmlReader->getNodeData(); - if ( name.empty() ) { + if (name.empty()) { return; } MetaEntry entry; entry.name = name; entry.value = value; - mMetaData.push_back( entry ); + mMetaData.push_back(entry); } - void ImportVertices(aiMesh* mesh) { + void ImportVertices(aiMesh *mesh) { std::vector vertices; - while(ReadToEndElement(D3MF::XmlTag::vertices)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) { + while (ReadToEndElement(D3MF::XmlTag::vertices)) { + if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) { vertices.push_back(ReadVertex()); } } @@ -233,20 +233,20 @@ private: return vertex; } - void ImportTriangles(aiMesh* mesh) { - std::vector faces; + 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; - } - } - } + 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]; @@ -269,117 +269,115 @@ private: 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 ) { + 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 ) { + MatId2MatArray::const_iterator it(mMatId2MatArray.find(id)); + if (mMatId2MatArray.end() == it) { MatIdArray.clear(); - mMatId2MatArray[ id ] = MatIdArray; + mMatId2MatArray[id] = MatIdArray; } else { MatIdArray = it->second; } } - MatIdArray.push_back( static_cast( newMatIdx ) ); - mMatId2MatArray[ mActiveMatGroup ] = MatIdArray; + MatIdArray.push_back(static_cast(newMatIdx)); + mMatId2MatArray[mActiveMatGroup] = MatIdArray; } - while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) { - mMatArray.push_back( readMaterialDef() ); + while (ReadToEndElement(D3MF::XmlTag::basematerials)) { + mMatArray.push_back(readMaterialDef()); } } - bool parseColor( const char *color, aiColor4D &diffuse ) { - if ( nullptr == color ) { + 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) { + const size_t len(strlen(color)); + if (9 != len && 7 != len) { return false; } - const char *buf( color ); - if ( '#' != *buf ) { + const char *buf(color); + if ('#' != *buf) { return false; } ++buf; - char comp[ 3 ] = { 0,0,'\0' }; + char comp[3] = { 0, 0, '\0' }; - comp[ 0 ] = *buf; + comp[0] = *buf; ++buf; - comp[ 1 ] = *buf; + comp[1] = *buf; ++buf; - diffuse.r = static_cast( strtol( comp, NULL, 16 ) ) / ai_real(255.0); + diffuse.r = static_cast(strtol(comp, NULL, 16)) / ai_real(255.0); + comp[0] = *buf; + ++buf; + comp[1] = *buf; + ++buf; + diffuse.g = static_cast(strtol(comp, NULL, 16)) / ai_real(255.0); - comp[ 0 ] = *buf; + comp[0] = *buf; ++buf; - comp[ 1 ] = *buf; + comp[1] = *buf; ++buf; - diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0); + diffuse.b = static_cast(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) + if (7 == len) return true; - comp[ 0 ] = *buf; + comp[0] = *buf; ++buf; - comp[ 1 ] = *buf; + comp[1] = *buf; ++buf; - diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0); + diffuse.a = static_cast(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() ); + 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 ); + 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() ); + 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 ) ); + std::string strId(to_string(mActiveMatGroup)); stdMatName += "id"; stdMatName += strId; stdMatName += "_"; - if ( nullptr != name ) { - stdMatName += std::string( name ); + if (nullptr != name) { + stdMatName += std::string(name); } else { stdMatName += "basemat"; } - matName.Set( stdMatName ); + matName.Set(stdMatName); mat = new aiMaterial; - mat->AddProperty( &matName, AI_MATKEY_NAME ); + mat->AddProperty(&matName, AI_MATKEY_NAME); - assignDiffuseColor( mat ); + assignDiffuseColor(mat); } return mat; } private: - bool ReadToStartElement(const std::string& startTag) { - while(xmlReader->read()) { - const std::string &nodeName( xmlReader->getNodeName() ); + 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) { @@ -390,9 +388,9 @@ private: return false; } - bool ReadToEndElement(const std::string& closeTag) { - while(xmlReader->read()) { - const std::string &nodeName( xmlReader->getNodeName() ); + 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) { @@ -410,11 +408,11 @@ private: std::string value; }; std::vector mMetaData; - std::vector mMeshes; + std::vector mMeshes; MatArray mMatArray; unsigned int mActiveMatGroup; MatId2MatArray mMatId2MatArray; - XmlReader* xmlReader; + XmlReader *xmlReader; }; } //namespace D3MF @@ -432,8 +430,8 @@ static const aiImporterDesc desc = { "3mf" }; -D3MFImporter::D3MFImporter() -: BaseImporter() { +D3MFImporter::D3MFImporter() : + BaseImporter() { // empty } @@ -442,17 +440,17 @@ D3MFImporter::~D3MFImporter() { } bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { - const std::string extension( GetExtension( filename ) ); - if(extension == desc.mFileExtensions ) { + const std::string extension(GetExtension(filename)); + if (extension == desc.mFileExtensions) { return true; - } else if ( !extension.length() || checkSig ) { - if ( nullptr == pIOHandler ) { + } else if (!extension.length() || checkSig) { + if (nullptr == pIOHandler) { return false; } - if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) { + if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { return false; } - D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); + D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); return opcPackage.validate(); } @@ -467,7 +465,7 @@ const aiImporterDesc *D3MFImporter::GetInfo() const { return &desc; } -void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) { +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())); 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 99% rename from code/3MF/D3MFOpcPackage.cpp rename to code/AssetLib/3MF/D3MFOpcPackage.cpp index 565790656..64300ed83 100644 --- a/code/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -147,7 +147,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) } } - ASSIMP_LOG_DEBUG(rootFile); + ASSIMP_LOG_VERBOSE_DEBUG(rootFile); mZipArchive->Close(fileStream); diff --git a/code/3MF/D3MFOpcPackage.h b/code/AssetLib/3MF/D3MFOpcPackage.h similarity index 100% rename from code/3MF/D3MFOpcPackage.h rename to code/AssetLib/3MF/D3MFOpcPackage.h diff --git a/code/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp similarity index 59% rename from code/AC/ACLoader.cpp rename to code/AssetLib/AC/ACLoader.cpp index ea533743f..2b8b7f087 100644 --- a/code/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -1,4 +1,3 @@ - /* --------------------------------------------------------------------------- Open Asset Import Library (assimp) @@ -6,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, @@ -44,25 +41,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the AC3D importer class */ - - #ifndef ASSIMP_BUILD_NO_AC_IMPORTER // internal headers #include "ACLoader.h" -#include -#include -#include #include "Common/Importer.h" #include -#include +#include +#include +#include +#include +#include #include -#include #include #include -#include +#include #include -#include +#include #include using namespace Assimp; @@ -82,116 +77,112 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // skip to the next token -#define AI_AC_SKIP_TO_NEXT_TOKEN() \ - if (!SkipSpaces(&buffer)) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \ - continue; \ +inline const char *AcSkipToNextToken(const char *buffer) { + if (!SkipSpaces(&buffer)) { + ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); } + return buffer; +} // ------------------------------------------------------------------------------------------------ // read a string (may be enclosed in double quotation marks). buffer must point to " -#define AI_AC_GET_STRING(out) \ - if (*buffer == '\0') { \ - throw DeadlyImportError("AC3D: Unexpected EOF in string"); \ - } \ - ++buffer; \ - const char* sz = buffer; \ - while ('\"' != *buffer) \ - { \ - if (IsLineEnd( *buffer )) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \ - out = "ERROR"; \ - break; \ - } \ - ++buffer; \ - } \ - if (IsLineEnd( *buffer ))continue; \ - out = std::string(sz,(unsigned int)(buffer-sz)); \ +inline const char *AcGetString(const char *buffer, std::string &out) { + if (*buffer == '\0') { + throw DeadlyImportError("AC3D: Unexpected EOF in string"); + } + ++buffer; + const char *sz = buffer; + while ('\"' != *buffer) { + if (IsLineEnd(*buffer)) { + ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); + out = "ERROR"; + break; + } + ++buffer; + } + if (IsLineEnd(*buffer)) { + return buffer; + } + out = std::string(sz, (unsigned int)(buffer - sz)); ++buffer; + return buffer; +} // ------------------------------------------------------------------------------------------------ // read 1 to n floats prefixed with an optional predefined identifier -#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - if (name_length) \ - { \ - if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \ - continue; \ - } \ - buffer += name_length+1; \ - } \ - for (unsigned int i = 0; i < num;++i) \ - { \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - buffer = fast_atoreal_move(buffer,((float*)out)[i]); \ +template +inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) { + buffer = AcSkipToNextToken(buffer); + if (0 != name_length) { + if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) { + ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string(name) + " was expected."); + return buffer; + } + buffer += name_length + 1; + } + for (unsigned int _i = 0; _i < num; ++_i) { + buffer = AcSkipToNextToken(buffer); + buffer = fast_atoreal_move(buffer, ((float *)out)[_i]); } + return buffer; +} // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -AC3DImporter::AC3DImporter() - : buffer(), - configSplitBFCull(), - configEvalSubdivision(), - mNumMeshes(), - mLights(), - lights(), - groups(), - polys(), - worlds() -{ +AC3DImporter::AC3DImporter() : + buffer(), + configSplitBFCull(), + configEvalSubdivision(), + mNumMeshes(), + mLights(), + mLightsCounter(0), + mGroupsCounter(0), + mPolysCounter(0), + mWorldsCounter(0) { // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -AC3DImporter::~AC3DImporter() -{ +AC3DImporter::~AC3DImporter() { // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ +bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { std::string extension = GetExtension(pFile); // fixme: are acc and ac3d *really* used? Some sources say they are - if(extension == "ac" || extension == "ac3d" || extension == "acc") { + if (extension == "ac" || extension == "ac3d" || extension == "acc") { return true; } if (!extension.length() || checkSig) { uint32_t token = AI_MAKE_MAGIC("AC3D"); - return CheckMagicToken(pIOHandler,pFile,&token,1,0); + return CheckMagicToken(pIOHandler, pFile, &token, 1, 0); } return false; } // ------------------------------------------------------------------------------------------------ // Loader meta information -const aiImporterDesc* AC3DImporter::GetInfo () const -{ +const aiImporterDesc *AC3DImporter::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Get a pointer to the next line from the file -bool AC3DImporter::GetNextLine( ) -{ +bool AC3DImporter::GetNextLine() { SkipLine(&buffer); return SkipSpaces(&buffer); } // ------------------------------------------------------------------------------------------------ // Parse an object section in an AC file -void AC3DImporter::LoadObjectSection(std::vector& objects) -{ - if (!TokenMatch(buffer,"OBJECT",6)) +void AC3DImporter::LoadObjectSection(std::vector &objects) { + if (!TokenMatch(buffer, "OBJECT", 6)) return; SkipSpaces(&buffer); @@ -199,147 +190,111 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) ++mNumMeshes; objects.push_back(Object()); - Object& obj = objects.back(); + Object &obj = objects.back(); - aiLight* light = NULL; - if (!ASSIMP_strincmp(buffer,"light",5)) - { + 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()); // Return a point light with no attenuation light->mType = aiLightSource_POINT; - light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); + light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f, 1.f, 1.f); light->mAttenuationConstant = 1.f; // Generate a default name for both the light source and the node // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. - light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast(mLights->size())-1); - obj.name = std::string( light->mName.data ); + 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)) - { + } else if (!ASSIMP_strincmp(buffer, "group", 5)) { obj.type = Object::Group; - } - else if (!ASSIMP_strincmp(buffer,"world",5)) - { + } else if (!ASSIMP_strincmp(buffer, "world", 5)) { obj.type = Object::World; - } - else obj.type = Object::Poly; - while (GetNextLine()) - { - if (TokenMatch(buffer,"kids",4)) - { + } else + obj.type = Object::Poly; + while (GetNextLine()) { + if (TokenMatch(buffer, "kids", 4)) { SkipSpaces(&buffer); - unsigned int num = strtoul10(buffer,&buffer); + unsigned int num = strtoul10(buffer, &buffer); GetNextLine(); - if (num) - { + if (num) { // load the children of this object recursively obj.children.reserve(num); for (unsigned int i = 0; i < num; ++i) LoadObjectSection(obj.children); } return; - } - else if (TokenMatch(buffer,"name",4)) - { + } else if (TokenMatch(buffer, "name", 4)) { SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.name); + buffer = AcGetString(buffer, obj.name); // If this is a light source, we'll also need to store // the name of the node in it. - if (light) - { + if (light) { light->mName.Set(obj.name); } - } - else if (TokenMatch(buffer,"texture",7)) - { + } else if (TokenMatch(buffer, "texture", 7)) { SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.texture); - } - else if (TokenMatch(buffer,"texrep",6)) - { + buffer = AcGetString(buffer, obj.texture); + } else if (TokenMatch(buffer, "texrep", 6)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat); if (!obj.texRepeat.x || !obj.texRepeat.y) - obj.texRepeat = aiVector2D (1.f,1.f); - } - else if (TokenMatch(buffer,"texoff",6)) - { + obj.texRepeat = aiVector2D(1.f, 1.f); + } else if (TokenMatch(buffer, "texoff", 6)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset); - } - else if (TokenMatch(buffer,"rot",3)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset); + } else if (TokenMatch(buffer, "rot", 3)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation); - } - else if (TokenMatch(buffer,"loc",3)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation); + } else if (TokenMatch(buffer, "loc", 3)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation); - } - else if (TokenMatch(buffer,"subdiv",6)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation); + } else if (TokenMatch(buffer, "subdiv", 6)) { SkipSpaces(&buffer); - obj.subDiv = strtoul10(buffer,&buffer); - } - else if (TokenMatch(buffer,"crease",6)) - { + obj.subDiv = strtoul10(buffer, &buffer); + } else if (TokenMatch(buffer, "crease", 6)) { SkipSpaces(&buffer); obj.crease = fast_atof(buffer); - } - else if (TokenMatch(buffer,"numvert",7)) - { + } else if (TokenMatch(buffer, "numvert", 7)) { SkipSpaces(&buffer); - unsigned int t = strtoul10(buffer,&buffer); + unsigned int t = strtoul10(buffer, &buffer); if (t >= AI_MAX_ALLOC(aiVector3D)) { throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); } obj.vertices.reserve(t); - for (unsigned int i = 0; i < t;++i) - { - if (!GetNextLine()) - { + for (unsigned int i = 0; i < t; ++i) { + if (!GetNextLine()) { ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet"); break; - } - else if (!IsNumeric(*buffer)) - { + } else if (!IsNumeric(*buffer)) { ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet"); --buffer; // make sure the line is processed a second time break; } obj.vertices.push_back(aiVector3D()); - aiVector3D& v = obj.vertices.back(); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); + aiVector3D &v = obj.vertices.back(); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x); } - } - else if (TokenMatch(buffer,"numsurf",7)) - { + } else if (TokenMatch(buffer, "numsurf", 7)) { SkipSpaces(&buffer); bool Q3DWorkAround = false; - const unsigned int t = strtoul10(buffer,&buffer); + const unsigned int t = strtoul10(buffer, &buffer); obj.surfaces.reserve(t); - for (unsigned int i = 0; i < t;++i) - { + for (unsigned int i = 0; i < t; ++i) { GetNextLine(); - if (!TokenMatch(buffer,"SURF",4)) - { + if (!TokenMatch(buffer, "SURF", 4)) { // FIX: this can occur for some files - Quick 3D for // example writes no surf chunks - if (!Q3DWorkAround) - { + 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 @@ -348,27 +303,20 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) } SkipSpaces(&buffer); obj.surfaces.push_back(Surface()); - Surface& surf = obj.surfaces.back(); + Surface &surf = obj.surfaces.back(); surf.flags = strtoul_cppstyle(buffer); - while (1) - { - if(!GetNextLine()) - { + while (1) { + if (!GetNextLine()) { throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete"); } - if (TokenMatch(buffer,"mat",3)) - { + if (TokenMatch(buffer, "mat", 3)) { SkipSpaces(&buffer); surf.mat = strtoul10(buffer); - } - else if (TokenMatch(buffer,"refs",4)) - { + } else if (TokenMatch(buffer, "refs", 4)) { // --- see fix notes above - if (Q3DWorkAround) - { - if (!surf.entries.empty()) - { + if (Q3DWorkAround) { + if (!surf.entries.empty()) { buffer -= 6; break; } @@ -380,24 +328,19 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) obj.numRefs += m; - for (unsigned int k = 0; k < m; ++k) - { - if(!GetNextLine()) - { + for (unsigned int k = 0; k < m; ++k) { + if (!GetNextLine()) { ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete"); break; } surf.entries.push_back(Surface::SurfaceEntry()); - Surface::SurfaceEntry& entry = surf.entries.back(); + Surface::SurfaceEntry &entry = surf.entries.back(); - entry.first = strtoul10(buffer,&buffer); + entry.first = strtoul10(buffer, &buffer); SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second); } - } - else - { - + } else { --buffer; // make sure the line is processed a second time break; } @@ -410,65 +353,58 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) // ------------------------------------------------------------------------------------------------ // Convert a material from AC3DImporter::Material to aiMaterial -void AC3DImporter::ConvertMaterial(const Object& object, - const Material& matSrc, - aiMaterial& matDest) -{ +void AC3DImporter::ConvertMaterial(const Object &object, + const Material &matSrc, + aiMaterial &matDest) { aiString s; - if (matSrc.name.length()) - { + if (matSrc.name.length()) { s.Set(matSrc.name); - matDest.AddProperty(&s,AI_MATKEY_NAME); + matDest.AddProperty(&s, AI_MATKEY_NAME); } - if (object.texture.length()) - { + if (object.texture.length()) { s.Set(object.texture); - matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); + matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); // UV transformation if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y || - object.texOffset.x || object.texOffset.y) - { + object.texOffset.x || object.texOffset.y) { aiUVTransform transform; transform.mScaling = object.texRepeat; transform.mTranslation = object.texOffset; - matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); + matDest.AddProperty(&transform, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); } } - matDest.AddProperty(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE); - matDest.AddProperty(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT); - matDest.AddProperty(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); - matDest.AddProperty(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); + matDest.AddProperty(&matSrc.rgb, 1, AI_MATKEY_COLOR_DIFFUSE); + matDest.AddProperty(&matSrc.amb, 1, AI_MATKEY_COLOR_AMBIENT); + matDest.AddProperty(&matSrc.emis, 1, AI_MATKEY_COLOR_EMISSIVE); + matDest.AddProperty(&matSrc.spec, 1, AI_MATKEY_COLOR_SPECULAR); - int n; - if (matSrc.shin) - { + int n = -1; + if (matSrc.shin) { n = aiShadingMode_Phong; - matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); + matDest.AddProperty(&matSrc.shin, 1, AI_MATKEY_SHININESS); + } else { + n = aiShadingMode_Gouraud; } - else n = aiShadingMode_Gouraud; - matDest.AddProperty(&n,1,AI_MATKEY_SHADING_MODEL); + matDest.AddProperty(&n, 1, AI_MATKEY_SHADING_MODEL); float f = 1.f - matSrc.trans; - matDest.AddProperty(&f,1,AI_MATKEY_OPACITY); + matDest.AddProperty(&f, 1, AI_MATKEY_OPACITY); } // ------------------------------------------------------------------------------------------------ // Converts the loaded data to the internal verbose representation -aiNode* AC3DImporter::ConvertObjectSection(Object& object, - std::vector& meshes, - std::vector& outMaterials, - const std::vector& materials, - aiNode* parent) -{ - aiNode* node = new aiNode(); +aiNode *AC3DImporter::ConvertObjectSection(Object &object, + std::vector &meshes, + std::vector &outMaterials, + const std::vector &materials, + aiNode *parent) { + aiNode *node = new aiNode(); node->mParent = parent; - if (object.vertices.size()) - { - if (!object.surfaces.size() || !object.numRefs) - { + if (object.vertices.size()) { + if (!object.surfaces.size() || !object.numRefs) { /* " An object with 7 vertices (no surfaces, no materials defined). This is a good way of getting point data into AC3D. The Vertex->create convex-surface/object can be used on these @@ -479,17 +415,16 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, */ ASSIMP_LOG_INFO("AC3D: No surfaces defined in object definition, " - "a point list is returned"); + "a point list is returned"); meshes.push_back(new aiMesh()); - aiMesh* mesh = meshes.back(); + aiMesh *mesh = meshes.back(); mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size(); - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; - aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + aiVector3D *verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts) - { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i, ++faces, ++verts) { *verts = object.vertices[i]; faces->mNumIndices = 1; faces->mIndices = new unsigned int[1]; @@ -502,65 +437,56 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, mesh->mMaterialIndex = 0; outMaterials.push_back(new aiMaterial()); ConvertMaterial(object, materials[0], *outMaterials.back()); - } - else - { + } else { // need to generate one or more meshes for this object. // find out how many different materials we have - typedef std::pair< unsigned int, unsigned int > IntPair; - typedef std::vector< IntPair > MatTable; - MatTable needMat(materials.size(),IntPair(0,0)); + typedef std::pair IntPair; + typedef std::vector MatTable; + MatTable needMat(materials.size(), IntPair(0, 0)); - std::vector::iterator it,end = object.surfaces.end(); - std::vector::iterator it2,end2; + std::vector::iterator it, end = object.surfaces.end(); + std::vector::iterator it2, end2; - for (it = object.surfaces.begin(); it != end; ++it) - { + for (it = object.surfaces.begin(); it != end; ++it) { unsigned int idx = (*it).mat; - if (idx >= needMat.size()) - { + if (idx >= needMat.size()) { ASSIMP_LOG_ERROR("AC3D: material index is out of range"); idx = 0; } - if ((*it).entries.empty()) - { + if ((*it).entries.empty()) { ASSIMP_LOG_WARN("AC3D: surface her zero vertex references"); } // validate all vertex indices to make sure we won't crash here - for (it2 = (*it).entries.begin(), - end2 = (*it).entries.end(); it2 != end2; ++it2) - { - if ((*it2).first >= object.vertices.size()) - { + for (it2 = (*it).entries.begin(), + end2 = (*it).entries.end(); + it2 != end2; ++it2) { + if ((*it2).first >= object.vertices.size()) { ASSIMP_LOG_WARN("AC3D: Invalid vertex reference"); (*it2).first = 0; } } - if (!needMat[idx].first)++node->mNumMeshes; + if (!needMat[idx].first) { + ++node->mNumMeshes; + } - switch ((*it).flags & 0xf) - { + 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; + 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; + 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) - { + if ((*it).flags & 0xf) { ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown"); (*it).flags &= ~(0xf); } @@ -571,20 +497,21 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, needMat[idx].second += (unsigned int)(*it).entries.size(); }; } - unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes]; + unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes]; unsigned int mat = 0; const size_t oldm = meshes.size(); for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end(); - cit != cend; ++cit, ++mat) - { - if (!(*cit).first)continue; + cit != cend; ++cit, ++mat) { + if (!(*cit).first) { + continue; + } // allocate a new aiMesh object *pip++ = (unsigned int)meshes.size(); - aiMesh* mesh = new aiMesh(); + aiMesh *mesh = new aiMesh(); meshes.push_back(mesh); - mesh->mMaterialIndex = (unsigned int)outMaterials.size(); + mesh->mMaterialIndex = static_cast(outMaterials.size()); outMaterials.push_back(new aiMaterial()); ConvertMaterial(object, materials[mat], *outMaterials.back()); @@ -595,7 +522,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) { throw DeadlyImportError("AC3D: Too many faces, would run out of memory"); } - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mNumVertices = (*cit).second; if (mesh->mNumVertices == 0) { @@ -603,35 +530,30 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) { throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); } - aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiVector3D *vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; unsigned int cur = 0; // allocate UV coordinates, but only if the texture name for the // surface is not empty - aiVector3D* uv = NULL; - if(object.texture.length()) - { + aiVector3D *uv = nullptr; + if (object.texture.length()) { uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; mesh->mNumUVComponents[0] = 2; } - for (it = object.surfaces.begin(); it != end; ++it) - { - if (mat == (*it).mat) - { - const Surface& src = *it; + for (it = object.surfaces.begin(); it != end; ++it) { + if (mat == (*it).mat) { + const Surface &src = *it; // closed polygon unsigned int type = (*it).flags & 0xf; - if (!type) - { - aiFace& face = *faces++; - if((face.mNumIndices = (unsigned int)src.entries.size())) - { + if (!type) { + aiFace &face = *faces++; + face.mNumIndices = (unsigned int)src.entries.size(); + if (0 != face.mNumIndices) { face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices) - { - const Surface::SurfaceEntry& entry = src.entries[i]; + for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) { + const Surface::SurfaceEntry &entry = src.entries[i]; face.mIndices[i] = cur++; // copy vertex positions @@ -640,28 +562,23 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } *vertices = object.vertices[entry.first] + object.translation; - // copy texture coordinates - if (uv) - { - uv->x = entry.second.x; - uv->y = entry.second.y; + if (uv) { + uv->x = entry.second.x; + uv->y = entry.second.y; ++uv; } } } - } - else - { + } else { - it2 = (*it).entries.begin(); + it2 = (*it).entries.begin(); // either a closed or an unclosed line unsigned int tmp = (unsigned int)(*it).entries.size(); - if (0x2 == type)--tmp; - for (unsigned int m = 0; m < tmp;++m) - { - aiFace& face = *faces++; + if (0x2 == type) --tmp; + for (unsigned int m = 0; m < tmp; ++m) { + aiFace &face = *faces++; face.mNumIndices = 2; face.mIndices = new unsigned int[2]; @@ -669,35 +586,31 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, face.mIndices[1] = cur++; // copy vertex positions - if (it2 == (*it).entries.end() ) { + if (it2 == (*it).entries.end()) { throw DeadlyImportError("AC3D: Bad line"); } ai_assert((*it2).first < object.vertices.size()); *vertices++ = object.vertices[(*it2).first]; // copy texture coordinates - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; + if (uv) { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; ++uv; } - - if (0x1 == type && tmp-1 == m) - { + if (0x1 == type && tmp - 1 == m) { // if this is a closed line repeat its beginning now - it2 = (*it).entries.begin(); - } - else ++it2; + it2 = (*it).entries.begin(); + } else + ++it2; // second point *vertices++ = object.vertices[(*it2).first]; - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; + if (uv) { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; ++uv; } } @@ -709,20 +622,18 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, // Now apply catmull clark subdivision if necessary. We split meshes into // materials which is not done by AC3D during smoothing, so we need to // collect all meshes using the same material group. - if (object.subDiv) { + if (object.subDiv) { if (configEvalSubdivision) { std::unique_ptr div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); - ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: "+object.name); + ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name); - std::vector cpy(meshes.size()-oldm,NULL); - div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); - std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm); + std::vector cpy(meshes.size() - oldm, NULL); + div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true); + std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm); // previous meshes are deleted vy Subdivide(). - } - else { - ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " - +object.name); + } else { + ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " + object.name); } } } @@ -730,48 +641,42 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, if (object.name.length()) node->mName.Set(object.name); - else - { + else { // generate a name depending on the type of the node - switch (object.type) - { + switch (object.type) { case Object::Group: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++); + 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",polys++); + 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",lights++); + 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",worlds++); + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++); break; } } - // setup the local transformation matrix of the object // compute the transformation offset to the parent node - node->mTransformation = aiMatrix4x4 ( object.rotation ); + node->mTransformation = aiMatrix4x4(object.rotation); - if (object.type == Object::Group || !object.numRefs) - { + if (object.type == Object::Group || !object.numRefs) { node->mTransformation.a4 = object.translation.x; node->mTransformation.b4 = object.translation.y; node->mTransformation.c4 = object.translation.z; } // add children to the object - if (object.children.size()) - { + if (object.children.size()) { node->mNumChildren = (unsigned int)object.children.size(); - node->mChildren = new aiNode*[node->mNumChildren]; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node); + node->mChildren = new aiNode *[node->mNumChildren]; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + node->mChildren[i] = ConvertObjectSection(object.children[i], meshes, outMaterials, materials, node); } } @@ -779,40 +684,39 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } // ------------------------------------------------------------------------------------------------ -void AC3DImporter::SetupProperties(const Importer* pImp) -{ - configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false; - configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false; +void AC3DImporter::SetupProperties(const Importer *pImp) { + configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL, 1) ? true : false; + configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION, 1) ? true : false; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void AC3DImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ - std::unique_ptr file( pIOHandler->Open( pFile, "rb")); +void AC3DImporter::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() == NULL) - 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 std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); + TextFileToBuffer(file.get(), mBuffer2); buffer = &mBuffer2[0]; mNumMeshes = 0; - lights = polys = worlds = groups = 0; + mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0; - if (::strncmp(buffer,"AC3D",4)) { + if (::strncmp(buffer, "AC3D", 4)) { throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); } // print the file format version to the console - unsigned int version = HexDigitToDecimal( buffer[4] ); + unsigned int version = HexDigitToDecimal(buffer[4]); char msg[3]; - ASSIMP_itoa10(msg,3,version); + ASSIMP_itoa10(msg, 3, version); ASSIMP_LOG_INFO_F("AC3D file format version: ", msg); std::vector materials; @@ -821,89 +725,84 @@ void AC3DImporter::InternReadFile( const std::string& pFile, std::vector rootObjects; rootObjects.reserve(5); - std::vector lights; - mLights = & lights; + std::vector lights; + mLights = &lights; - while (GetNextLine()) - { - if (TokenMatch(buffer,"MATERIAL",8)) - { + while (GetNextLine()) { + if (TokenMatch(buffer, "MATERIAL", 8)) { materials.push_back(Material()); - Material& mat = materials.back(); + Material &mat = materials.back(); // manually parse the material ... sscanf would use the buldin atof ... // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f - AI_AC_SKIP_TO_NEXT_TOKEN(); - if ('\"' == *buffer) - { - AI_AC_GET_STRING(mat.name); - AI_AC_SKIP_TO_NEXT_TOKEN(); + buffer = AcSkipToNextToken(buffer); + if ('\"' == *buffer) { + buffer = AcGetString(buffer, mat.name); + buffer = AcSkipToNextToken(buffer); } - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); + buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb); + buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb); + buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis); + buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec); + buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin); + buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans); } LoadObjectSection(rootObjects); } - if (rootObjects.empty() || !mNumMeshes) - { + if (rootObjects.empty() || !mNumMeshes) { throw DeadlyImportError("AC3D: No meshes have been loaded"); } - if (materials.empty()) - { + if (materials.empty()) { ASSIMP_LOG_WARN("AC3D: No material has been found"); materials.push_back(Material()); } - mNumMeshes += (mNumMeshes>>2u) + 1; - std::vector meshes; + mNumMeshes += (mNumMeshes >> 2u) + 1; + std::vector meshes; meshes.reserve(mNumMeshes); - std::vector omaterials; + std::vector omaterials; materials.reserve(mNumMeshes); // generate a dummy root if there are multiple objects on the top layer - Object* root; + Object *root; if (1 == rootObjects.size()) root = &rootObjects[0]; - else - { + else { root = new Object(); } // now convert the imported stuff to our output data structure - pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); - if (1 != rootObjects.size())delete root; + pScene->mRootNode = ConvertObjectSection(*root, meshes, omaterials, materials); + if (1 != rootObjects.size()) { + delete root; + } - if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) + if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) { pScene->mRootNode->mName.Set(""); + } // copy meshes - if (meshes.empty()) - { + if (meshes.empty()) { throw DeadlyImportError("An unknown error occurred during converting"); } pScene->mNumMeshes = (unsigned int)meshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); + pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; + ::memcpy(pScene->mMeshes, &meshes[0], pScene->mNumMeshes * sizeof(void *)); // copy materials pScene->mNumMaterials = (unsigned int)omaterials.size(); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); + pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; + ::memcpy(pScene->mMaterials, &omaterials[0], pScene->mNumMaterials * sizeof(void *)); // copy lights pScene->mNumLights = (unsigned int)lights.size(); - if (lights.size()) - { - pScene->mLights = new aiLight*[lights.size()]; - ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); + if (lights.size()) { + pScene->mLights = new aiLight *[lights.size()]; + ::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *)); } } diff --git a/code/AC/ACLoader.h b/code/AssetLib/AC/ACLoader.h similarity index 77% rename from code/AC/ACLoader.h rename to code/AssetLib/AC/ACLoader.h index 1fc654f3c..e330ddf1b 100644 --- a/code/AC/ACLoader.h +++ b/code/AssetLib/AC/ACLoader.h @@ -56,29 +56,20 @@ 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; @@ -103,43 +94,25 @@ 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; }; // 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; @@ -179,37 +152,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*/ @@ -220,7 +189,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. @@ -229,26 +198,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 @@ -265,10 +232,10 @@ private: unsigned int mNumMeshes; // current list of light sources - std::vector* mLights; + std::vector *mLights; // name counters - unsigned int lights, groups, polys, worlds; + unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter; }; } // end of namespace Assimp diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp new file mode 100644 index 000000000..3bb18b0ab --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -0,0 +1,672 @@ +/* +--------------------------------------------------------------------------- +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/AssetLib/AMF/AMFImporter.hpp similarity index 100% rename from code/AMF/AMFImporter.hpp rename to code/AssetLib/AMF/AMFImporter.hpp diff --git a/code/AssetLib/AMF/AMFImporter_Geometry.cpp b/code/AssetLib/AMF/AMFImporter_Geometry.cpp new file mode 100644 index 000000000..45be05df1 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Geometry.cpp @@ -0,0 +1,357 @@ +/* +--------------------------------------------------------------------------- +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/AssetLib/AMF/AMFImporter_Macro.hpp b/code/AssetLib/AMF/AMFImporter_Macro.hpp new file mode 100644 index 000000000..5877a62d2 --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Macro.hpp @@ -0,0 +1,166 @@ +/* +--------------------------------------------------------------------------- +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_Macro.hpp +/// \brief Useful macrodefines. +/// \date 2016 +/// \author smal.root@gmail.com + +#pragma once +#ifndef AMFIMPORTER_MACRO_HPP_INCLUDED +#define AMFIMPORTER_MACRO_HPP_INCLUDED + +/// \def MACRO_ATTRREAD_LOOPBEG +/// Begin of loop that read attributes values. +#define MACRO_ATTRREAD_LOOPBEG \ + for(int idx = 0, idx_end = mReader->getAttributeCount(); idx < idx_end; idx++) \ + { \ + std::string an(mReader->getAttributeName(idx)); + +/// \def MACRO_ATTRREAD_LOOPEND +/// End of loop that read attributes values. +#define MACRO_ATTRREAD_LOOPEND \ + Throw_IncorrectAttr(an); \ + } + +/// \def MACRO_ATTRREAD_LOOPEND_WSKIP +/// End of loop that read attributes values. Difference from \ref MACRO_ATTRREAD_LOOPEND in that: current macro skip unknown attributes, but +/// \ref MACRO_ATTRREAD_LOOPEND throw an exception. +#define MACRO_ATTRREAD_LOOPEND_WSKIP \ + continue; \ + } + +/// \def MACRO_ATTRREAD_CHECK_REF +/// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then +/// "continue" will called. +/// \param [in] pAttrName - attribute name. +/// \param [out] pVarName - output variable name. +/// \param [in] pFunction - function which read attribute value and write it to pVarName. +#define MACRO_ATTRREAD_CHECK_REF(pAttrName, pVarName, pFunction) \ + if(an == pAttrName) \ + { \ + pFunction(idx, pVarName); \ + continue; \ + } + +/// \def MACRO_ATTRREAD_CHECK_RET +/// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction. +/// If result was read then "continue" will called. +/// \param [in] pAttrName - attribute name. +/// \param [out] pVarName - output variable name. +/// \param [in] pFunction - function which read attribute value and write it to pVarName. +#define MACRO_ATTRREAD_CHECK_RET(pAttrName, pVarName, pFunction) \ + if(an == pAttrName) \ + { \ + pVarName = pFunction(idx); \ + continue; \ + } + +/// \def MACRO_NODECHECK_LOOPBEGIN(pNodeName) +/// Begin of loop of parsing child nodes. Do not add ';' at end. +/// \param [in] pNodeName - current node name. +#define MACRO_NODECHECK_LOOPBEGIN(pNodeName) \ + do { \ + bool close_found = false; \ + \ + while(mReader->read()) \ + { \ + if(mReader->getNodeType() == irr::io::EXN_ELEMENT) \ + { + +/// \def MACRO_NODECHECK_LOOPEND(pNodeName) +/// End of loop of parsing child nodes. +/// \param [in] pNodeName - current node name. +#define MACRO_NODECHECK_LOOPEND(pNodeName) \ + XML_CheckNode_SkipUnsupported(pNodeName); \ + }/* if(mReader->getNodeType() == irr::io::EXN_ELEMENT) */ \ + else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) \ + { \ + if(XML_CheckNode_NameEqual(pNodeName)) \ + { \ + close_found = true; \ + \ + break; \ + } \ + }/* else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) */ \ + }/* while(mReader->read()) */ \ + \ + if(!close_found) Throw_CloseNotFound(pNodeName); \ + \ + } while(false) + +/// \def MACRO_NODECHECK_READCOMP_F +/// Check current node name and if it equal to requested then read value. Result write to output variable of type "float". +/// If result was read then "continue" will called. Also check if node data already read then raise exception. +/// \param [in] pNodeName - node name. +/// \param [in, out] pReadFlag - read flag. +/// \param [out] pVarName - output variable name. +#define MACRO_NODECHECK_READCOMP_F(pNodeName, pReadFlag, pVarName) \ + if(XML_CheckNode_NameEqual(pNodeName)) \ + { \ + /* Check if field already read before. */ \ + if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \ + /* Read color component and assign it to object. */ \ + pVarName = XML_ReadNode_GetVal_AsFloat(); \ + pReadFlag = true; \ + continue; \ + } + +/// \def MACRO_NODECHECK_READCOMP_U32 +/// Check current node name and if it equal to requested then read value. Result write to output variable of type "uint32_t". +/// If result was read then "continue" will called. Also check if node data already read then raise exception. +/// \param [in] pNodeName - node name. +/// \param [in, out] pReadFlag - read flag. +/// \param [out] pVarName - output variable name. +#define MACRO_NODECHECK_READCOMP_U32(pNodeName, pReadFlag, pVarName) \ + if(XML_CheckNode_NameEqual(pNodeName)) \ + { \ + /* Check if field already read before. */ \ + if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \ + /* Read color component and assign it to object. */ \ + pVarName = XML_ReadNode_GetVal_AsU32(); \ + pReadFlag = true; \ + continue; \ + } + +#endif // AMFIMPORTER_MACRO_HPP_INCLUDED diff --git a/code/AMF/AMFImporter_Material.cpp b/code/AssetLib/AMF/AMFImporter_Material.cpp similarity index 99% rename from code/AMF/AMFImporter_Material.cpp rename to code/AssetLib/AMF/AMFImporter_Material.cpp index 1ed33d070..0d0e756a1 100644 --- a/code/AMF/AMFImporter_Material.cpp +++ b/code/AssetLib/AMF/AMFImporter_Material.cpp @@ -1,4 +1,4 @@ -/* +/* --------------------------------------------------------------------------- Open Asset Import Library (assimp) --------------------------------------------------------------------------- diff --git a/code/AMF/AMFImporter_Node.hpp b/code/AssetLib/AMF/AMFImporter_Node.hpp similarity index 99% rename from code/AMF/AMFImporter_Node.hpp rename to code/AssetLib/AMF/AMFImporter_Node.hpp index 8808730ee..e399c0afd 100644 --- a/code/AMF/AMFImporter_Node.hpp +++ b/code/AssetLib/AMF/AMFImporter_Node.hpp @@ -1,4 +1,4 @@ -/* +/* --------------------------------------------------------------------------- Open Asset Import Library (assimp) --------------------------------------------------------------------------- diff --git a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp new file mode 100644 index 000000000..596b0235c --- /dev/null +++ b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp @@ -0,0 +1,872 @@ +/* +--------------------------------------------------------------------------- +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/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..a27767229 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..09ad2ab1d 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"); + "but the node is neither a camera nor a spot light"); anim = NULL; - } - else anim = &mesh.mTargetAnim; + } 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,40 +1776,34 @@ 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) -{ +void Parser::ParseLV4MeshLongTriple(unsigned int *apOut) { ai_assert(NULL != 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) -{ +void Parser::ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut) { ai_assert(NULL != apOut); // parse the index @@ -2105,8 +1813,7 @@ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut ParseLV4MeshLongTriple(apOut); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut) -{ +void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) { ai_assert(NULL != apOut); // parse the index @@ -2116,19 +1823,16 @@ void Parser::ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut) ParseLV4MeshFloatTriple(apOut); } // ------------------------------------------------------------------------------------------------ -void Parser::ParseLV4MeshFloatTriple(ai_real* apOut) -{ +void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) { ai_assert(NULL != 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 98% rename from code/ASE/ASEParser.h rename to code/AssetLib/ASE/ASEParser.h index e55949f99..c94c8e3aa 100644 --- a/code/ASE/ASEParser.h +++ b/code/AssetLib/ASE/ASEParser.h @@ -57,7 +57,7 @@ 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 { @@ -80,7 +80,18 @@ struct Material : public D3DS::Material } Material(const Material &other) = default; - Material &operator=(const Material &other) = default; + + Material &operator=(const Material &other) { + if (this == &other) { + return *this; + } + + avSubMaterials = other.avSubMaterials; + pcInstance = other.pcInstance; + bNeed = other.bNeed; + + return *this; + } //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it @@ -94,12 +105,12 @@ struct Material : public D3DS::Material } - Material &operator=(Material &&other) AI_NO_EXCEPT { + Material &operator=( Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; } - D3DS::Material::operator=(std::move(other)); + //D3DS::Material::operator=(std::move(other)); avSubMaterials = std::move(other.avSubMaterials); pcInstance = std::move(other.pcInstance); diff --git a/code/AssetLib/Assbin/AssbinExporter.cpp b/code/AssetLib/Assbin/AssbinExporter.cpp new file mode 100644 index 000000000..e86a6526d --- /dev/null +++ b/code/AssetLib/Assbin/AssbinExporter.cpp @@ -0,0 +1,68 @@ +/* +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 AssbinExporter.cpp + * ASSBIN exporter main code + */ + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER + +#include "AssbinFileWriter.h" + +#include +#include +#include + +namespace Assimp { + +void ExportSceneAssbin(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { + DumpSceneToAssbin( + pFile, + "\0", // no command(s). + pIOSystem, + pScene, + false, // shortened? + false); // compressed? +} +} // end of namespace Assimp + +#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT 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/AssetLib/Assbin/AssbinFileWriter.cpp b/code/AssetLib/Assbin/AssbinFileWriter.cpp new file mode 100644 index 000000000..431be4d3a --- /dev/null +++ b/code/AssetLib/Assbin/AssbinFileWriter.cpp @@ -0,0 +1,832 @@ +/* +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 AssbinFileWriter.cpp + * @brief Implementation of Assbin file writer. + */ + +#include "AssbinFileWriter.h" + +#include "Common/assbin_chunks.h" +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +#include +#else +#include "../contrib/zlib/zlib.h" +#endif + +#include + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4706) +#endif // _WIN32 + +namespace Assimp { + +template +size_t Write(IOStream *stream, const T &v) { + return stream->Write(&v, sizeof(T), 1); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiString +template <> +inline size_t Write(IOStream *stream, const aiString &s) { + const size_t s2 = (uint32_t)s.length; + stream->Write(&s, 4, 1); + stream->Write(s.data, s2, 1); + + return s2 + 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint32_t +template <> +inline size_t Write(IOStream *stream, const unsigned int &w) { + const uint32_t t = (uint32_t)w; + if (w > t) { + // this shouldn't happen, integers in Assimp data structures never exceed 2^32 + throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); + } + + stream->Write(&t, 4, 1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint16_t +template <> +inline size_t Write(IOStream *stream, const uint16_t &w) { + static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t)==2"); + stream->Write(&w, 2, 1); + + return 2; +} + +// ----------------------------------------------------------------------------------- +// Serialize a float +template <> +inline size_t Write(IOStream *stream, const float &f) { + static_assert(sizeof(float) == 4, "sizeof(float)==4"); + stream->Write(&f, 4, 1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize a double +template <> +inline size_t Write(IOStream *stream, const double &f) { + static_assert(sizeof(double) == 8, "sizeof(double)==8"); + stream->Write(&f, 8, 1); + + return 8; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vec3 +template <> +inline size_t Write(IOStream *stream, const aiVector3D &v) { + size_t t = Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline size_t Write(IOStream *stream, const aiColor3D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline size_t Write(IOStream *stream, const aiColor4D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); + t += Write(stream, v.a); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a quaternion +template <> +inline size_t Write(IOStream *stream, const aiQuaternion &v) { + size_t t = Write(stream, v.w); + t += Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); + ai_assert(t == 16); + + return 16; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vertex weight +template <> +inline size_t Write(IOStream *stream, const aiVertexWeight &v) { + size_t t = Write(stream, v.mVertexId); + + return t + Write(stream, v.mWeight); +} + +// ----------------------------------------------------------------------------------- +// Serialize a mat4x4 +template <> +inline size_t Write(IOStream *stream, const aiMatrix4x4 &m) { + for (unsigned int i = 0; i < 4; ++i) { + for (unsigned int i2 = 0; i2 < 4; ++i2) { + Write(stream, m[i][i2]); + } + } + + return 64; +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiVectorKey +template <> +inline size_t Write(IOStream *stream, const aiVectorKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiQuatKey +template <> +inline size_t Write(IOStream *stream, const aiQuatKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); +} + +template +inline size_t WriteBounds(IOStream *stream, const T *in, unsigned int size) { + T minc, maxc; + ArrayBounds(in, size, minc, maxc); + + const size_t t = Write(stream, minc); + return t + Write(stream, maxc); +} + +// We use this to write out non-byte arrays so that we write using the specializations. +// This way we avoid writing out extra bytes that potentially come from struct alignment. +template +inline size_t WriteArray(IOStream *stream, const T *in, unsigned int size) { + size_t n = 0; + for (unsigned int i = 0; i < size; i++) + n += Write(stream, in[i]); + + return n; +} + +// ---------------------------------------------------------------------------------- +/** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ +class AssbinChunkWriter : public IOStream { +private: + uint8_t *buffer; + uint32_t magic; + IOStream *container; + size_t cur_size, cursor, initial; + +private: + // ------------------------------------------------------------------- + void Grow(size_t need = 0) { + size_t new_size = std::max(initial, std::max(need, cur_size + (cur_size >> 1))); + + const uint8_t *const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer, old, cur_size); + delete[] old; + } + + cur_size = new_size; + } + +public: + AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) : + buffer(nullptr), + magic(magic), + container(container), + cur_size(0), + cursor(0), + initial(initial) { + // empty + } + + virtual ~AssbinChunkWriter() { + if (container) { + container->Write(&magic, sizeof(uint32_t), 1); + container->Write(&cursor, sizeof(uint32_t), 1); + container->Write(buffer, 1, cursor); + } + if (buffer) delete[] buffer; + } + + void *GetBufferPointer() { return buffer; } + + // ------------------------------------------------------------------- + virtual size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + return 0; + } + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { + return aiReturn_FAILURE; + } + virtual size_t Tell() const { + return cursor; + } + virtual void Flush() { + // not implemented + } + + virtual size_t FileSize() const { + return cursor; + } + + // ------------------------------------------------------------------- + virtual size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) { + pSize *= pCount; + if (cursor + pSize > cur_size) { + Grow(cursor + pSize); + } + + memcpy(buffer + cursor, pvBuffer, pSize); + cursor += pSize; + + return pCount; + } +}; + +// ---------------------------------------------------------------------------------- +/** @class AssbinFileWriter + * @brief Assbin file writer class + * + * This class writes an .assbin file, and is responsible for the file layout. + */ +class AssbinFileWriter { +private: + bool shortened; + bool compressed; + +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); + + Write(&chunk, node->mName); + Write(&chunk, node->mTransformation); + Write(&chunk, node->mNumChildren); + Write(&chunk, node->mNumMeshes); + Write(&chunk, nb_metadata); + + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + Write(&chunk, node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + WriteBinaryNode(&chunk, node->mChildren[i]); + } + + for (unsigned int i = 0; i < nb_metadata; ++i) { + const aiString &key = node->mMetaData->mKeys[i]; + aiMetadataType type = node->mMetaData->mValues[i].mType; + void *value = node->mMetaData->mValues[i].mData; + + Write(&chunk, key); + 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; +#ifdef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream *container, const aiTexture *tex) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AITEXTURE); + + Write(&chunk, tex->mWidth); + Write(&chunk, tex->mHeight); + // Write the texture format, but don't include the null terminator. + chunk.Write(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1); + + if (!shortened) { + if (!tex->mHeight) { + chunk.Write(tex->pcData, 1, tex->mWidth); + } else { + chunk.Write(tex->pcData, 1, tex->mWidth * tex->mHeight * 4); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryBone(IOStream *container, const aiBone *b) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIBONE); + + Write(&chunk, b->mName); + Write(&chunk, b->mNumWeights); + Write(&chunk, b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(&chunk, b->mWeights, b->mNumWeights); + } // else write as usual + else + WriteArray(&chunk, b->mWeights, b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream *container, const aiMesh *mesh) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMESH); + + Write(&chunk, mesh->mPrimitiveTypes); + Write(&chunk, mesh->mNumVertices); + Write(&chunk, mesh->mNumFaces); + Write(&chunk, mesh->mNumBones); + Write(&chunk, mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk, c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk, mesh->mVertices, mesh->mNumVertices); + } // else write as usual + else + WriteArray(&chunk, mesh->mVertices, mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk, mesh->mNormals, mesh->mNumVertices); + } // else write as usual + else + WriteArray(&chunk, mesh->mNormals, mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteBounds(&chunk, mesh->mBitangents, mesh->mNumVertices); + } // else write as usual + else { + WriteArray(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteArray(&chunk, mesh->mBitangents, mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk, mesh->mColors[n], mesh->mNumVertices); + } // else write as usual + else + WriteArray(&chunk, mesh->mColors[n], mesh->mNumVertices); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + Write(&chunk, mesh->mNumUVComponents[n]); + + if (shortened) { + WriteBounds(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); + } // else write as usual + else + WriteArray(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job; (job = std::min(mesh->mNumFaces - processed, 512u)); processed += job) { + uint32_t hash = 0; + for (unsigned int a = 0; a < job; ++a) { + + const aiFace &f = mesh->mFaces[processed + a]; + uint32_t tmp = f.mNumIndices; + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); + for (unsigned int i = 0; i < f.mNumIndices; ++i) { + static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); + tmp = static_cast(f.mIndices[i]); + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); + } + } + Write(&chunk, hash); + } + } else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + const aiFace &f = mesh->mFaces[i]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + Write(&chunk, static_cast(f.mNumIndices)); + + for (unsigned int a = 0; a < f.mNumIndices; ++a) { + if (mesh->mNumVertices < (1u << 16)) { + Write(&chunk, static_cast(f.mIndices[a])); + } else { + Write(&chunk, f.mIndices[a]); + } + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones; ++a) { + const aiBone *b = mesh->mBones[a]; + WriteBinaryBone(&chunk, b); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterialProperty(IOStream *container, const aiMaterialProperty *prop) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIALPROPERTY); + + Write(&chunk, prop->mKey); + Write(&chunk, prop->mSemantic); + Write(&chunk, prop->mIndex); + + Write(&chunk, prop->mDataLength); + Write(&chunk, (unsigned int)prop->mType); + chunk.Write(prop->mData, 1, prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream *container, const aiMaterial *mat) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIAL); + + Write(&chunk, mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties; ++i) { + WriteBinaryMaterialProperty(&chunk, mat->mProperties[i]); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNodeAnim(IOStream *container, const aiNodeAnim *nd) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODEANIM); + + Write(&chunk, nd->mNodeName); + Write(&chunk, nd->mNumPositionKeys); + Write(&chunk, nd->mNumRotationKeys); + Write(&chunk, nd->mNumScalingKeys); + Write(&chunk, nd->mPreState); + Write(&chunk, nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); + + } // else write as usual + else + WriteArray(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); + + } // else write as usual + else + WriteArray(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); + + } // else write as usual + else + WriteArray(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim(IOStream *container, const aiAnimation *anim) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIANIMATION); + + Write(&chunk, anim->mName); + Write(&chunk, anim->mDuration); + Write(&chunk, anim->mTicksPerSecond); + Write(&chunk, anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk, nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight(IOStream *container, const aiLight *l) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AILIGHT); + + Write(&chunk, l->mName); + Write(&chunk, l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + Write(&chunk, l->mAttenuationConstant); + Write(&chunk, l->mAttenuationLinear); + Write(&chunk, l->mAttenuationQuadratic); + } + + Write(&chunk, l->mColorDiffuse); + Write(&chunk, l->mColorSpecular); + Write(&chunk, l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk, l->mAngleInnerCone); + Write(&chunk, l->mAngleOuterCone); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera(IOStream *container, const aiCamera *cam) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AICAMERA); + + Write(&chunk, cam->mName); + Write(&chunk, cam->mPosition); + Write(&chunk, cam->mLookAt); + Write(&chunk, cam->mUp); + Write(&chunk, cam->mHorizontalFOV); + Write(&chunk, cam->mClipPlaneNear); + Write(&chunk, cam->mClipPlaneFar); + Write(&chunk, cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene(IOStream *container, const aiScene *scene) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AISCENE); + + // basic scene information + Write(&chunk, scene->mFlags); + Write(&chunk, scene->mNumMeshes); + Write(&chunk, scene->mNumMaterials); + Write(&chunk, scene->mNumAnimations); + Write(&chunk, scene->mNumTextures); + Write(&chunk, scene->mNumLights); + Write(&chunk, scene->mNumCameras); + + // write node graph + WriteBinaryNode(&chunk, scene->mRootNode); + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + const aiMesh *mesh = scene->mMeshes[i]; + WriteBinaryMesh(&chunk, mesh); + } + + // write materials + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + const aiMaterial *mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk, mat); + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { + const aiAnimation *anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk, anim); + } + + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { + const aiTexture *mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk, mesh); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights; ++i) { + const aiLight *l = scene->mLights[i]; + WriteBinaryLight(&chunk, l); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras; ++i) { + const aiCamera *cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk, cam); + } + } + +public: + AssbinFileWriter(bool shortened, bool compressed) : + shortened(shortened), compressed(compressed) { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char *pFile, const char *cmd, IOSystem *pIOSystem, const aiScene *pScene) { + IOStream *out = pIOSystem->Open(pFile, "wb"); + if (!out) + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + + auto CloseIOStream = [&]() { + if (out) { + pIOSystem->Close(out); + out = nullptr; // Ensure this is only done once. + } + }; + + try { + time_t tt = time(NULL); +#if _WIN32 + tm *p = gmtime(&tt); +#else + struct tm now; + tm *p = gmtime_r(&tt, &now); +#endif + + // header + char s[64]; + memset(s, 0, 64); +#if _MSC_VER >= 1400 + sprintf_s(s, "ASSIMP.binary-dump.%s", asctime(p)); +#else + ai_snprintf(s, 64, "ASSIMP.binary-dump.%s", asctime(p)); +#endif + out->Write(s, 44, 1); + // == 44 bytes + + Write(out, ASSBIN_VERSION_MAJOR); + Write(out, ASSBIN_VERSION_MINOR); + Write(out, aiGetVersionRevision()); + Write(out, aiGetCompileFlags()); + Write(out, shortened); + Write(out, compressed); + // == 20 bytes + + char buff[256] = { 0 }; + ai_snprintf(buff, 256, "%s", pFile); + out->Write(buff, sizeof(char), 256); + + memset(buff, 0, sizeof(buff)); + ai_snprintf(buff, 128, "%s", cmd); + out->Write(buff, sizeof(char), 128); + + // leave 64 bytes free for future extensions + memset(buff, 0xcd, 64); + out->Write(buff, sizeof(char), 64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert(out->Tell() == ASSBIN_HEADER_LENGTH); + + // 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); + WriteBinaryScene(&uncompressedStream, pScene); + + uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); + uLongf compressedSize = (uLongf)compressBound(uncompressedSize); + uint8_t *compressedBuffer = new uint8_t[compressedSize]; + + int res = compress2(compressedBuffer, &compressedSize, (const Bytef *)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); + if (res != Z_OK) { + delete[] compressedBuffer; + throw DeadlyExportError("Compression failed."); + } + + out->Write(&uncompressedSize, sizeof(uint32_t), 1); + out->Write(compressedBuffer, sizeof(char), compressedSize); + + delete[] compressedBuffer; + } else { + WriteBinaryScene(out, pScene); + } + + CloseIOStream(); + } catch (...) { + CloseIOStream(); + throw; + } + } +}; + +void DumpSceneToAssbin( + const char *pFile, const char *cmd, IOSystem *pIOSystem, + const aiScene *pScene, bool shortened, bool compressed) { + AssbinFileWriter fileWriter(shortened, compressed); + fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); +} +#ifdef _WIN32 +#pragma warning(pop) +#endif // _WIN32 + +} // end of namespace Assimp diff --git a/code/AssetLib/Assbin/AssbinFileWriter.h b/code/AssetLib/Assbin/AssbinFileWriter.h new file mode 100644 index 000000000..25cbc8106 --- /dev/null +++ b/code/AssetLib/Assbin/AssbinFileWriter.h @@ -0,0 +1,65 @@ +/* +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 AssbinFileWriter.h + * @brief Declaration of Assbin file writer. + */ + +#ifndef AI_ASSBINFILEWRITER_H_INC +#define AI_ASSBINFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssbin( + const char *pFile, + const char *cmd, + IOSystem *pIOSystem, + const aiScene *pScene, + bool shortened, + bool compressed); + +} + +#endif // AI_ASSBINFILEWRITER_H_INC diff --git a/code/Assbin/AssbinLoader.cpp b/code/AssetLib/Assbin/AssbinLoader.cpp similarity index 57% rename from code/Assbin/AssbinLoader.cpp rename to code/AssetLib/Assbin/AssbinLoader.cpp index 71e35cb6a..5ee87e952 100644 --- a/code/Assbin/AssbinLoader.cpp +++ b/code/AssetLib/Assbin/AssbinLoader.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, @@ -50,19 +48,19 @@ 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 #include -#include #include +#include +#include #include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include +#include #else -# include +#include #endif using namespace Assimp; @@ -81,94 +79,97 @@ static const aiImporterDesc desc = { }; // ----------------------------------------------------------------------------------- -const aiImporterDesc* AssbinImporter::GetInfo() const { +const aiImporterDesc *AssbinImporter::GetInfo() const { return &desc; } // ----------------------------------------------------------------------------------- -bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const { - IOStream * in = pIOHandler->Open(pFile); +bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { + IOStream *in = pIOHandler->Open(pFile); if (nullptr == in) { return false; } char s[32]; - in->Read( s, sizeof(char), 32 ); + in->Read(s, sizeof(char), 32); pIOHandler->Close(in); - return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0; + return strncmp(s, "ASSIMP.binary-dump.", 19) == 0; } // ----------------------------------------------------------------------------------- template -T Read(IOStream * stream) { +T Read(IOStream *stream) { T t; - size_t res = stream->Read( &t, sizeof(T), 1 ); - if(res != 1) + size_t res = stream->Read(&t, sizeof(T), 1); + if (res != 1) { throw DeadlyImportError("Unexpected EOF"); + } return t; } // ----------------------------------------------------------------------------------- template <> -aiVector3D Read(IOStream * stream) { +aiVector3D Read(IOStream *stream) { aiVector3D v; - v.x = Read(stream); - v.y = Read(stream); - v.z = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); return v; } // ----------------------------------------------------------------------------------- template <> -aiColor4D Read(IOStream * stream) { +aiColor4D Read(IOStream *stream) { aiColor4D c; - c.r = Read(stream); - c.g = Read(stream); - c.b = Read(stream); - c.a = Read(stream); + c.r = Read(stream); + c.g = Read(stream); + c.b = Read(stream); + c.a = Read(stream); return c; } // ----------------------------------------------------------------------------------- template <> -aiQuaternion Read(IOStream * stream) { +aiQuaternion Read(IOStream *stream) { aiQuaternion v; - v.w = Read(stream); - v.x = Read(stream); - v.y = Read(stream); - v.z = Read(stream); + v.w = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); return v; } // ----------------------------------------------------------------------------------- template <> -aiString Read(IOStream * stream) { +aiString Read(IOStream *stream) { aiString s; - stream->Read(&s.length,4,1); - if(s.length) - stream->Read(s.data,s.length,1); + stream->Read(&s.length, 4, 1); + if (s.length) { + stream->Read(s.data, s.length, 1); + } s.data[s.length] = 0; + return s; } // ----------------------------------------------------------------------------------- template <> -aiVertexWeight Read(IOStream * stream) { +aiVertexWeight Read(IOStream *stream) { aiVertexWeight w; w.mVertexId = Read(stream); - w.mWeight = Read(stream); + w.mWeight = Read(stream); return w; } // ----------------------------------------------------------------------------------- template <> -aiMatrix4x4 Read(IOStream * stream) { +aiMatrix4x4 Read(IOStream *stream) { aiMatrix4x4 m; - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - m[i][i2] = Read(stream); + for (unsigned int i = 0; i < 4; ++i) { + for (unsigned int i2 = 0; i2 < 4; ++i2) { + m[i][i2] = Read(stream); } } return m; @@ -176,7 +177,7 @@ aiMatrix4x4 Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template <> -aiVectorKey Read(IOStream * stream) { +aiVectorKey Read(IOStream *stream) { aiVectorKey v; v.mTime = Read(stream); v.mValue = Read(stream); @@ -185,7 +186,7 @@ aiVectorKey Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template <> -aiQuatKey Read(IOStream * stream) { +aiQuatKey Read(IOStream *stream) { aiQuatKey v; v.mTime = Read(stream); v.mValue = Read(stream); @@ -194,27 +195,27 @@ aiQuatKey Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template -void ReadArray( IOStream *stream, T * out, unsigned int size) { - ai_assert( nullptr != stream ); - ai_assert( nullptr != out ); +void ReadArray(IOStream *stream, T *out, unsigned int size) { + ai_assert(nullptr != stream); + ai_assert(nullptr != out); - for (unsigned int i=0; i(stream); } } // ----------------------------------------------------------------------------------- template -void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) { +void ReadBounds(IOStream *stream, T * /*p*/, unsigned int n) { // not sure what to do here, the data isn't really useful. - stream->Seek( sizeof(T) * n, aiOrigin_CUR ); + stream->Seek(sizeof(T) * n, aiOrigin_CUR); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* parent ) { - if(Read(stream) != ASSBIN_CHUNK_AINODE) +void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) { + if (Read(stream) != ASSBIN_CHUNK_AINODE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); std::unique_ptr node(new aiNode()); @@ -222,14 +223,13 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* node->mTransformation = Read(stream); unsigned numChildren = Read(stream); unsigned numMeshes = Read(stream); - unsigned int nb_metadata = Read(stream); + unsigned int nb_metadata = Read(stream); - if(parent) { + if (parent) { node->mParent = parent; } - if (numMeshes) - { + if (numMeshes) { node->mMeshes = new unsigned int[numMeshes]; for (unsigned int i = 0; i < numMeshes; ++i) { node->mMeshes[i] = Read(stream); @@ -238,60 +238,60 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* } if (numChildren) { - node->mChildren = new aiNode*[numChildren]; + node->mChildren = new aiNode *[numChildren]; for (unsigned int i = 0; i < numChildren; ++i) { - ReadBinaryNode( stream, &node->mChildren[i], node.get() ); + ReadBinaryNode(stream, &node->mChildren[i], node.get()); node->mNumChildren++; } } - if ( nb_metadata > 0 ) { + if (nb_metadata > 0) { node->mMetaData = aiMetadata::Alloc(nb_metadata); for (unsigned int i = 0; i < nb_metadata; ++i) { node->mMetaData->mKeys[i] = Read(stream); - node->mMetaData->mValues[i].mType = (aiMetadataType) Read(stream); - void* data = nullptr; + node->mMetaData->mValues[i].mType = (aiMetadataType)Read(stream); + 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 float(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; - } - } + node->mMetaData->mValues[i].mData = data; + } + } *onode = node.release(); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) { - if(Read(stream) != ASSBIN_CHUNK_AIBONE) +void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) { + if (Read(stream) != ASSBIN_CHUNK_AIBONE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); b->mName = Read(stream); b->mNumWeights = Read(stream); @@ -300,23 +300,24 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) { // for the moment we write dumb min/max values for the bones, too. // maybe I'll add a better, hash-like solution later if (shortened) { - ReadBounds(stream,b->mWeights,b->mNumWeights); + ReadBounds(stream, b->mWeights, b->mNumWeights); } else { // else write as usual b->mWeights = new aiVertexWeight[b->mNumWeights]; - ReadArray(stream,b->mWeights,b->mNumWeights); + ReadArray(stream, b->mWeights, b->mNumWeights); } } // ----------------------------------------------------------------------------------- static bool fitsIntoUI16(unsigned int mNumVertices) { - return ( mNumVertices < (1u<<16) ); + return (mNumVertices < (1u << 16)); } + // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { - if(Read(stream) != ASSBIN_CHUNK_AIMESH) +void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) { + if (Read(stream) != ASSBIN_CHUNK_AIMESH) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); mesh->mPrimitiveTypes = Read(stream); mesh->mNumVertices = Read(stream); @@ -329,48 +330,48 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { if (c & ASSBIN_MESH_HAS_POSITIONS) { if (shortened) { - ReadBounds(stream,mesh->mVertices,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mVertices, mesh->mNumVertices); + } else { // else write as usual mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mVertices,mesh->mNumVertices); + ReadArray(stream, mesh->mVertices, mesh->mNumVertices); } } if (c & ASSBIN_MESH_HAS_NORMALS) { if (shortened) { - ReadBounds(stream,mesh->mNormals,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mNormals, mesh->mNumVertices); + } else { // else write as usual mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mNormals,mesh->mNumVertices); + ReadArray(stream, mesh->mNormals, mesh->mNumVertices); } } if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) { if (shortened) { - ReadBounds(stream,mesh->mTangents,mesh->mNumVertices); - ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mTangents, mesh->mNumVertices); + ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices); + } else { // else write as usual mesh->mTangents = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mTangents,mesh->mNumVertices); + ReadArray(stream, mesh->mTangents, mesh->mNumVertices); mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mBitangents,mesh->mNumVertices); + ReadArray(stream, mesh->mBitangents, mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!(c & ASSBIN_MESH_HAS_COLOR(n))) { break; } if (shortened) { - ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices); + } else { // else write as usual mesh->mColors[n] = new aiColor4D[mesh->mNumVertices]; - ReadArray(stream,mesh->mColors[n],mesh->mNumVertices); + ReadArray(stream, mesh->mColors[n], mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) { break; } @@ -379,11 +380,11 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { mesh->mNumUVComponents[n] = Read(stream); if (shortened) { - ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices); + } else { // else write as usual mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + ReadArray(stream, mesh->mTextureCoords[n], mesh->mNumVertices); } } @@ -393,20 +394,20 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { // using Assimp's standard hashing function. if (shortened) { Read(stream); - } else { + } else { // else write as usual // if there are less than 2^16 vertices, we can simply use 16 bit integers ... mesh->mFaces = new aiFace[mesh->mNumFaces]; - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - aiFace& f = mesh->mFaces[i]; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace &f = mesh->mFaces[i]; static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); f.mNumIndices = Read(stream); f.mIndices = new unsigned int[f.mNumIndices]; - for (unsigned int a = 0; a < f.mNumIndices;++a) { + for (unsigned int a = 0; a < f.mNumIndices; ++a) { // Check if unsigned short ( 16 bit ) are big enought for the indices - if ( fitsIntoUI16( mesh->mNumVertices ) ) { + if (fitsIntoUI16(mesh->mNumVertices)) { f.mIndices[a] = Read(stream); } else { f.mIndices[a] = Read(stream); @@ -417,19 +418,19 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { // write bones if (mesh->mNumBones) { - mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones]; - for (unsigned int a = 0; a < mesh->mNumBones;++a) { + mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones]; + for (unsigned int a = 0; a < mesh->mNumBones; ++a) { mesh->mBones[a] = new aiBone(); - ReadBinaryBone(stream,mesh->mBones[a]); + ReadBinaryBone(stream, mesh->mBones[a]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) { - if(Read(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY) +void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) { + if (Read(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); prop->mKey = Read(stream); prop->mSemantic = Read(stream); @@ -437,36 +438,34 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro prop->mDataLength = Read(stream); prop->mType = (aiPropertyTypeInfo)Read(stream); - prop->mData = new char [ prop->mDataLength ]; - stream->Read(prop->mData,1,prop->mDataLength); + prop->mData = new char[prop->mDataLength]; + stream->Read(prop->mData, 1, prop->mDataLength); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) { - if(Read(stream) != ASSBIN_CHUNK_AIMATERIAL) +void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) { + if (Read(stream) != ASSBIN_CHUNK_AIMATERIAL) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); mat->mNumAllocated = mat->mNumProperties = Read(stream); - if (mat->mNumProperties) - { - if (mat->mProperties) - { + if (mat->mNumProperties) { + if (mat->mProperties) { delete[] mat->mProperties; } - mat->mProperties = new aiMaterialProperty*[mat->mNumProperties]; - for (unsigned int i = 0; i < mat->mNumProperties;++i) { + mat->mProperties = new aiMaterialProperty *[mat->mNumProperties]; + for (unsigned int i = 0; i < mat->mNumProperties; ++i) { mat->mProperties[i] = new aiMaterialProperty(); - ReadBinaryMaterialProperty( stream, mat->mProperties[i]); + ReadBinaryMaterialProperty(stream, mat->mProperties[i]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) { - if(Read(stream) != ASSBIN_CHUNK_AINODEANIM) +void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) { + if (Read(stream) != ASSBIN_CHUNK_AINODEANIM) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); nd->mNodeName = Read(stream); nd->mNumPositionKeys = Read(stream); @@ -477,82 +476,82 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) { if (nd->mNumPositionKeys) { if (shortened) { - ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys); + ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys); } // else write as usual else { nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - ReadArray(stream,nd->mPositionKeys,nd->mNumPositionKeys); + ReadArray(stream, nd->mPositionKeys, nd->mNumPositionKeys); } } if (nd->mNumRotationKeys) { if (shortened) { - ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys); + ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys); - } else { + } else { // else write as usual nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; - ReadArray(stream,nd->mRotationKeys,nd->mNumRotationKeys); + ReadArray(stream, nd->mRotationKeys, nd->mNumRotationKeys); } } if (nd->mNumScalingKeys) { if (shortened) { - ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys); + ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys); - } else { + } else { // else write as usual nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; - ReadArray(stream,nd->mScalingKeys,nd->mNumScalingKeys); + ReadArray(stream, nd->mScalingKeys, nd->mNumScalingKeys); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) { - if(Read(stream) != ASSBIN_CHUNK_AIANIMATION) +void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) { + if (Read(stream) != ASSBIN_CHUNK_AIANIMATION) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); - anim->mName = Read (stream); - anim->mDuration = Read (stream); - anim->mTicksPerSecond = Read (stream); + anim->mName = Read(stream); + anim->mDuration = Read(stream); + anim->mTicksPerSecond = Read(stream); anim->mNumChannels = Read(stream); if (anim->mNumChannels) { - anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ]; - for (unsigned int a = 0; a < anim->mNumChannels;++a) { + anim->mChannels = new aiNodeAnim *[anim->mNumChannels]; + for (unsigned int a = 0; a < anim->mNumChannels; ++a) { anim->mChannels[a] = new aiNodeAnim(); - ReadBinaryNodeAnim(stream,anim->mChannels[a]); + ReadBinaryNodeAnim(stream, anim->mChannels[a]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) { - if(Read(stream) != ASSBIN_CHUNK_AITEXTURE) +void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) { + if (Read(stream) != ASSBIN_CHUNK_AITEXTURE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); tex->mWidth = Read(stream); tex->mHeight = Read(stream); - stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + stream->Read(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1); - if(!shortened) { + if (!shortened) { if (!tex->mHeight) { - tex->pcData = new aiTexel[ tex->mWidth ]; - stream->Read(tex->pcData,1,tex->mWidth); + tex->pcData = new aiTexel[tex->mWidth]; + stream->Read(tex->pcData, 1, tex->mWidth); } else { - tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ]; - stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4); + tex->pcData = new aiTexel[tex->mWidth * tex->mHeight]; + stream->Read(tex->pcData, 1, tex->mWidth * tex->mHeight * 4); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) { - if(Read(stream) != ASSBIN_CHUNK_AILIGHT) +void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) { + if (Read(stream) != ASSBIN_CHUNK_AILIGHT) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); l->mName = Read(stream); l->mType = (aiLightSourceType)Read(stream); @@ -574,10 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) { } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) { - if(Read(stream) != ASSBIN_CHUNK_AICAMERA) +void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) { + if (Read(stream) != ASSBIN_CHUNK_AICAMERA) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); cam->mName = Read(stream); cam->mPosition = Read(stream); @@ -590,141 +589,139 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) { } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) { - if(Read(stream) != ASSBIN_CHUNK_AISCENE) +void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) { + if (Read(stream) != ASSBIN_CHUNK_AISCENE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); - scene->mFlags = Read(stream); - scene->mNumMeshes = Read(stream); - scene->mNumMaterials = Read(stream); + scene->mFlags = Read(stream); + scene->mNumMeshes = Read(stream); + scene->mNumMaterials = Read(stream); scene->mNumAnimations = Read(stream); - scene->mNumTextures = Read(stream); - scene->mNumLights = Read(stream); - scene->mNumCameras = Read(stream); + scene->mNumTextures = Read(stream); + scene->mNumLights = Read(stream); + scene->mNumCameras = Read(stream); // Read node graph //scene->mRootNode = new aiNode[1]; - ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL ); + ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL); // Read all meshes if (scene->mNumMeshes) { - scene->mMeshes = new aiMesh*[scene->mNumMeshes]; - memset(scene->mMeshes, 0, scene->mNumMeshes*sizeof(aiMesh*)); - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + scene->mMeshes = new aiMesh *[scene->mNumMeshes]; + memset(scene->mMeshes, 0, scene->mNumMeshes * sizeof(aiMesh *)); + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { scene->mMeshes[i] = new aiMesh(); - ReadBinaryMesh( stream,scene->mMeshes[i]); + ReadBinaryMesh(stream, scene->mMeshes[i]); } } // Read materials if (scene->mNumMaterials) { - scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; - memset(scene->mMaterials, 0, scene->mNumMaterials*sizeof(aiMaterial*)); - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; + memset(scene->mMaterials, 0, scene->mNumMaterials * sizeof(aiMaterial *)); + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { scene->mMaterials[i] = new aiMaterial(); - ReadBinaryMaterial(stream,scene->mMaterials[i]); + ReadBinaryMaterial(stream, scene->mMaterials[i]); } } // Read all animations if (scene->mNumAnimations) { - scene->mAnimations = new aiAnimation*[scene->mNumAnimations]; - memset(scene->mAnimations, 0, scene->mNumAnimations*sizeof(aiAnimation*)); - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + scene->mAnimations = new aiAnimation *[scene->mNumAnimations]; + memset(scene->mAnimations, 0, scene->mNumAnimations * sizeof(aiAnimation *)); + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { scene->mAnimations[i] = new aiAnimation(); - ReadBinaryAnim(stream,scene->mAnimations[i]); + ReadBinaryAnim(stream, scene->mAnimations[i]); } } // Read all textures if (scene->mNumTextures) { - scene->mTextures = new aiTexture*[scene->mNumTextures]; - memset(scene->mTextures, 0, scene->mNumTextures*sizeof(aiTexture*)); - for (unsigned int i = 0; i < scene->mNumTextures;++i) { + scene->mTextures = new aiTexture *[scene->mNumTextures]; + memset(scene->mTextures, 0, scene->mNumTextures * sizeof(aiTexture *)); + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { scene->mTextures[i] = new aiTexture(); - ReadBinaryTexture(stream,scene->mTextures[i]); + ReadBinaryTexture(stream, scene->mTextures[i]); } } // Read lights if (scene->mNumLights) { - scene->mLights = new aiLight*[scene->mNumLights]; - memset(scene->mLights, 0, scene->mNumLights*sizeof(aiLight*)); - for (unsigned int i = 0; i < scene->mNumLights;++i) { + scene->mLights = new aiLight *[scene->mNumLights]; + memset(scene->mLights, 0, scene->mNumLights * sizeof(aiLight *)); + for (unsigned int i = 0; i < scene->mNumLights; ++i) { scene->mLights[i] = new aiLight(); - ReadBinaryLight(stream,scene->mLights[i]); + ReadBinaryLight(stream, scene->mLights[i]); } } // Read cameras if (scene->mNumCameras) { - scene->mCameras = new aiCamera*[scene->mNumCameras]; - memset(scene->mCameras, 0, scene->mNumCameras*sizeof(aiCamera*)); - for (unsigned int i = 0; i < scene->mNumCameras;++i) { + scene->mCameras = new aiCamera *[scene->mNumCameras]; + memset(scene->mCameras, 0, scene->mNumCameras * sizeof(aiCamera *)); + for (unsigned int i = 0; i < scene->mNumCameras; ++i) { scene->mCameras[i] = new aiCamera(); - ReadBinaryCamera(stream,scene->mCameras[i]); + ReadBinaryCamera(stream, scene->mCameras[i]); } } - } // ----------------------------------------------------------------------------------- -void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) { - IOStream * stream = pIOHandler->Open(pFile,"rb"); +void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + IOStream *stream = pIOHandler->Open(pFile, "rb"); if (nullptr == stream) { return; } // signature - stream->Seek( 44, aiOrigin_CUR ); + stream->Seek(44, aiOrigin_CUR); unsigned int versionMajor = Read(stream); unsigned int versionMinor = Read(stream); if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) { - throw DeadlyImportError( "Invalid version, data format not compatible!" ); + throw DeadlyImportError("Invalid version, data format not compatible!"); } - /*unsigned int versionRevision =*/ Read(stream); - /*unsigned int compileFlags =*/ Read(stream); + /*unsigned int versionRevision =*/Read(stream); + /*unsigned int compileFlags =*/Read(stream); shortened = Read(stream) > 0; compressed = Read(stream) > 0; if (shortened) - throw DeadlyImportError( "Shortened binaries are not supported!" ); + throw DeadlyImportError("Shortened binaries are not supported!"); - stream->Seek( 256, aiOrigin_CUR ); // original filename - stream->Seek( 128, aiOrigin_CUR ); // options - stream->Seek( 64, aiOrigin_CUR ); // padding + stream->Seek(256, aiOrigin_CUR); // original filename + stream->Seek(128, aiOrigin_CUR); // options + stream->Seek(64, aiOrigin_CUR); // padding if (compressed) { uLongf uncompressedSize = Read(stream); uLongf compressedSize = static_cast(stream->FileSize() - stream->Tell()); - unsigned char * compressedData = new unsigned char[ compressedSize ]; - size_t len = stream->Read( compressedData, 1, compressedSize ); + unsigned char *compressedData = new unsigned char[compressedSize]; + size_t len = stream->Read(compressedData, 1, compressedSize); ai_assert(len == compressedSize); - unsigned char * uncompressedData = new unsigned char[ uncompressedSize ]; + unsigned char *uncompressedData = new unsigned char[uncompressedSize]; - int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len ); - if(res != Z_OK) - { - delete [] uncompressedData; - delete [] compressedData; + int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len); + if (res != Z_OK) { + delete[] uncompressedData; + delete[] compressedData; pIOHandler->Close(stream); throw DeadlyImportError("Zlib decompression failed."); } - MemoryIOStream io( uncompressedData, uncompressedSize ); + MemoryIOStream io(uncompressedData, uncompressedSize); - ReadBinaryScene(&io,pScene); + ReadBinaryScene(&io, pScene); delete[] uncompressedData; delete[] compressedData; } else { - ReadBinaryScene(stream,pScene); + ReadBinaryScene(stream, pScene); } pIOHandler->Close(stream); 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 97% rename from code/Assjson/cencode.c rename to code/AssetLib/Assjson/cencode.c index bd302100b..0ed979b01 100644 --- a/code/Assjson/cencode.c +++ b/code/AssetLib/Assjson/cencode.c @@ -9,6 +9,9 @@ For details, see http://sourceforge.net/projects/libb64 const int CHARS_PER_LINE = 72; +#pragma warning(push) +#pragma warning(disable : 4244) + void base64_init_encodestate(base64_encodestate* state_in) { state_in->step = step_A; @@ -107,3 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in) return (int)(codechar - code_out); } +#pragma warning(pop) diff --git a/code/Assjson/cencode.h b/code/AssetLib/Assjson/cencode.h similarity index 91% rename from code/Assjson/cencode.h rename to code/AssetLib/Assjson/cencode.h index c1e3464af..6bf76724e 100644 --- a/code/Assjson/cencode.h +++ b/code/AssetLib/Assjson/cencode.h @@ -8,6 +8,10 @@ For details, see http://sourceforge.net/projects/libb64 #ifndef BASE64_CENCODE_H #define BASE64_CENCODE_H +#ifdef _WIN32 +#pragma warning(disable : 4127 ) +#endif // _WIN32 + typedef enum { step_A, step_B, step_C diff --git a/code/Assjson/json_exporter.cpp b/code/AssetLib/Assjson/json_exporter.cpp similarity index 80% rename from code/Assjson/json_exporter.cpp rename to code/AssetLib/Assjson/json_exporter.cpp index e9fa72496..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,43 +67,43 @@ 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 out = new char[std::max(len * 2, static_cast(16u))]; - const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), out, &s); - out[n + base64_encode_blockend(out + n, &s)] = '\0'; + 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'; // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines // (only escaped ones). Remove any newlines in out. - for (char* cur = out; *cur; ++cur) { + for (char *cur = cur_out; *cur; ++cur) { if (*cur == '\n') { *cur = ' '; } } - buff << '\"' << out << "\"\n"; - delete[] out; + buff << '\"' << cur_out << "\"\n"; + delete[] cur_out; } void StartObj(bool is_element = false) { @@ -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 i = 0; i < prop->mDataLength / sizeof(float); ++i) { - out.Element(reinterpret_cast(prop->mData)[i]); - } - 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 i = 0; i < prop->mDataLength / sizeof(int); ++i) { - out.Element(reinterpret_cast(prop->mData)[i]); - } - 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/AssetLib/Assxml/AssxmlExporter.cpp b/code/AssetLib/Assxml/AssxmlExporter.cpp new file mode 100644 index 000000000..ac2a433dd --- /dev/null +++ b/code/AssetLib/Assxml/AssxmlExporter.cpp @@ -0,0 +1,68 @@ +/* +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 AssxmlExporter.cpp + * ASSXML exporter main code + */ + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER + +#include "AssxmlFileWriter.h" +#include +#include + +namespace Assimp { + +void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) +{ + DumpSceneToAssxml( + pFile, + "\0", // command(s) + pIOSystem, + pScene, + false); // shortened? +} + +} // end of namespace Assimp + +#endif // ASSIMP_BUILD_NO_ASSXML_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT 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..b175265b5 --- /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(NULL); +#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/AssetLib/Assxml/AssxmlFileWriter.h b/code/AssetLib/Assxml/AssxmlFileWriter.h new file mode 100644 index 000000000..c10a8a5aa --- /dev/null +++ b/code/AssetLib/Assxml/AssxmlFileWriter.h @@ -0,0 +1,65 @@ +/* +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.h + * @brief Declaration of Assxml file writer. + */ + +#ifndef AI_ASSXMLFILEWRITER_H_INC +#define AI_ASSXMLFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssxml( + const char* pFile, + const char* cmd, + IOSystem* pIOSystem, + const aiScene* pScene, + bool shortened); + +} + +#endif // AI_ASSXMLFILEWRITER_H_INC diff --git a/code/AssetLib/B3D/B3DImporter.cpp b/code/AssetLib/B3D/B3DImporter.cpp new file mode 100644 index 000000000..ff595aaf1 --- /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 97% rename from code/B3D/B3DImporter.h rename to code/AssetLib/B3D/B3DImporter.h index f0568dd16..17f15963d 100644 --- a/code/B3D/B3DImporter.h +++ b/code/AssetLib/B3D/B3DImporter.h @@ -82,7 +82,7 @@ private: std::string ReadString(); std::string ReadChunk(); void ExitChunk(); - unsigned ChunkSize(); + size_t ChunkSize(); template T *to_array( const std::vector &v ); @@ -112,10 +112,10 @@ private: void ReadBB3D( aiScene *scene ); - unsigned _pos; + size_t _pos; // unsigned _size; std::vector _buf; - std::vector _stack; + std::vector _stack; std::vector _textures; std::vector > _materials; diff --git a/code/BVH/BVHLoader.cpp b/code/AssetLib/BVH/BVHLoader.cpp similarity index 50% rename from code/BVH/BVHLoader.cpp rename to code/AssetLib/BVH/BVHLoader.cpp index 1110754c2..348c30337 100644 --- a/code/BVH/BVHLoader.cpp +++ b/code/AssetLib/BVH/BVHLoader.cpp @@ -42,19 +42,18 @@ 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 +#include +#include +#include #include +#include using namespace Assimp; using namespace Assimp::Formatter; @@ -74,104 +73,98 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -BVHLoader::BVHLoader() - : mLine(), - mAnimTickDuration(), - mAnimNumFrames(), - noSkeletonMesh() -{} +BVHLoader::BVHLoader() : + mLine(), + mAnimTickDuration(), + mAnimNumFrames(), + noSkeletonMesh() {} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -BVHLoader::~BVHLoader() -{} +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 -{ +bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { // check file extension const std::string extension = GetExtension(pFile); - if( extension == "bvh") + if (extension == "bvh") return true; if ((!extension.length() || cs) && pIOHandler) { - const char* tokens[] = {"HIERARCHY"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + 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; +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 -{ +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) -{ +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() == NULL) - throw DeadlyImportError( "Failed to open file " + pFile + "."); + 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."); + if (fileSize == 0) { + throw DeadlyImportError("File is too small."); + } - mBuffer.resize( fileSize); - file->Read( &mBuffer.front(), 1, fileSize); + mBuffer.resize(fileSize); + file->Read(&mBuffer.front(), 1, fileSize); // start reading mReader = mBuffer.begin(); mLine = 1; - ReadStructure( pScene); + ReadStructure(pScene); if (!noSkeletonMesh) { // build a dummy mesh for the skeleton so that we see something at least - SkeletonMeshBuilder meshBuilder( pScene); + SkeletonMeshBuilder meshBuilder(pScene); } // construct an animation from all the motion data we read - CreateAnimation( pScene); + CreateAnimation(pScene); } // ------------------------------------------------------------------------------------------------ // Reads the file -void BVHLoader::ReadStructure( aiScene* pScene) -{ +void BVHLoader::ReadStructure(aiScene *pScene) { // first comes hierarchy std::string header = GetNextToken(); - if( header != "HIERARCHY") - ThrowException( "Expected header string \"HIERARCHY\"."); - ReadHierarchy( pScene); + 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); + if (motion != "MOTION") + ThrowException("Expected beginning of motion data \"MOTION\"."); + ReadMotion(pScene); } // ------------------------------------------------------------------------------------------------ // Reads the hierarchy -void BVHLoader::ReadHierarchy( aiScene* pScene) -{ +void BVHLoader::ReadHierarchy(aiScene *pScene) { std::string root = GetNextToken(); - if( root != "ROOT") - ThrowException( "Expected root node \"ROOT\"."); + if (root != "ROOT") + ThrowException("Expected root node \"ROOT\"."); // Go read the hierarchy from here pScene->mRootNode = ReadNode(); @@ -179,73 +172,64 @@ void BVHLoader::ReadHierarchy( aiScene* pScene) // ------------------------------------------------------------------------------------------------ // Reads a node and recursively its childs and returns the created node; -aiNode* BVHLoader::ReadNode() -{ +aiNode *BVHLoader::ReadNode() { // first token is name std::string nodeName = GetNextToken(); - if( nodeName.empty() || nodeName == "{") - ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." ); + if (nodeName.empty() || nodeName == "{") + ThrowException(format() << "Expected node name, but found \"" << nodeName << "\"."); // then an opening brace should follow std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." ); + if (openBrace != "{") + ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); // Create a node - aiNode* node = new aiNode( nodeName); - std::vector childNodes; + aiNode *node = new aiNode(nodeName); + std::vector childNodes; // and create an bone entry for it - mNodes.push_back( Node( node)); - Node& internNode = mNodes.back(); + mNodes.push_back(Node(node)); + Node &internNode = mNodes.back(); // now read the node's contents std::string siteToken; - while( 1) - { + 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") - { + if (token == "OFFSET") + ReadNodeOffset(node); + else if (token == "CHANNELS") + ReadNodeChannels(internNode); + else if (token == "JOINT") { // child node follows - aiNode* child = ReadNode(); + aiNode *child = ReadNode(); child->mParent = node; - childNodes.push_back( child); - } - else if( token == "End") - { + 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( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." ); + if (siteToken != "Site") + ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"."); - aiNode* child = ReadEndSite( nodeName); + aiNode *child = ReadEndSite(nodeName); child->mParent = node; - childNodes.push_back( child); - } - else if( token == "}") - { + childNodes.push_back(child); + } else if (token == "}") { // we're done with that part of the hierarchy break; - } else - { + } else { // everything else is a parse error - ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + ThrowException(format() << "Unknown keyword \"" << token << "\"."); } } // add the child nodes if there are any - if( childNodes.size() > 0) - { + if (childNodes.size() > 0) { node->mNumChildren = static_cast(childNodes.size()); - node->mChildren = new aiNode*[node->mNumChildren]; - std::copy( childNodes.begin(), childNodes.end(), node->mChildren); + node->mChildren = new aiNode *[node->mNumChildren]; + std::copy(childNodes.begin(), childNodes.end(), node->mChildren); } // and return the sub-hierarchy we built here @@ -254,31 +238,30 @@ aiNode* BVHLoader::ReadNode() // ------------------------------------------------------------------------------------------------ // Reads an end node and returns the created node. -aiNode* BVHLoader::ReadEndSite( const std::string& pParentName) -{ +aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) { // check opening brace std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); + if (openBrace != "{") + ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); // Create a node - aiNode* node = new aiNode( "EndSite_" + pParentName); + aiNode *node = new aiNode("EndSite_" + pParentName); // now read the node's contents. Only possible entry is "OFFSET" std::string token; - while( 1) { + while (1) { token.clear(); token = GetNextToken(); // end node's offset - if( token == "OFFSET") { - ReadNodeOffset( node); - } else if( token == "}") { + if (token == "OFFSET") { + ReadNodeOffset(node); + } else if (token == "}") { // we're done with the end node break; } else { // everything else is a parse error - ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + ThrowException(format() << "Unknown keyword \"" << token << "\"."); } } @@ -287,8 +270,7 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName) } // ------------------------------------------------------------------------------------------------ // Reads a node offset for the given node -void BVHLoader::ReadNodeOffset( aiNode* pNode) -{ +void BVHLoader::ReadNodeOffset(aiNode *pNode) { // Offset consists of three floats to read aiVector3D offset; offset.x = GetNextTokenAsFloat(); @@ -296,74 +278,69 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode) 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); + 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) -{ +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; + unsigned int numChannels = (unsigned int)numChannelsFloat; - for( unsigned int a = 0; a < numChannels; a++) - { + 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); + 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( format() << "Invalid channel specifier \"" << channelToken << "\"." ); + ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\"."); } } // ------------------------------------------------------------------------------------------------ // Reads the motion data -void BVHLoader::ReadMotion( aiScene* /*pScene*/) -{ +void BVHLoader::ReadMotion(aiScene * /*pScene*/) { // Read number of frames std::string tokenFrames = GetNextToken(); - if( tokenFrames != "Frames:") - ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); + if (tokenFrames != "Frames:") + ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); float numFramesFloat = GetNextTokenAsFloat(); - mAnimNumFrames = (unsigned int) numFramesFloat; + mAnimNumFrames = (unsigned int)numFramesFloat; // Read frame duration std::string tokenDuration1 = GetNextToken(); std::string tokenDuration2 = GetNextToken(); - if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") - ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." ); + if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") + ThrowException(format() << "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); + 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) - { + 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) - { + 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()); + 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 @@ -372,16 +349,14 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/) // ------------------------------------------------------------------------------------------------ // Retrieves the next token -std::string BVHLoader::GetNextToken() -{ +std::string BVHLoader::GetNextToken() { // skip any preceding whitespace - while( mReader != mBuffer.end()) - { - if( !isspace( *mReader)) + while (mReader != mBuffer.end()) { + if (!isspace(*mReader)) break; // count lines - if( *mReader == '\n') + if (*mReader == '\n') mLine++; ++mReader; @@ -389,16 +364,15 @@ std::string BVHLoader::GetNextToken() // collect all chars till the next whitespace. BVH is easy in respect to that. std::string token; - while( mReader != mBuffer.end()) - { - if( isspace( *mReader)) + while (mReader != mBuffer.end()) { + if (isspace(*mReader)) break; - token.push_back( *mReader); + token.push_back(*mReader); ++mReader; // little extra logic to make sure braces are counted correctly - if( token == "{" || token == "}") + if (token == "{" || token == "}") break; } @@ -408,111 +382,101 @@ std::string BVHLoader::GetNextToken() // ------------------------------------------------------------------------------------------------ // Reads the next token as a float -float BVHLoader::GetNextTokenAsFloat() -{ +float BVHLoader::GetNextTokenAsFloat() { std::string token = GetNextToken(); - if( token.empty()) - ThrowException( "Unexpected end of file while trying to read a float"); + 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(); + const char *ctoken = token.c_str(); float result = 0.0f; - ctoken = fast_atoreal_move( ctoken, result); + ctoken = fast_atoreal_move(ctoken, result); - if( ctoken != token.c_str() + token.length()) - ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." ); + if (ctoken != token.c_str() + token.length()) + ThrowException(format() << "Expected a floating point number, but found \"" << token << "\"."); return result; } // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError) -{ - throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError); +AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) { + throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError); } // ------------------------------------------------------------------------------------------------ // Constructs an animation for the motion data and stores it in the given scene -void BVHLoader::CreateAnimation( aiScene* pScene) -{ +void BVHLoader::CreateAnimation(aiScene *pScene) { // create the animation pScene->mNumAnimations = 1; - pScene->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = new aiAnimation; + 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); + 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]; + anim->mChannels = new aiNodeAnim *[anim->mNumChannels]; // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown - for (unsigned int i = 0; i < anim->mNumChannels;++i) + for (unsigned int i = 0; i < anim->mNumChannels; ++i) anim->mChannels[i] = NULL; - 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; + 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; + 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; - } + //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) - { + 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); + 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); + // 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; - } + 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 - { + } 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); + 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; @@ -525,42 +489,36 @@ void BVHLoader::CreateAnimation( aiScene* pScene) // 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) - { + aiQuatKey *rotkey = nodeAnim->mRotationKeys; + for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) { aiMatrix4x4 temp; aiMatrix3x3 rotMatrix; - for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1)) - { - //Find channel in node - std::map::iterator mapIter = channelMap.find(channel); - - if (mapIter == channelMap.end()) - throw DeadlyImportError("Missing rotation channel in node " + nodeName); - else { - int channelIdx = mapIter->second; - // translate ZXY euler angels into a quaternion - const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; - - // Compute rotation transformations in the right order - switch (channel) - { - case Channel_RotationX: - aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp); - break; - case Channel_RotationY: - aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp); - break; - case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp); - break; - default: - break; - } + 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->mTime = double(fr); + rotkey->mValue = aiQuaternion(rotMatrix); ++rotkey; } } @@ -570,7 +528,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene) 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); + nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f); } } } 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..c2ecbd102 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,10 @@ protected: float GetNextTokenAsFloat(); /** Aborts the file reading with an exception */ - AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX; + AI_WONT_RETURN void ThrowException(const std::string &pError) 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..c752da4e0 --- /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((Formatter::format(), "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 72% rename from code/Blender/BlenderDNA.cpp rename to code/AssetLib/Blender/BlenderDNA.cpp index 53fb84824..920362f24 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,75 +71,76 @@ 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)" - )); + "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; + Structure &s = dna.structures.back(); + s.name = types[n].name; //s.index = dna.structures.size()-1; n = stream.GetI2(); @@ -152,12 +152,11 @@ 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)" - )); + "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; @@ -166,9 +165,8 @@ 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)" - )); + "BlenderDNA: Invalid name index in structure field ", j, + " (there are only ", names.size(), " entries)")); } f.name = names[j]; @@ -191,26 +189,25 @@ void DNAParser::Parse () const std::string::size_type rb = f.name.find('['); if (rb == std::string::npos) { throw DeadlyImportError((format(), - "BlenderDNA: Encountered invalid array declaration ", - f.name - )); + "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 +217,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 +230,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 +249,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 +259,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 +267,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 +302,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 +330,7 @@ void DNA :: AddPrimitiveStructures() } // ------------------------------------------------------------------------------------------------ -void SectionParser :: Next() -{ +void SectionParser ::Next() { stream.SetCurrentPos(current.start + current.size); const char tmp[] = { @@ -352,7 +339,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 +353,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 76% rename from code/Blender/BlenderDNA.h rename to code/AssetLib/Blender/BlenderDNA.h index 16ce960e2..7e04bad19 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