Merge branch 'master' into master

pull/3231/head
Kim Kulling 2020-10-17 10:57:26 +02:00 committed by GitHub
commit 56e1a80e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
227 changed files with 34954 additions and 24284 deletions

View File

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

View File

@ -19,7 +19,7 @@ jobs:
CC: clang CC: clang
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v2 uses: lukka/run-cmake@v3
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'

View File

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

View File

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

View File

@ -16,5 +16,5 @@ set(RT_LIBRARIES ${RT_LIBRARY})
# handle the QUIETLY and REQUIRED arguments and set # handle the QUIETLY and REQUIRED arguments and set
# RT_FOUND to TRUE if all listed variables are TRUE # RT_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY) find_package_handle_standard_args(RT DEFAULT_MSG RT_LIBRARY)
mark_as_advanced(RT_LIBRARY) mark_as_advanced(RT_LIBRARY)

View File

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

View File

@ -2,13 +2,13 @@
find_package(RapidJSON CONFIG REQUIRED) find_package(RapidJSON CONFIG REQUIRED)
find_package(ZLIB CONFIG REQUIRED) find_package(ZLIB CONFIG REQUIRED)
find_package(utf8 CONFIG REQUIRED) find_package(utf8cpp CONFIG REQUIRED)
find_package(irrXML CONFIG REQUIRED)
find_package(minizip CONFIG REQUIRED) find_package(minizip CONFIG REQUIRED)
find_package(openddlparser CONFIG REQUIRED) find_package(openddlparser CONFIG REQUIRED)
find_package(poly2tri CONFIG REQUIRED) find_package(poly2tri CONFIG REQUIRED)
find_package(polyclipping CONFIG REQUIRED) find_package(polyclipping CONFIG REQUIRED)
find_package(zip CONFIG REQUIRED) find_package(zip CONFIG REQUIRED)
find_package(pugixml CONFIG REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@") check_required_components("@PROJECT_NAME@")

View File

@ -0,0 +1,978 @@
/*
---------------------------------------------------------------------------
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 <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
// Header files, stdlib.
#include <iterator>
namespace Assimp
{
aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const
{
aiColor4D tcol;
// Check if stored data are supported.
if(!Composition.empty())
{
throw DeadlyImportError("IME. GetColor for composition");
}
else if(Color->Composed)
{
throw DeadlyImportError("IME. GetColor, composed color");
}
else
{
tcol = Color->Color;
}
// Check if default color must be used
if((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0))
{
tcol.r = 0.5f;
tcol.g = 0.5f;
tcol.b = 0.5f;
tcol.a = 1;
}
return tcol;
}
void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
std::vector<AMFColor*>& pVertexColorArray) const
{
AMFVertices* vn = nullptr;
size_t col_idx;
// All data stored in "vertices", search for it.
for(AMFNodeElementBase* ne_child: pNodeElement.Child)
{
if(ne_child->Type == AMFNodeElementBase::ENET_Vertices) vn = (AMFVertices*)ne_child;
}
// If "vertices" not found then no work for us.
if(vn == nullptr) return;
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(AMFNodeElementBase* vn_child: vn->Child)
{
// vertices, colors
if(vn_child->Type == AMFNodeElementBase::ENET_Vertex)
{
// by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr;
for(AMFNodeElementBase* vtx: vn_child->Child)
{
if(vtx->Type == AMFNodeElementBase::ENET_Coordinates)
{
pVertexCoordinateArray.push_back(((AMFCoordinates*)vtx)->Coordinate);
continue;
}
if(vtx->Type == AMFNodeElementBase::ENET_Color)
{
pVertexColorArray[col_idx] = (AMFColor*)vtx;
continue;
}
}// 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.
//
AMFTexture* src_texture[4]{nullptr};
std::vector<AMFTexture*> src_texture_4check;
SPP_Texture converted_texture;
{// find all specified source textures
AMFNodeElementBase* t_tex;
// R
if(!pID_R.empty())
{
if(!Find_NodeElement(pID_R, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
src_texture[0] = (AMFTexture*)t_tex;
src_texture_4check.push_back((AMFTexture*)t_tex);
}
else
{
src_texture[0] = nullptr;
}
// G
if(!pID_G.empty())
{
if(!Find_NodeElement(pID_G, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
src_texture[1] = (AMFTexture*)t_tex;
src_texture_4check.push_back((AMFTexture*)t_tex);
}
else
{
src_texture[1] = nullptr;
}
// B
if(!pID_B.empty())
{
if(!Find_NodeElement(pID_B, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
src_texture[2] = (AMFTexture*)t_tex;
src_texture_4check.push_back((AMFTexture*)t_tex);
}
else
{
src_texture[2] = nullptr;
}
// A
if(!pID_A.empty())
{
if(!Find_NodeElement(pID_A, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
src_texture[3] = (AMFTexture*)t_tex;
src_texture_4check.push_back((AMFTexture*)t_tex);
}
else
{
src_texture[3] = nullptr;
}
}// END: find all specified source textures
// check that all textures has same size
if(src_texture_4check.size() > 1)
{
for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
{
if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth))
{
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
}
}
}// if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture.Width = src_texture_4check[0]->Width;
converted_texture.Height = src_texture_4check[0]->Height;
converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false;
for(uint8_t i = 0; i < src_texture_4check.size(); i++) converted_texture.Tiled |= src_texture_4check[i]->Tiled;
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000");// copy initial string.
if(!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++) {
AMFTexture* tex = src_texture[pSrcTexNum];
ai_assert(tex);
converted_texture.Data[idx_target] = tex->Data.at(idx_src);
}
}
};// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(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<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated)
{
auto texmap_is_equal = [](const AMFTexMap* pTexMap1, const AMFTexMap* pTexMap2) -> bool
{
if((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
if(pTexMap1 == nullptr) return false;
if(pTexMap2 == nullptr) return false;
if(pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
if(pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
if(pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
if(pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
return true;
};
pOutputList_Separated.clear();
if(pInputList.empty()) return;
do
{
SComplexFace face_start = pInputList.front();
std::list<SComplexFace> face_list_cur;
for(std::list<SComplexFace>::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<AMFMetadata*>& 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<unsigned int>(metadataList.size()) );
size_t meta_idx( 0 );
for(const AMFMetadata& metadata: metadataList)
{
sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
}
}// if(!metadataList.empty())
}
void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode)
{
AMFColor* object_color = nullptr;
// create new aiNode and set name as <object> has.
*pSceneNode = new aiNode;
(*pSceneNode)->mName = pNodeElement.ID;
// read mesh and color
for(const AMFNodeElementBase* ne_child: pNodeElement.Child)
{
std::vector<aiVector3D> vertex_arr;
std::vector<AMFColor*> color_arr;
// color for object
if(ne_child->Type == AMFNodeElementBase::ENET_Color) object_color = (AMFColor*)ne_child;
if(ne_child->Type == AMFNodeElementBase::ENET_Mesh)
{
// Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((AMFMesh*)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh
Postprocess_BuildMeshSet(*((AMFMesh*)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
}
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
}
void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
const std::vector<AMFColor*>& pVertexColorArray,
const AMFColor* pObjectColor, std::list<aiMesh*>& pMeshList, aiNode& pSceneNode)
{
std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it.
for(const AMFNodeElementBase* ne_child: pNodeElement.Child)
{
const AMFColor* ne_volume_color = nullptr;
const SPP_Material* cur_mat = nullptr;
if(ne_child->Type == AMFNodeElementBase::ENET_Volume)
{
/******************* Get faces *******************/
const AMFVolume* ne_volume = reinterpret_cast<const AMFVolume*>(ne_child);
std::list<SComplexFace> complex_faces_list;// List of the faces of the volume.
std::list<std::list<SComplexFace> > complex_faces_toplist;// List of the face list for every mesh.
// check if volume use material
if(!ne_volume->MaterialID.empty())
{
if(!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID);
}
// inside "volume" collect all data and place to arrays or create new objects
for(const AMFNodeElementBase* ne_volume_child: ne_volume->Child)
{
// color for volume
if(ne_volume_child->Type == AMFNodeElementBase::ENET_Color)
{
ne_volume_color = reinterpret_cast<const AMFColor*>(ne_volume_child);
}
else if(ne_volume_child->Type == AMFNodeElementBase::ENET_Triangle)// triangles, triangles colors
{
const AMFTriangle& tri_al = *reinterpret_cast<const AMFTriangle*>(ne_volume_child);
SComplexFace complex_face;
// initialize pointers
complex_face.Color = nullptr;
complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates.
if(tri_al.Child.size())
{
for(const AMFNodeElementBase* ne_triangle_child: tri_al.Child)
{
if(ne_triangle_child->Type == AMFNodeElementBase::ENET_Color)
complex_face.Color = reinterpret_cast<const AMFColor*>(ne_triangle_child);
else if(ne_triangle_child->Type == AMFNodeElementBase::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const AMFTexMap*>(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<unsigned int>(tri_al.V[0]);
complex_face.Face.mIndices[1] = static_cast<unsigned int>(tri_al.V[1]);
complex_face.Face.mIndices[2] = static_cast<unsigned int>(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<SComplexFace>& face_list_cur: complex_faces_toplist)
{
auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
{
size_t rv;
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<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
auto VertexIndex_Replace = [](std::list<SComplexFace>& 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<unsigned int>(pIdx_To);
}
}
};// auto VertexIndex_Replace = [](std::list<SComplexFace>& 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<unsigned int>(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<aiVector3D> vert_arr, texcoord_arr;
std::vector<aiColor4D> 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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(pMeshList.size()));
pMeshList.push_back(tmesh);
}// for(const std::list<SComplexFace>& 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<unsigned int>::const_iterator mit = mesh_idx.begin();
pSceneNode.mNumMeshes = static_cast<unsigned int>(mesh_idx.size());
pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *mit++;
}// if(mesh_idx.size() > 0)
}
void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial& pMaterial)
{
SPP_Material new_mat;
new_mat.ID = pMaterial.ID;
for(const AMFNodeElementBase* mat_child: pMaterial.Child)
{
if(mat_child->Type == AMFNodeElementBase::ENET_Color)
{
new_mat.Color = (AMFColor*)mat_child;
}
else if(mat_child->Type == AMFNodeElementBase::ENET_Metadata)
{
new_mat.Metadata.push_back((AMFMetadata*)mat_child);
}
}// for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
// place converted material to special list
mMaterial_Converted.push_back(new_mat);
}
void AMFImporter::Postprocess_BuildConstellation(AMFConstellation& pConstellation, std::list<aiNode*>& pNodeList) const
{
aiNode* con_node;
std::list<aiNode*> ch_node;
// We will build next hierarchy:
// aiNode as parent (<constellation>) for set of nodes as a children
// |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
// ...
// \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
con_node = new aiNode;
con_node->mName = pConstellation.ID;
// Walk through children and search for instances of another objects, constellations.
for(const AMFNodeElementBase* ne: pConstellation.Child)
{
aiMatrix4x4 tmat;
aiNode* t_node;
aiNode* found_node;
if(ne->Type == AMFNodeElementBase::ENET_Metadata) continue;
if(ne->Type != AMFNodeElementBase::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for conveniance
AMFInstance& als = *((AMFInstance*)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("<constellation> must have at least one <instance>.");
size_t ch_idx = 0;
con_node->mNumChildren = static_cast<unsigned int>(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 <constellation> node to node list
pNodeList.push_back(con_node);
}
void AMFImporter::Postprocess_BuildScene(aiScene* pScene)
{
std::list<aiNode*> node_list;
std::list<aiMesh*> mesh_list;
std::list<AMFMetadata*> 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(<amf>) element
AMFNodeElementBase* root_el = nullptr;
for(AMFNodeElementBase* ne: mNodeElement_List)
{
if(ne->Type != AMFNodeElementBase::ENET_Root) continue;
root_el = ne;
break;
}// for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found.
if(root_el == nullptr) throw DeadlyImportError("Root(<amf>) element not found.");
// after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
// at any moment.
//
// 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
for(const AMFNodeElementBase* root_child: root_el->Child)
{
if(root_child->Type == AMFNodeElementBase::ENET_Material) Postprocess_BuildMaterial(*((AMFMaterial*)root_child));
}
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
//
// 3. <object>
for(const AMFNodeElementBase* root_child: root_el->Child)
{
if(root_child->Type == AMFNodeElementBase::ENET_Object)
{
aiNode* tnode = nullptr;
// for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
Postprocess_BuildNodeAndObject(*((AMFObject*)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 AMFNodeElementBase* root_child: root_el->Child)
{
// 4. <constellation>
if(root_child->Type == AMFNodeElementBase::ENET_Constellation)
{
// <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's.
Postprocess_BuildConstellation(*((AMFConstellation*)root_child), node_list);
}
// 5, <metadata>
if(root_child->Type == AMFNodeElementBase::ENET_Metadata) meta_list.push_back((AMFMetadata*)root_child);
}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// at now we can add collected metadata to root node
Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
//
// Check constellation children
//
// As said in specification:
// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
// And at this step we are checking that relations.
nl_clean_loop:
if(node_list.size() > 1)
{
// walk through all nodes
for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it)
{
// and try to find them in another top nodes.
std::list<aiNode*>::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<aiNode*>::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<aiNode*>::const_iterator nl_it = node_list.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(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 <amf> 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<aiMesh*>::const_iterator ml_it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *ml_it++;
}// if(mesh_list.size() > 0)
//
// Textures
pScene->mNumTextures = static_cast<unsigned int>(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<unsigned int>(tex_convd.Width);
pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(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<unsigned int>(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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -46,12 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <cassert> #include <cassert>
#include <map> #include <map>
#include <memory> #include <memory>
@ -61,7 +60,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/irrXMLWrapper.h>
#include <iomanip> #include <iomanip>
@ -73,12 +71,12 @@ public:
using MatArray = std::vector<aiMaterial *>; using MatArray = std::vector<aiMaterial *>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>; using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
XmlSerializer(XmlReader *xmlReader) : XmlSerializer(XmlParser *xmlParser) :
mMeshes(), mMeshes(),
mMatArray(), mMatArray(),
mActiveMatGroup(99999999), mActiveMatGroup(99999999),
mMatId2MatArray(), mMatId2MatArray(),
xmlReader(xmlReader) { mXmlParser(xmlParser) {
// empty // empty
} }
@ -95,16 +93,21 @@ public:
std::vector<aiNode *> children; std::vector<aiNode *> children;
std::string nodeName; std::string nodeName;
while (ReadToEndElement(D3MF::XmlTag::model)) { XmlNode node = mXmlParser->getRootNode().child("model");
nodeName = xmlReader->getNodeName(); if (node.empty()) {
if (nodeName == D3MF::XmlTag::object) { return;
children.push_back(ReadObject(scene)); }
} else if (nodeName == D3MF::XmlTag::build) { XmlNode resNode = node.child("resources");
for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentNodeName = currentNode.name();
if (currentNodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(currentNode, scene));
} else if (currentNodeName == D3MF::XmlTag::build) {
// //
} else if (nodeName == D3MF::XmlTag::basematerials) { } else if (currentNodeName == D3MF::XmlTag::basematerials) {
ReadBaseMaterials(); ReadBaseMaterials(currentNode);
} else if (nodeName == D3MF::XmlTag::meta) { } else if (currentNodeName == D3MF::XmlTag::meta) {
ReadMetadata(); ReadMetadata(currentNode);
} }
} }
@ -134,38 +137,37 @@ public:
std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials); std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
} }
// create the scenegraph // create the scene-graph
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size()); scene->mRootNode->mNumChildren = static_cast<unsigned int>(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); std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
} }
private: private:
aiNode *ReadObject(aiScene *scene) { aiNode *ReadObject(XmlNode &node, aiScene *scene) {
std::unique_ptr<aiNode> node(new aiNode()); std::unique_ptr<aiNode> nodePtr(new aiNode());
std::vector<unsigned long> meshIds; std::vector<unsigned long> meshIds;
const char *attrib(nullptr);
std::string name, type; std::string name, type;
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str()); pugi::xml_attribute attr = node.attribute(D3MF::XmlTag::id.c_str());
if (nullptr != attrib) { if (!attr.empty()) {
name = attrib; name = attr.as_string();
} }
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str()); attr = node.attribute(D3MF::XmlTag::type.c_str());
if (nullptr != attrib) { if (!attr.empty()) {
type = attrib; type = attr.as_string();
} }
node->mParent = scene->mRootNode; nodePtr->mParent = scene->mRootNode;
node->mName.Set(name); nodePtr->mName.Set(name);
size_t meshIdx = mMeshes.size(); size_t meshIdx = mMeshes.size();
while (ReadToEndElement(D3MF::XmlTag::object)) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) { const std::string &currentName = currentNode.name();
auto mesh = ReadMesh(); if (currentName == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh(currentNode);
mesh->mName.Set(name); mesh->mName.Set(name);
mMeshes.push_back(mesh); mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx)); meshIds.push_back(static_cast<unsigned long>(meshIdx));
@ -173,33 +175,34 @@ private:
} }
} }
node->mNumMeshes = static_cast<unsigned int>(meshIds.size()); nodePtr->mNumMeshes = static_cast<unsigned int>(meshIds.size());
node->mMeshes = new unsigned int[node->mNumMeshes]; nodePtr->mMeshes = new unsigned int[nodePtr->mNumMeshes];
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); std::copy(meshIds.begin(), meshIds.end(), nodePtr->mMeshes);
return node.release(); return nodePtr.release();
} }
aiMesh *ReadMesh() { aiMesh *ReadMesh(XmlNode &node) {
aiMesh *mesh = new aiMesh(); aiMesh *mesh = new aiMesh();
while (ReadToEndElement(D3MF::XmlTag::mesh)) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) { const std::string &currentName = currentNode.name();
ImportVertices(mesh); if (currentName == D3MF::XmlTag::vertices) {
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) { ImportVertices(currentNode, mesh);
ImportTriangles(mesh); } else if (currentName == D3MF::XmlTag::triangles) {
ImportTriangles(currentNode, mesh);
} }
} }
return mesh; return mesh;
} }
void ReadMetadata() { void ReadMetadata(XmlNode &node) {
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str()); pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str());
xmlReader->read(); const std::string name = attribute.as_string();
const std::string value = xmlReader->getNodeData(); const std::string value = node.value();
if (name.empty()) { if (name.empty()) {
return; return;
} }
@ -210,37 +213,36 @@ private:
mMetaData.push_back(entry); mMetaData.push_back(entry);
} }
void ImportVertices(aiMesh *mesh) { void ImportVertices(XmlNode &node, aiMesh *mesh) {
std::vector<aiVector3D> vertices; std::vector<aiVector3D> vertices;
while (ReadToEndElement(D3MF::XmlTag::vertices)) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) { const std::string &currentName = currentNode.name();
vertices.push_back(ReadVertex()); if (currentName == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode));
} }
} }
mesh->mNumVertices = static_cast<unsigned int>(vertices.size()); mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices); std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
} }
aiVector3D ReadVertex() { aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex; aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr);
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr);
vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr); vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr);
vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr);
return vertex; return vertex;
} }
void ImportTriangles(aiMesh *mesh) { void ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces; std::vector<aiFace> faces;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
while (ReadToEndElement(D3MF::XmlTag::triangles)) { const std::string &currentName = currentNode.name();
const std::string nodeName(xmlReader->getNodeName()); if (currentName == D3MF::XmlTag::triangle) {
if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) { faces.push_back(ReadTriangle(currentNode));
faces.push_back(ReadTriangle()); const char *pidToken = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string();
const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
if (nullptr != pidToken) { if (nullptr != pidToken) {
int matIdx(std::atoi(pidToken)); int matIdx(std::atoi(pidToken));
mesh->mMaterialIndex = matIdx; mesh->mMaterialIndex = matIdx;
@ -255,21 +257,21 @@ private:
std::copy(faces.begin(), faces.end(), mesh->mFaces); std::copy(faces.begin(), faces.end(), mesh->mFaces);
} }
aiFace ReadTriangle() { aiFace ReadTriangle(XmlNode &node) {
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str()))); face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string()));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str()))); face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v2.c_str()).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str()))); face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v3.c_str()).as_string()));
return face; return face;
} }
void ReadBaseMaterials() { void ReadBaseMaterials(XmlNode &node) {
std::vector<unsigned int> MatIdArray; std::vector<unsigned int> MatIdArray;
const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str())); const char *baseMaterialId = node.attribute(D3MF::XmlTag::basematerials_id.c_str()).as_string();
if (nullptr != baseMaterialId) { if (nullptr != baseMaterialId) {
unsigned int id = std::atoi(baseMaterialId); unsigned int id = std::atoi(baseMaterialId);
const size_t newMatIdx(mMatArray.size()); const size_t newMatIdx(mMatArray.size());
@ -287,9 +289,7 @@ private:
mMatId2MatArray[mActiveMatGroup] = MatIdArray; mMatId2MatArray[mActiveMatGroup] = MatIdArray;
} }
while (ReadToEndElement(D3MF::XmlTag::basematerials)) { mMatArray.push_back(readMaterialDef(node));
mMatArray.push_back(readMaterialDef());
}
} }
bool parseColor(const char *color, aiColor4D &diffuse) { bool parseColor(const char *color, aiColor4D &diffuse) {
@ -339,19 +339,20 @@ private:
return true; return true;
} }
void assignDiffuseColor(aiMaterial *mat) { void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str()); const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string();
aiColor4D diffuse; aiColor4D diffuse;
if (parseColor(color, diffuse)) { if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
} }
} }
aiMaterial *readMaterialDef() {
aiMaterial *readMaterialDef(XmlNode &node) {
aiMaterial *mat(nullptr); aiMaterial *mat(nullptr);
const char *name(nullptr); const char *name(nullptr);
const std::string nodeName(xmlReader->getNodeName()); const std::string nodeName = node.name();
if (nodeName == D3MF::XmlTag::basematerials_base) { if (nodeName == D3MF::XmlTag::basematerials_base) {
name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str()); name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string();
std::string stdMatName; std::string stdMatName;
aiString matName; aiString matName;
std::string strId(to_string(mActiveMatGroup)); std::string strId(to_string(mActiveMatGroup));
@ -368,40 +369,12 @@ private:
mat = new aiMaterial; mat = new aiMaterial;
mat->AddProperty(&matName, AI_MATKEY_NAME); mat->AddProperty(&matName, AI_MATKEY_NAME);
assignDiffuseColor(mat); assignDiffuseColor(node, mat);
} }
return mat; return mat;
} }
private:
bool ReadToStartElement(const std::string &startTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
return false;
}
bool ReadToEndElement(const std::string &closeTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false;
}
}
ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
private: private:
struct MetaEntry { struct MetaEntry {
std::string name; std::string name;
@ -412,7 +385,7 @@ private:
MatArray mMatArray; MatArray mMatArray;
unsigned int mActiveMatGroup; unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray; MatId2MatArray mMatId2MatArray;
XmlReader *xmlReader; XmlParser *mXmlParser;
}; };
} //namespace D3MF } //namespace D3MF
@ -468,13 +441,12 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
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); D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); XmlParser xmlParser;
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); if (xmlParser.parse(opcPackage.RootStream())) {
D3MF::XmlSerializer xmlSerializer(&xmlParser);
D3MF::XmlSerializer xmlSerializer(xmlReader.get());
xmlSerializer.ImportXml(pScene); xmlSerializer.ImportXml(pScene);
} }
}
} // Namespace Assimp } // Namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -45,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -68,27 +68,22 @@ typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
class OpcPackageRelationshipReader { class OpcPackageRelationshipReader {
public: public:
OpcPackageRelationshipReader(XmlReader *xmlReader) { OpcPackageRelationshipReader(XmlParser &parser) {
while (xmlReader->read()) { XmlNode root = parser.getRootNode();
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && ParseRootNode(root);
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) { }
ParseRootNode(xmlReader);
void ParseRootNode(XmlNode &node) {
ParseAttributes(node);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
std::string name = currentNode.name();
if (name == "Relationships") {
ParseRelationsNode(currentNode);
} }
} }
} }
void ParseRootNode(XmlReader *xmlReader) { void ParseAttributes(XmlNode & /*node*/) {
ParseAttributes(xmlReader);
while (xmlReader->read()) {
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
ParseChildNode(xmlReader);
}
}
}
void ParseAttributes(XmlReader *) {
// empty // empty
} }
@ -99,26 +94,35 @@ public:
return true; return true;
} }
void ParseChildNode(XmlReader *xmlReader) { void ParseRelationsNode(XmlNode &node) {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); if (node.empty()) {
return;
}
relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str()); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str()); std::string name = currentNode.name();
relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str()); if (name == "Relationship") {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string();
relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string();
relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string();
if (validateRels(relPtr)) { if (validateRels(relPtr)) {
m_relationShips.push_back(relPtr); m_relationShips.push_back(relPtr);
} }
} }
}
}
std::vector<OpcPackageRelationshipPtr> m_relationShips; std::vector<OpcPackageRelationshipPtr> m_relationShips;
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr), mZipArchive() { mRootStream(nullptr),
mZipArchive() {
mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
if (!mZipArchive->isOpen()) { if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile + "."); throw DeadlyImportError("Failed to open file ", rFile, ".");
} }
std::vector<std::string> fileList; std::vector<std::string> fileList;
@ -182,17 +186,19 @@ bool D3MFOpcPackage::validate() {
} }
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream)); XmlParser xmlParser;
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get())); if (!xmlParser.parse(stream)) {
return "";
}
OpcPackageRelationshipReader reader(xml.get()); OpcPackageRelationshipReader reader(xmlParser);
auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) { auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) {
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
}); });
if (itr == reader.m_relationShips.end()) { if (itr == reader.m_relationShips.end()) {
throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
} }
return (*itr)->target; return (*itr)->target;

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -44,18 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define D3MFOPCPACKAGE_H #define D3MFOPCPACKAGE_H
#include <memory> #include <memory>
#include <string>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/irrXMLWrapper.h>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem; class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ;
using XmlReaderPtr = std::shared_ptr<XmlReader> ;
struct OpcPackageRelationship { struct OpcPackageRelationship {
std::string id; std::string id;
std::string type; std::string type;
@ -64,7 +59,7 @@ struct OpcPackageRelationship {
class D3MFOpcPackage { class D3MFOpcPackage {
public: public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& file );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate(); bool validate();

View File

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

View File

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

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -60,8 +58,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
/// \var aiImporterDesc AMFImporter::Description
/// Conastant which hold importer description
const aiImporterDesc AMFImporter::Description = { const aiImporterDesc AMFImporter::Description = {
"Additive manufacturing file format(AMF) Importer", "Additive manufacturing file format(AMF) Importer",
"smalcom", "smalcom",
@ -82,7 +78,7 @@ void AMFImporter::Clear() {
mTexture_Converted.clear(); mTexture_Converted.clear();
// Delete all elements // Delete all elements
if (!mNodeElement_List.empty()) { if (!mNodeElement_List.empty()) {
for (CAMFImporter_NodeElement *ne : mNodeElement_List) { for (AMFNodeElementBase *ne : mNodeElement_List) {
delete ne; delete ne;
} }
@ -90,8 +86,18 @@ void AMFImporter::Clear() {
} }
} }
AMFImporter::AMFImporter() AI_NO_EXCEPT :
mNodeElement_Cur(nullptr),
mXmlParser(nullptr),
mUnit(),
mVersion(),
mMaterial_Converted(),
mTexture_Converted() {
// empty
}
AMFImporter::~AMFImporter() { AMFImporter::~AMFImporter() {
if (mReader != nullptr) delete mReader; delete mXmlParser;
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted. // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
Clear(); Clear();
} }
@ -100,10 +106,12 @@ AMFImporter::~AMFImporter() {
/************************************************************ Functions: find set ************************************************************/ /************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
bool AMFImporter::Find_NodeElement(const std::string &pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement **pNodeElement) const { bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const {
for (CAMFImporter_NodeElement *ne : mNodeElement_List) { for (AMFNodeElementBase *ne : mNodeElement_List) {
if ((ne->ID == pID) && (ne->Type == pType)) { if ((ne->ID == pID) && (ne->Type == pType)) {
if (pNodeElement != nullptr) *pNodeElement = ne; if (pNodeElement != nullptr) {
*pNodeElement = ne;
}
return true; return true;
} }
@ -112,12 +120,13 @@ bool AMFImporter::Find_NodeElement(const std::string &pID, const CAMFImporter_No
return false; return false;
} }
bool AMFImporter::Find_ConvertedNode(const std::string &pID, std::list<aiNode *> &pNodeList, aiNode **pNode) const { bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const {
aiString node_name(pID.c_str()); aiString node_name(pID.c_str());
for (aiNode *node : nodeArray) {
for (aiNode *node : pNodeList) {
if (node->mName == node_name) { if (node->mName == node_name) {
if (pNode != nullptr) *pNode = node; if (pNode != nullptr) {
*pNode = node;
}
return true; return true;
} }
@ -129,7 +138,9 @@ bool AMFImporter::Find_ConvertedNode(const std::string &pID, std::list<aiNode *>
bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const { bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const {
for (const SPP_Material &mat : mMaterial_Converted) { for (const SPP_Material &mat : mMaterial_Converted) {
if (mat.ID == pID) { if (mat.ID == pID) {
if (pConvertedMaterial != nullptr) *pConvertedMaterial = &mat; if (pConvertedMaterial != nullptr) {
*pConvertedMaterial = &mat;
}
return true; return true;
} }
@ -142,148 +153,38 @@ bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Mater
/************************************************************ Functions: throw set ***********************************************************/ /************************************************************ Functions: throw set ***********************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
void AMFImporter::Throw_CloseNotFound(const std::string &pNode) { void AMFImporter::Throw_CloseNotFound(const std::string &nodeName) {
throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt."); throw DeadlyImportError("Close tag for node <" + nodeName + "> not found. Seems file is corrupt.");
} }
void AMFImporter::Throw_IncorrectAttr(const std::string &pAttrName) { void AMFImporter::Throw_IncorrectAttr(const std::string &nodeName, const std::string &attrName) {
throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\"."); throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + attrName + "\".");
} }
void AMFImporter::Throw_IncorrectAttrValue(const std::string &pAttrName) { void AMFImporter::Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &attrName) {
throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value."); throw DeadlyImportError("Attribute \"" + attrName + "\" in node <" + nodeName + "> has incorrect value.");
} }
void AMFImporter::Throw_MoreThanOnceDefined(const std::string &pNodeType, const std::string &pDescription) { void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) {
throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription); throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription);
} }
void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
throw DeadlyImportError("Not found node with name \"" + pID + "\"."); throw DeadlyImportError("Not found node with name \"", pID, "\".");
} }
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
/************************************************************* Functions: XML set ************************************************************/ /************************************************************* Functions: XML set ************************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
void AMFImporter::XML_CheckNode_MustHaveChildren() { void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) {
if (mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children."); if (node.children().begin() == node.children().end()) {
} throw DeadlyImportError(std::string("Node <") + node.name() + "> 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) { bool AMFImporter::XML_SearchNode(const std::string &nodeName) {
while (mReader->read()) { return nullptr != mXmlParser->findNode(nodeName);
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) { void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
@ -362,29 +263,33 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
} }
void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AMF file " + pFile + "."); throw DeadlyImportError("Failed to open AMF file ", pFile, ".");
} }
// generate a XML reader for it mXmlParser = new XmlParser();
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get())); if (!mXmlParser->parse(file.get())) {
mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); delete mXmlParser;
if (!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
// }
// start reading
// search for root tag <amf>
if (XML_SearchNode("amf"))
ParseNode_Root();
else
throw DeadlyImportError("Root node \"amf\" not found.");
delete mReader; // Start reading, search for root tag <amf>
// restore old XMLreader if (!mXmlParser->hasNode("amf")) {
mReader = OldReader; throw DeadlyImportError("Root node \"amf\" not found.");
}
ParseNode_Root();
} // namespace Assimp
void AMFImporter::ParseHelper_Node_Enter(AMFNodeElementBase *node) {
mNodeElement_Cur->Child.push_back(node); // add new element to current element child list.
mNodeElement_Cur = node;
}
void AMFImporter::ParseHelper_Node_Exit() {
if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
} }
// <amf // <amf
@ -395,54 +300,48 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
// Root XML element. // Root XML element.
// Multi elements - No. // Multi elements - No.
void AMFImporter::ParseNode_Root() { void AMFImporter::ParseNode_Root() {
std::string unit, version; AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement *ne(nullptr); XmlNode *root = mXmlParser->findNode("amf");
if (nullptr == root) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
XmlNode node = *root;
mUnit = node.attribute("unit").as_string();
mVersion = node.attribute("version").as_string();
// Read attributes for node <amf>. // Read attributes for node <amf>.
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 // Check attributes
if (!mUnit.empty()) { if (!mUnit.empty()) {
if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit"); if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) {
Throw_IncorrectAttrValue("unit", mUnit);
}
} }
// create root node element. // create root node element.
ne = new CAMFImporter_NodeElement_Root(nullptr); ne = new AMFRoot(nullptr);
mNodeElement_Cur = ne; // set first "current" element mNodeElement_Cur = ne; // set first "current" element
// and assign attribute's values // and assign attribute's values
((CAMFImporter_NodeElement_Root *)ne)->Unit = unit; ((AMFRoot *)ne)->Unit = mUnit;
((CAMFImporter_NodeElement_Root *)ne)->Version = version; ((AMFRoot *)ne)->Version = mVersion;
// Check for child nodes // Check for child nodes
if (!mReader->isEmptyElement()) { for (XmlNode &currentNode : node.children() ) {
MACRO_NODECHECK_LOOPBEGIN("amf"); const std::string currentName = currentNode.name();
if (XML_CheckNode_NameEqual("object")) { if (currentName == "object") {
ParseNode_Object(); ParseNode_Object(currentNode);
continue; } else if (currentName == "material") {
ParseNode_Material(currentNode);
} else if (currentName == "texture") {
ParseNode_Texture(currentNode);
} else if (currentName == "constellation") {
ParseNode_Constellation(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
} }
if (XML_CheckNode_NameEqual("material")) { mNodeElement_Cur = ne;
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 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. mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
} }
@ -453,40 +352,34 @@ void AMFImporter::ParseNode_Root() {
// A collection of objects or constellations with specific relative locations. // A collection of objects or constellations with specific relative locations.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Constellation() { void AMFImporter::ParseNode_Constellation(XmlNode &node) {
std::string id; std::string id;
CAMFImporter_NodeElement *ne(nullptr); id = node.attribute("id").as_string();
// Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new grouping object. // create and if needed - define new grouping object.
ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
CAMFImporter_NodeElement_Constellation &als = *((CAMFImporter_NodeElement_Constellation *)ne); // alias for convenience AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
if (!id.empty()) als.ID = id;
// Check for child nodes // Check for child nodes
if (!mReader->isEmptyElement()) { if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("constellation"); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if (XML_CheckNode_NameEqual("instance")) { std::string name = currentNode.name();
ParseNode_Instance(); if (name == "instance") {
continue; ParseNode_Instance(currentNode);
} else if (name == "metadata") {
ParseNode_Metadata(currentNode);
} }
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
} }
MACRO_NODECHECK_LOOPEND("constellation");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement()) } else {
else { mNodeElement_Cur->Child.push_back(ne);
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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -497,47 +390,43 @@ void AMFImporter::ParseNode_Constellation() {
// A collection of objects or constellations with specific relative locations. // A collection of objects or constellations with specific relative locations.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Instance() { void AMFImporter::ParseNode_Instance(XmlNode &node) {
std::string objectid; AMFNodeElementBase *ne(nullptr);
CAMFImporter_NodeElement *ne(nullptr);
// Read attributes for node <constellation>. // Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG; std::string objectid = node.attribute("objectid").as_string();
MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// used object id must be defined, check that. // used object id must be defined, check that.
if (objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined."); if (objectid.empty()) {
throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
}
// create and define new grouping object. // create and define new grouping object.
ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur); ne = new AMFInstance(mNodeElement_Cur);
AMFInstance &als = *((AMFInstance *)ne);
CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience
als.ObjectID = objectid; 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); if (!node.empty()) {
als.Rotation.Set(0, 0, 0);
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("instance"); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x); const std::string &currentName = currentNode.name();
MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y); if (currentName == "deltax") {
MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z); als.Delta.x = (ai_real)std::atof(currentNode.value());
MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x); } else if (currentName == "deltay") {
MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y); als.Delta.y = (ai_real)std::atof(currentNode.value());
MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z); } else if (currentName == "deltaz") {
MACRO_NODECHECK_LOOPEND("instance"); als.Delta.z = (ai_real)std::atof(currentNode.value());
} else if (currentName == "rx") {
als.Delta.x = (ai_real)std::atof(currentNode.value());
} else if (currentName == "ry") {
als.Delta.y = (ai_real)std::atof(currentNode.value());
} else if (currentName == "rz") {
als.Delta.z = (ai_real)std::atof(currentNode.value());
}
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
// also convert degrees to radians. } else {
als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f; mNodeElement_Cur->Child.push_back(ne);
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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -549,51 +438,38 @@ void AMFImporter::ParseNode_Instance() {
// An object definition. // An object definition.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Object() { void AMFImporter::ParseNode_Object(XmlNode &node) {
std::string id; AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement *ne(nullptr);
// Read attributes for node <object>. // Read attributes for node <object>.
MACRO_ATTRREAD_LOOPBEG; std::string id = node.attribute("id").as_string();
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new geometry object. // create and if needed - define new geometry object.
ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur); ne = new AMFObject(mNodeElement_Cur);
CAMFImporter_NodeElement_Object &als = *((CAMFImporter_NodeElement_Object *)ne); // alias for convenience AMFObject &als = *((AMFObject *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
if (!id.empty()) als.ID = id;
// Check for child nodes // Check for child nodes
if (!mReader->isEmptyElement()) { if (!node.empty()) {
bool col_read = false;
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("object"); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if (XML_CheckNode_NameEqual("color")) { const std::string &currentName = currentNode.name();
// Check if color already defined for object. if (currentName == "color") {
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>."); ParseNode_Color(currentNode);
// read data and set flag about it } else if (currentName == "mesh") {
ParseNode_Color(); ParseNode_Mesh(currentNode);
col_read = true; } else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
continue;
} }
if (XML_CheckNode_NameEqual("mesh")) {
ParseNode_Mesh();
continue;
} }
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("object");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement()) } else {
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element 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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -616,28 +492,20 @@ void AMFImporter::ParseNode_Object() {
// "Revision" - specifies the revision of the entity // "Revision" - specifies the revision of the entity
// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system // "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) // "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() { void AMFImporter::ParseNode_Metadata(XmlNode &node) {
std::string type, value; AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement *ne(nullptr);
std::string type = node.attribute("type").as_string(), value;
XmlParser::getValueAsString(node, value);
// read attribute // read attribute
MACRO_ATTRREAD_LOOPBEG; ne = new AMFMetadata(mNodeElement_Cur);
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); ((AMFMetadata *)ne)->Type = type;
MACRO_ATTRREAD_LOOPEND; ((AMFMetadata *)ne)->Value = value;
// 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_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. 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 { bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
@ -645,9 +513,8 @@ bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool p
return true; return true;
} }
if (!extension.length() || pCheckSig) { if (extension.empty() || pCheckSig) {
const char *tokens[] = { "<amf" }; const char *tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -54,11 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AMFImporter_Node.hpp" #include "AMFImporter_Node.hpp"
// Header files, Assimp. // Header files, Assimp.
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include "assimp/types.h" #include "assimp/types.h"
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/irrXMLWrapper.h> #include <assimp/XmlParser.h>
#include <assimp/importerdesc.h>
#include <assimp/DefaultLogger.hpp>
// Header files, stdlib. // Header files, stdlib.
#include <set> #include <set>
@ -103,7 +101,6 @@ class AMFImporter : public BaseImporter {
private: private:
struct SPP_Material; // forward declaration struct SPP_Material; // forward declaration
/// \struct SPP_Composite
/// Data type for post-processing step. More suitable container for part of material's composition. /// Data type for post-processing step. More suitable container for part of material's composition.
struct SPP_Composite { struct SPP_Composite {
SPP_Material *Material; ///< Pointer to material - part of composition. SPP_Material *Material; ///< Pointer to material - part of composition.
@ -114,8 +111,8 @@ private:
/// Data type for post-processing step. More suitable container for material. /// Data type for post-processing step. More suitable container for material.
struct SPP_Material { struct SPP_Material {
std::string ID; ///< Material ID. std::string ID; ///< Material ID.
std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material. std::list<AMFMetadata *> Metadata; ///< Metadata of material.
CAMFImporter_NodeElement_Color* Color;///< Color of material. AMFColor *Color; ///< Color of material.
std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another. std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate. /// Return color calculated for specified coordinate.
@ -138,56 +135,24 @@ private:
/// Data type for post-processing step. Contain face data. /// Data type for post-processing step. Contain face data.
struct SComplexFace { struct SComplexFace {
aiFace Face; ///< Face vertices. aiFace Face; ///< Face vertices.
const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face. const AMFColor *Color; ///< Face color. Equal to nullptr if color is not set for the face.
const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
}; };
using AMFMetaDataArray = std::vector<AMFMetadata*>;
using MeshArray = std::vector<aiMesh*>;
using NodeArray = std::vector<aiNode*>;
/// Clear all temporary data. /// Clear all temporary data.
void Clear(); void Clear();
/***********************************************/
/************* Functions: find set *************/
/***********************************************/
/// Find specified node element in node elements list ( \ref mNodeElement_List).
/// \param [in] pID - ID(name) of requested node element.
/// \param [in] pType - type of node element.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node element is found, else - false.
bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const;
/// Find requested aiNode in node list.
/// \param [in] pID - ID(name) of requested node.
/// \param [in] pNodeList - list of nodes where to find the node.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node is found, else - false.
bool Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const;
/// Find material in list for converted materials. Use at postprocessing step.
/// \param [in] pID - material ID.
/// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material).
/// \return true - if the material is found, else - false.
bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const;
/// Find texture in list of converted textures. Use at postprocessing step,
/// \param [in] pID_R - ID of source "red" texture.
/// \param [in] pID_G - ID of source "green" texture.
/// \param [in] pID_B - ID of source "blue" texture.
/// \param [in] pID_A - ID of source "alpha" texture. Use empty string to find RGB-texture.
/// \param [out] pConvertedTextureIndex - pointer where index in list of found texture will be written. If equivalent to nullptr then nothing will be
/// written.
/// \return true - if the texture is found, else - false.
bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A,
uint32_t* pConvertedTextureIndex = nullptr) const;
/// Get data stored in <vertices> and place it to arrays. /// Get data stored in <vertices> and place it to arrays.
/// \param [in] pNodeElement - reference to node element which kept <object> data. /// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>. /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>.
/// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array /// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array
/// contain nullptr. /// contain nullptr.
void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray, void PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const; std::vector<AMFColor *> &pVertexColorArray) const;
/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
@ -209,13 +174,13 @@ private:
/// Check if child elements of node element is metadata and add it to scene node. /// Check if child elements of node element is metadata and add it to scene node.
/// \param [in] pMetadataList - reference to list with collected metadata. /// \param [in] pMetadataList - reference to list with collected metadata.
/// \param [out] pSceneNode - scene node in which metadata will be added. /// \param [out] pSceneNode - scene node in which metadata will be added.
void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const; void Postprocess_AddMetadata(const AMFMetaDataArray &pMetadataList, aiNode &pSceneNode) const;
/// To create aiMesh and aiNode for it from <object>. /// To create aiMesh and aiNode for it from <object>.
/// \param [in] pNodeElement - reference to node element which kept <object> data. /// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \param [out] pMeshList - reference to a list with all aiMesh of the scene. /// \param [out] meshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - pointer to place where new aiNode will be created. /// \param [out] pSceneNode - pointer to place where new aiNode will be created.
void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode); void Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode);
/// Create mesh for every <volume> in <mesh>. /// Create mesh for every <volume> in <mesh>.
/// \param [in] pNodeElement - reference to node element which kept <mesh> data. /// \param [in] pNodeElement - reference to node element which kept <mesh> data.
@ -226,116 +191,23 @@ private:
/// \param [in] pMaterialList - reference to a list with defined materials. /// \param [in] pMaterialList - reference to a list with defined materials.
/// \param [out] pMeshList - reference to a list with all aiMesh of the scene. /// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's. /// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray, void Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor, const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor,
std::list<aiMesh*>& pMeshList, aiNode& pSceneNode); MeshArray &pMeshList, aiNode &pSceneNode);
/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material. /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material. /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial); void Postprocess_BuildMaterial(const AMFMaterial &pMaterial);
/// Create and add to aiNode's list new part of scene graph defined by <constellation>. /// Create and add to aiNode's list new part of scene graph defined by <constellation>.
/// \param [in] pConstellation - reference to <constellation> node. /// \param [in] pConstellation - reference to <constellation> node.
/// \param [out] pNodeList - reference to aiNode's list. /// \param [out] nodeArray - reference to aiNode's list.
void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const; void Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const;
/// Build Assimp scene graph in aiScene from collected data. /// Build Assimp scene graph in aiScene from collected data.
/// \param [out] pScene - pointer to aiScene where tree will be built. /// \param [out] pScene - pointer to aiScene where tree will be built.
void Postprocess_BuildScene(aiScene *pScene); void Postprocess_BuildScene(aiScene *pScene);
/// Call that function when close tag of node not found and exception must be raised.
/// E.g.:
/// <amf>
/// <object>
/// </amf> <!--- object not closed --->
/// \throw DeadlyImportError.
/// \param [in] pNode - node name in which exception happened.
void Throw_CloseNotFound(const std::string& pNode);
/// Call that function when attribute name is incorrect and exception must be raised.
/// \param [in] pAttrName - attribute name.
/// \throw DeadlyImportError.
void Throw_IncorrectAttr(const std::string& pAttrName);
/// Call that function when attribute value is incorrect and exception must be raised.
/// \param [in] pAttrName - attribute name.
/// \throw DeadlyImportError.
void Throw_IncorrectAttrValue(const std::string& pAttrName);
/// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised.
/// E.g.:
/// <object>
/// <color>... <!--- color defined --->
/// <color>... <!--- color defined again --->
/// </object>
/// \throw DeadlyImportError.
/// \param [in] pNodeType - type of node which defined one more time.
/// \param [in] pDescription - message about error. E.g. what the node defined while exception raised.
void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription);
/// Call that function when referenced element ID are not found in graph and exception must be raised.
/// \param [in] pID - ID of of element which not found.
/// \throw DeadlyImportError.
void Throw_ID_NotFound(const std::string& pID) const;
/// Check if current node have children: <node>...</node>. If not then exception will throwed.
void XML_CheckNode_MustHaveChildren();
/// Check if current node name is equal to pNodeName.
/// \param [in] pNodeName - name for checking.
/// return true if current node name is equal to pNodeName, else - false.
bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
/// \param [in] pParentNodeName - parent node name. Used for reporting.
void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName);
/// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end.
/// \param [in] pNodeName - requested node name.
/// return true - if node is found, else - false.
bool XML_SearchNode(const std::string& pNodeName);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx);
/// Read node value.
/// \return read data.
float XML_ReadNode_GetVal_AsFloat();
/// Read node value.
/// \return read data.
uint32_t XML_ReadNode_GetVal_AsU32();
/// Read node value.
/// \return read data.
void XML_ReadNode_GetVal_AsString(std::string& pValue);
/// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called.
/// \param [in] pNode - new current node.
void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode);
/// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin.
void ParseHelper_Node_Exit();
/// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it
/// must be converted to right form - "0.xxx".
/// \param [in] pInStr - pointer to input string which can contain incorrect form of values.
/// \param [out[ pOutString - output string with right form of values.
void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString);
/// Decode Base64-encoded data. /// Decode Base64-encoded data.
/// \param [in] pInputBase64 - reference to input Base64-encoded string. /// \param [in] pInputBase64 - reference to input Base64-encoded string.
/// \param [out] pOutputData - reference to output array for decoded data. /// \param [out] pOutputData - reference to output array for decoded data.
@ -345,58 +217,54 @@ private:
void ParseNode_Root(); void ParseNode_Root();
/// Parse <constellation> node of the file. /// Parse <constellation> node of the file.
void ParseNode_Constellation(); void ParseNode_Constellation(XmlNode &node);
/// Parse <instance> node of the file. /// Parse <instance> node of the file.
void ParseNode_Instance(); void ParseNode_Instance(XmlNode &node);
/// Parse <material> node of the file. /// Parse <material> node of the file.
void ParseNode_Material(); void ParseNode_Material(XmlNode &node);
/// Parse <metadata> node. /// Parse <metadata> node.
void ParseNode_Metadata(); void ParseNode_Metadata(XmlNode &node);
/// Parse <object> node of the file. /// Parse <object> node of the file.
void ParseNode_Object(); void ParseNode_Object(XmlNode &node);
/// Parse <texture> node of the file. /// Parse <texture> node of the file.
void ParseNode_Texture(); void ParseNode_Texture(XmlNode &node);
/// Parse <coordinates> node of the file. /// Parse <coordinates> node of the file.
void ParseNode_Coordinates(); void ParseNode_Coordinates(XmlNode &node);
/// Parse <edge> node of the file. /// Parse <edge> node of the file.
void ParseNode_Edge(); void ParseNode_Edge(XmlNode &node);
/// Parse <mesh> node of the file. /// Parse <mesh> node of the file.
void ParseNode_Mesh(); void ParseNode_Mesh(XmlNode &node);
/// Parse <triangle> node of the file. /// Parse <triangle> node of the file.
void ParseNode_Triangle(); void ParseNode_Triangle(XmlNode &node);
/// Parse <vertex> node of the file. /// Parse <vertex> node of the file.
void ParseNode_Vertex(); void ParseNode_Vertex(XmlNode &node);
/// Parse <vertices> node of the file. /// Parse <vertices> node of the file.
void ParseNode_Vertices(); void ParseNode_Vertices(XmlNode &node);
/// Parse <volume> node of the file. /// Parse <volume> node of the file.
void ParseNode_Volume(); void ParseNode_Volume(XmlNode &node);
/// Parse <color> node of the file. /// Parse <color> node of the file.
void ParseNode_Color(); void ParseNode_Color(XmlNode &node);
/// Parse <texmap> of <map> node of the file. /// Parse <texmap> of <map> node of the file.
/// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>. /// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>.
void ParseNode_TexMap(const bool pUseOldName = false); void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false);
public: public:
/// Default constructor. /// Default constructor.
AMFImporter() AI_NO_EXCEPT AMFImporter() AI_NO_EXCEPT;
: mNodeElement_Cur(nullptr)
, mReader(nullptr) {
// empty
}
/// Default destructor. /// Default destructor.
~AMFImporter(); ~AMFImporter();
@ -406,25 +274,36 @@ public:
/// \param [in] pFile - name of file to be parsed. /// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object. /// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile(const std::string &pFile, IOSystem *pIOHandler); void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
void ParseHelper_Node_Enter(AMFNodeElementBase *child);
void ParseHelper_Node_Exit();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const; bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
void GetExtensionList(std::set<std::string> &pExtensionList); void GetExtensionList(std::set<std::string> &pExtensionList);
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
const aiImporterDesc *GetInfo() const; const aiImporterDesc *GetInfo() const;
bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
void Throw_CloseNotFound(const std::string &nodeName);
void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName);
void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName);
void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription);
void Throw_ID_NotFound(const std::string &pID) const;
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
bool XML_SearchNode(const std::string &nodeName);
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
AMFImporter(const AMFImporter &pScene) = delete; AMFImporter(const AMFImporter &pScene) = delete;
AMFImporter &operator=(const AMFImporter &pScene) = delete; AMFImporter &operator=(const AMFImporter &pScene) = delete;
private: private:
static const aiImporterDesc Description; static const aiImporterDesc Description;
CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element. AMFNodeElementBase *mNodeElement_Cur; ///< Current element.
std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph. std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph.
irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object XmlParser *mXmlParser;
std::string mUnit; std::string mUnit;
std::string mVersion;
std::list<SPP_Material> mMaterial_Converted; ///< List of converted materials for postprocessing step. std::list<SPP_Material> mMaterial_Converted; ///< List of converted materials for postprocessing step.
std::list<SPP_Texture> mTexture_Converted; ///< List of converted textures for postprocessing step. std::list<SPP_Texture> mTexture_Converted; ///< List of converted textures for postprocessing step.
}; };
} // namespace Assimp } // namespace Assimp

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -51,48 +49,47 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp" #include "AMFImporter_Macro.hpp"
namespace Assimp #include <assimp/ParsingUtils.h>
{
namespace Assimp {
// <mesh> // <mesh>
// </mesh> // </mesh>
// A 3D mesh hull. // A 3D mesh hull.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <object>. // Parent element - <object>.
void AMFImporter::ParseNode_Mesh() void AMFImporter::ParseNode_Mesh(XmlNode &node) {
{ AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement* ne;
// create new mesh object. // create new mesh object.
ne = new CAMFImporter_NodeElement_Mesh(mNodeElement_Cur); ne = new AMFMesh(mNodeElement_Cur);
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement()) if (0 != ASSIMP_stricmp(node.name(), "mesh")) {
{ return;
bool vert_read = false; }
bool found_verts = false, found_volumes = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("mesh"); pugi::xml_node vertNode = node.child("vertices");
if(XML_CheckNode_NameEqual("vertices")) if (!vertNode.empty()) {
{ ParseNode_Vertices(vertNode);
// Check if data already defined. found_verts = true;
if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
// read data and set flag about it
ParseNode_Vertices();
vert_read = true;
continue;
} }
if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; } pugi::xml_node volumeNode = node.child("volume");
MACRO_NODECHECK_LOOPEND("mesh"); if (!volumeNode.empty()) {
ParseNode_Volume(volumeNode);
found_volumes = true;
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement()) }
else
{ if (!found_verts && !found_volumes) {
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element mNodeElement_Cur->Child.push_back(ne);
} // if(!mReader->isEmptyElement()) else } // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. // and to node element list because its a new object in graph.
mNodeElement_List.push_back(ne);
} }
// <vertices> // <vertices>
@ -100,23 +97,21 @@ CAMFImporter_NodeElement* ne;
// The list of vertices to be used in defining triangles. // The list of vertices to be used in defining triangles.
// Multi elements - No. // Multi elements - No.
// Parent element - <mesh>. // Parent element - <mesh>.
void AMFImporter::ParseNode_Vertices() void AMFImporter::ParseNode_Vertices(XmlNode &node) {
{ AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement* ne;
// create new mesh object. // create new mesh object.
ne = new CAMFImporter_NodeElement_Vertices(mNodeElement_Cur); ne = new AMFVertices(mNodeElement_Cur);
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement()) pugi::xml_node vertexNode = node.child("vertex");
{ if (!vertexNode.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertices");
if(XML_CheckNode_NameEqual("vertex")) { ParseNode_Vertex(); continue; } ParseNode_Vertex(vertexNode);
MACRO_NODECHECK_LOOPEND("vertices");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else } else {
{
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else } // if(!mReader->isEmptyElement()) else
@ -128,50 +123,33 @@ CAMFImporter_NodeElement* ne;
// A vertex to be referenced in triangles. // A vertex to be referenced in triangles.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <vertices>. // Parent element - <vertices>.
void AMFImporter::ParseNode_Vertex() void AMFImporter::ParseNode_Vertex(XmlNode &node) {
{ AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement* ne;
// create new mesh object. // create new mesh object.
ne = new CAMFImporter_NodeElement_Vertex(mNodeElement_Cur); ne = new AMFVertex(mNodeElement_Cur);
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement()) pugi::xml_node colorNode = node.child("color");
{
bool col_read = false; bool col_read = false;
bool coord_read = false; bool coord_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertex"); if (!colorNode.empty()) {
if(XML_CheckNode_NameEqual("color")) ParseNode_Color(colorNode);
{
// Check if data already defined.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
continue;
} }
pugi::xml_node coordNode = node.child("coordinates");
if(XML_CheckNode_NameEqual("coordinates")) if (!coordNode.empty()) {
{ ParseNode_Coordinates(coordNode);
// Check if data already defined.
if(coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Coordinates();
coord_read = true; coord_read = true;
}
continue; ParseHelper_Node_Exit();
} }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } if (!coord_read && !col_read) {
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 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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -186,35 +164,30 @@ CAMFImporter_NodeElement* ne;
// <x>, <y>, <z> // <x>, <y>, <z>
// Multi elements - No. // Multi elements - No.
// X, Y, or Z coordinate, respectively, of a vertex position in space. // X, Y, or Z coordinate, respectively, of a vertex position in space.
void AMFImporter::ParseNode_Coordinates() void AMFImporter::ParseNode_Coordinates(XmlNode &node) {
{ AMFNodeElementBase *ne = nullptr;
CAMFImporter_NodeElement* ne;
// create new color object. // create new color object.
ne = new CAMFImporter_NodeElement_Coordinates(mNodeElement_Cur); ne = new AMFCoordinates(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 };
AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("coordinates"); for (XmlNode &currentNode : node.children()) {
MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x); const std::string &currentName = currentNode.name();
MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y); if (currentName == "X") {
MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z); XmlParser::getValueAsFloat(currentNode, als.Coordinate.x);
MACRO_NODECHECK_LOOPEND("coordinates"); } else if (currentName == "Y") {
ParseHelper_Node_Exit(); XmlParser::getValueAsFloat(currentNode, als.Coordinate.y);
// check that all components was defined } else if (currentName == "Z") {
if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined."); XmlParser::getValueAsFloat(currentNode, als.Coordinate.z);
}
}
}// if(!mReader->isEmptyElement()) ParseHelper_Node_Exit();
else } else {
{ mNodeElement_Cur->Child.push_back(ne);
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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -228,50 +201,39 @@ CAMFImporter_NodeElement* ne;
// Defines a volume from the established vertex list. // Defines a volume from the established vertex list.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <mesh>. // Parent element - <mesh>.
void AMFImporter::ParseNode_Volume() void AMFImporter::ParseNode_Volume(XmlNode &node) {
{
std::string materialid; std::string materialid;
std::string type; std::string type;
CAMFImporter_NodeElement* ne; AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur);
// Read attributes for node <color>. // Read attributes for node <color>.
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 // and assign read data
((CAMFImporter_NodeElement_Volume*)ne)->MaterialID = materialid;
((CAMFImporter_NodeElement_Volume*)ne)->Type = type; ((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string();
((AMFVolume *)ne)->Type = type;
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false; bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("volume"); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if(XML_CheckNode_NameEqual("color")) const std::string currentName = currentNode.name();
{ if (currentName == "color") {
// Check if data already defined. if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <volume>.");
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <volume>."); ParseNode_Color(currentNode);
// read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
} else if (currentName == "triangle") {
continue; ParseNode_Triangle(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
} else if (currentName == "volume") {
ParseNode_Metadata(currentNode);
}
} }
if(XML_CheckNode_NameEqual("triangle")) { ParseNode_Triangle(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("volume");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement()) } else {
else
{
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element 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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -286,68 +248,38 @@ CAMFImporter_NodeElement* ne;
// <v1>, <v2>, <v3> // <v1>, <v2>, <v3>
// Multi elements - No. // Multi elements - No.
// Index of the desired vertices in a triangle or edge. // Index of the desired vertices in a triangle or edge.
void AMFImporter::ParseNode_Triangle() void AMFImporter::ParseNode_Triangle(XmlNode &node) {
{ AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur);
CAMFImporter_NodeElement* ne;
// create new color object. // create new triangle object.
ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
CAMFImporter_NodeElement_Triangle& als = *((CAMFImporter_NodeElement_Triangle*)ne);// alias for convenience AMFTriangle &als = *((AMFTriangle *)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 };
bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("triangle"); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
if(XML_CheckNode_NameEqual("color")) const std::string currentName = currentNode.name();
{ if (currentName == "color") {
// Check if data already defined. if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <triangle>.");
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <triangle>."); ParseNode_Color(currentNode);
// read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
} else if (currentName == "texmap") {
continue; ParseNode_TexMap(currentNode);
} else if (currentName == "map") {
ParseNode_TexMap(currentNode, true);
} else if (currentName == "v1") {
als.V[0] = std::atoi(currentNode.value());
} else if (currentName == "v2") {
als.V[1] = std::atoi(currentNode.value());
} else if (currentName == "v3") {
als.V[2] = std::atoi(currentNode.value());
} }
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 <triangle>.");
// 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 <triangle>.");
// 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(); ParseHelper_Node_Exit();
// check that all components was defined } else {
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 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. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -49,10 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
namespace Assimp namespace Assimp {
{
// <color // <color
// profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>. // profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>.
@ -68,34 +64,34 @@ namespace Assimp
// Multi elements - No. // Multi elements - No.
// Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The // Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
// values can be specified as constants, or as a formula depending on the coordinates. // values can be specified as constants, or as a formula depending on the coordinates.
void AMFImporter::ParseNode_Color() { void AMFImporter::ParseNode_Color(XmlNode &node) {
std::string profile; std::string profile = node.attribute("profile").as_string();
CAMFImporter_NodeElement* ne;
// Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("profile", profile, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create new color object. // create new color object.
ne = new CAMFImporter_NodeElement_Color(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFColor(mNodeElement_Cur);
AMFColor& als = *((AMFColor*)ne);// alias for convenience
CAMFImporter_NodeElement_Color& als = *((CAMFImporter_NodeElement_Color*)ne);// alias for convenience
als.Profile = profile; als.Profile = profile;
// Check for child nodes if (!node.empty()) {
if(!mReader->isEmptyElement())
{
bool read_flag[4] = { false, false, false, false };
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("color"); bool read_flag[4] = { false, false, false, false };
MACRO_NODECHECK_READCOMP_F("r", read_flag[0], als.Color.r); for (pugi::xml_node &child : node.children()) {
MACRO_NODECHECK_READCOMP_F("g", read_flag[1], als.Color.g); std::string name = child.name();
MACRO_NODECHECK_READCOMP_F("b", read_flag[2], als.Color.b); if ( name == "r") {
MACRO_NODECHECK_READCOMP_F("a", read_flag[3], als.Color.a); read_flag[0] = true;
MACRO_NODECHECK_LOOPEND("color"); XmlParser::getValueAsFloat(child, als.Color.r);
} else if (name == "g") {
read_flag[1] = true;
XmlParser::getValueAsFloat(child, als.Color.g);
} else if (name == "b") {
read_flag[2] = true;
XmlParser::getValueAsFloat(child, als.Color.b);
} else if (name == "a") {
read_flag[3] = true;
XmlParser::getValueAsFloat(child, als.Color.a);
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
}
// check that all components was defined // check that all components was defined
if (!(read_flag[0] && read_flag[1] && read_flag[2])) { if (!(read_flag[0] && read_flag[1] && read_flag[2])) {
throw DeadlyImportError("Not all color components are defined."); throw DeadlyImportError("Not all color components are defined.");
@ -105,9 +101,7 @@ void AMFImporter::ParseNode_Color() {
if (!read_flag[3]) { if (!read_flag[3]) {
als.Color.a = 1; als.Color.a = 1;
} }
} } else {
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
} }
@ -122,45 +116,25 @@ void AMFImporter::ParseNode_Color() {
// An available material. // An available material.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Material() { void AMFImporter::ParseNode_Material(XmlNode &node) {
std::string id; // create new object and assign read data
CAMFImporter_NodeElement* ne; std::string id = node.attribute("id").as_string();
AMFNodeElementBase *ne = new AMFMaterial(mNodeElement_Cur);
// Read attributes for node <color>. ((AMFMaterial*)ne)->ID = id;
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create new object.
ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur);
// and assign read data
((CAMFImporter_NodeElement_Material*)ne)->ID = id;
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement()) if (!node.empty()) {
{
bool col_read = false;
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("material"); for (pugi::xml_node &child : node.children()) {
if(XML_CheckNode_NameEqual("color")) const std::string name = child.name();
{ if (name == "color") {
// Check if data already defined. ParseNode_Color(child);
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <material>."); } else if (name == "metadata") {
// read data and set flag about it ParseNode_Metadata(child);
ParseNode_Color(); }
col_read = true;
continue;
} }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("material");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} } else {
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
} }
@ -183,51 +157,41 @@ void AMFImporter::ParseNode_Material() {
// then layer by layer. // then layer by layer.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Texture() void AMFImporter::ParseNode_Texture(XmlNode &node) {
{ std::string id = node.attribute("id").as_string();
std::string id; uint32_t width = node.attribute("width").as_uint();
uint32_t width = 0; uint32_t height = node.attribute("height").as_uint();
uint32_t height = 0; uint32_t depth = node.attribute("depth").as_uint();
uint32_t depth = 1; std::string type = node.attribute("type").as_string();
std::string type; bool tiled = node.attribute("tiled").as_bool();
bool tiled = false;
std::string enc64_data;
// Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("width", width, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("depth", depth, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("tiled", tiled, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// create new texture object. // create new texture object.
CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFTexture(mNodeElement_Cur);
CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience AMFTexture& als = *((AMFTexture*)ne);// alias for convenience
// Check for child nodes if (node.empty()) {
if (!mReader->isEmptyElement()) { return;
XML_ReadNode_GetVal_AsString(enc64_data);
} }
std::string enc64_data = node.value();
// Check for child nodes
// check that all components was defined // check that all components was defined
if (id.empty()) { if (id.empty()) {
throw DeadlyImportError("ID for texture must be defined."); throw DeadlyImportError("ID for texture must be defined.");
} }
if (width < 1) { if (width < 1) {
Throw_IncorrectAttrValue("width"); throw DeadlyImportError("INvalid width for texture.");
} }
if (height < 1) { if (height < 1) {
Throw_IncorrectAttrValue("height"); throw DeadlyImportError("Invalid height for texture.");
} }
if (depth < 1) { if (depth < 1) {
Throw_IncorrectAttrValue("depth"); throw DeadlyImportError("Invalid depth for texture.");
} }
if (type != "grayscale") { if (type != "grayscale") {
Throw_IncorrectAttrValue("type"); throw DeadlyImportError("Invalid type for texture.");
} }
if (enc64_data.empty()) { if (enc64_data.empty()) {
throw DeadlyImportError("Texture data not defined."); throw DeadlyImportError("Texture data not defined.");
@ -263,57 +227,94 @@ void AMFImporter::ParseNode_Texture()
// <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>. // <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
// Multi elements - No. // Multi elements - No.
// Texture coordinates for every vertex of triangle. // Texture coordinates for every vertex of triangle.
void AMFImporter::ParseNode_TexMap(const bool pUseOldName) { void AMFImporter::ParseNode_TexMap(XmlNode &node, const bool pUseOldName) {
std::string rtexid, gtexid, btexid, atexid;
// Read attributes for node <color>. // Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG; AMFNodeElementBase *ne = new AMFTexMap(mNodeElement_Cur);
MACRO_ATTRREAD_CHECK_RET("rtexid", rtexid, mReader->getAttributeValue); AMFTexMap &als = *((AMFTexMap *)ne); //
MACRO_ATTRREAD_CHECK_RET("gtexid", gtexid, mReader->getAttributeValue); std::string rtexid, gtexid, btexid, atexid;
MACRO_ATTRREAD_CHECK_RET("btexid", btexid, mReader->getAttributeValue); if (!node.empty()) {
MACRO_ATTRREAD_CHECK_RET("atexid", atexid, mReader->getAttributeValue); ParseHelper_Node_Enter(ne);
MACRO_ATTRREAD_LOOPEND; for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "rtexid") {
XmlParser::getValueAsString(node, rtexid);
} else if (currentName == "gtexid") {
XmlParser::getValueAsString(node, gtexid);
} else if (currentName == "btexid") {
XmlParser::getValueAsString(node, btexid);
} else if (currentName == "atexid") {
XmlParser::getValueAsString(node, atexid);
}
}
ParseHelper_Node_Exit();
}
// create new texture coordinates object. // create new texture coordinates object, alias for convenience
CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience
// check data // check data
if(rtexid.empty() && gtexid.empty() && btexid.empty()) throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined."); if (rtexid.empty() && gtexid.empty() && btexid.empty()) {
throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
}
// Check for children nodes // Check for children nodes
XML_CheckNode_MustHaveChildren(); //XML_CheckNode_MustHaveChildren();
if (node.children().begin() == node.children().end()) {
throw DeadlyImportError("Invalid children definition.");
}
// read children nodes // read children nodes
bool read_flag[6] = { false, false, false, false, false, false }; bool read_flag[6] = { false, false, false, false, false, false };
ParseHelper_Node_Enter(ne); if (!pUseOldName) {
if(!pUseOldName) for (pugi::xml_attribute &attr : node.attributes()) {
{ const std::string name = attr.name();
MACRO_NODECHECK_LOOPBEGIN("texmap"); if (name == "utex1") {
MACRO_NODECHECK_READCOMP_F("utex1", read_flag[0], als.TextureCoordinate[0].x); read_flag[0] = true;
MACRO_NODECHECK_READCOMP_F("utex2", read_flag[1], als.TextureCoordinate[1].x); als.TextureCoordinate[0].x = attr.as_float();
MACRO_NODECHECK_READCOMP_F("utex3", read_flag[2], als.TextureCoordinate[2].x); } else if (name == "utex2") {
MACRO_NODECHECK_READCOMP_F("vtex1", read_flag[3], als.TextureCoordinate[0].y); read_flag[1] = true;
MACRO_NODECHECK_READCOMP_F("vtex2", read_flag[4], als.TextureCoordinate[1].y); als.TextureCoordinate[1].x = attr.as_float();
MACRO_NODECHECK_READCOMP_F("vtex3", read_flag[5], als.TextureCoordinate[2].y); } else if (name == "utex3") {
MACRO_NODECHECK_LOOPEND("texmap"); read_flag[2] = true;
als.TextureCoordinate[2].x = attr.as_float();
} else if (name == "vtex1") {
read_flag[3] = true;
als.TextureCoordinate[0].y = attr.as_float();
} else if (name == "vtex2") {
read_flag[4] = true;
als.TextureCoordinate[1].y = attr.as_float();
} else if (name == "vtex3") {
read_flag[5] = true;
als.TextureCoordinate[0].y = attr.as_float();
}
}
} else {
for (pugi::xml_attribute &attr : node.attributes()) {
const std::string name = attr.name();
if (name == "u") {
read_flag[0] = true;
als.TextureCoordinate[0].x = attr.as_float();
} else if (name == "u2") {
read_flag[1] = true;
als.TextureCoordinate[1].x = attr.as_float();
} else if (name == "u3") {
read_flag[2] = true;
als.TextureCoordinate[2].x = attr.as_float();
} else if (name == "v1") {
read_flag[3] = true;
als.TextureCoordinate[0].y = attr.as_float();
} else if (name == "v2") {
read_flag[4] = true;
als.TextureCoordinate[1].y = attr.as_float();
} else if (name == "v3") {
read_flag[5] = true;
als.TextureCoordinate[0].y = attr.as_float();
}
}
} }
else
{
MACRO_NODECHECK_LOOPBEGIN("map");
MACRO_NODECHECK_READCOMP_F("u1", read_flag[0], als.TextureCoordinate[0].x);
MACRO_NODECHECK_READCOMP_F("u2", read_flag[1], als.TextureCoordinate[1].x);
MACRO_NODECHECK_READCOMP_F("u3", read_flag[2], als.TextureCoordinate[2].x);
MACRO_NODECHECK_READCOMP_F("v1", read_flag[3], als.TextureCoordinate[0].y);
MACRO_NODECHECK_READCOMP_F("v2", read_flag[4], als.TextureCoordinate[1].y);
MACRO_NODECHECK_READCOMP_F("v3", read_flag[5], als.TextureCoordinate[2].y);
MACRO_NODECHECK_LOOPEND("map");
}// if(!pUseOldName) else
ParseHelper_Node_Exit();
// check that all components was defined // check that all components was defined
if(!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) if (!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) {
throw DeadlyImportError("Not all texture coordinates are defined."); throw DeadlyImportError("Not all texture coordinates are defined.");
}
// copy attributes data // copy attributes data
als.TextureID_R = rtexid; als.TextureID_R = rtexid;
@ -321,7 +322,7 @@ void AMFImporter::ParseNode_TexMap(const bool pUseOldName) {
als.TextureID_B = btexid; als.TextureID_B = btexid;
als.TextureID_A = atexid; als.TextureID_A = atexid;
mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph. mNodeElement_List.push_back(ne);
} }
}// namespace Assimp }// namespace Assimp

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -56,12 +54,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
// Header files, Assimp. // Header files, Assimp.
#include "assimp/types.h"
#include "assimp/scene.h" #include "assimp/scene.h"
#include "assimp/types.h"
/// \class CAMFImporter_NodeElement /// \class CAMFImporter_NodeElement
/// Base class for elements of nodes. /// Base class for elements of nodes.
class CAMFImporter_NodeElement { class AMFNodeElementBase {
public: public:
/// Define what data type contain node element. /// Define what data type contain node element.
enum EType { enum EType {
@ -87,47 +85,43 @@ public:
const EType Type; ///< Type of element. const EType Type; ///< Type of element.
std::string ID; ///< ID of element. std::string ID; ///< ID of element.
CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root. AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
std::list<CAMFImporter_NodeElement*> Child;///< Child elements. std::list<AMFNodeElementBase *> Child; ///< Child elements.
public: /// Destructor, virtual.. public: /// Destructor, virtual..
virtual ~CAMFImporter_NodeElement() { virtual ~AMFNodeElementBase() {
// empty // empty
} }
/// Disabled copy constructor and co. /// Disabled copy constructor and co.
CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete; AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete;
CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete; AMFNodeElementBase(AMFNodeElementBase &&) = delete;
CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete; AMFNodeElementBase &operator=(const AMFNodeElementBase &pNodeElement) = delete;
CAMFImporter_NodeElement() = delete; AMFNodeElementBase() = delete;
protected: protected:
/// In constructor inheritor must set element type. /// In constructor inheritor must set element type.
/// \param [in] pType - element type. /// \param [in] pType - element type.
/// \param [in] pParent - parent element. /// \param [in] pParent - parent element.
CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent) AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
: Type(pType) Type(pType), ID(), Parent(pParent), Child() {
, ID()
, Parent(pParent)
, Child() {
// empty // empty
} }
}; // class IAMFImporter_NodeElement }; // class IAMFImporter_NodeElement
/// \struct CAMFImporter_NodeElement_Constellation /// \struct CAMFImporter_NodeElement_Constellation
/// A collection of objects or constellations with specific relative locations. /// A collection of objects or constellations with specific relative locations.
struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement { struct AMFConstellation : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent) AMFConstellation(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Constellation, pParent) AMFNodeElementBase(ENET_Constellation, pParent) {}
{}
}; // struct CAMFImporter_NodeElement_Constellation }; // struct CAMFImporter_NodeElement_Constellation
/// \struct CAMFImporter_NodeElement_Instance /// \struct CAMFImporter_NodeElement_Instance
/// Part of constellation. /// Part of constellation.
struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement { struct AMFInstance : public AMFNodeElementBase {
std::string ObjectID; ///< ID of object for instantiation. std::string ObjectID; ///< ID of object for instantiation.
/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to /// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
@ -140,42 +134,39 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent) AMFInstance(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Instance, pParent) AMFNodeElementBase(ENET_Instance, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Metadata /// \struct CAMFImporter_NodeElement_Metadata
/// Structure that define metadata node. /// Structure that define metadata node.
struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement { struct AMFMetadata : public AMFNodeElementBase {
std::string Type; ///< Type of "Value". std::string Type; ///< Type of "Value".
std::string Value; ///< Value. std::string Value; ///< Value.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent) AMFMetadata(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Metadata, pParent) AMFNodeElementBase(ENET_Metadata, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Root /// \struct CAMFImporter_NodeElement_Root
/// Structure that define root node. /// Structure that define root node.
struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement { struct AMFRoot : public AMFNodeElementBase {
std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron". std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
std::string Version; ///< Version of format. std::string Version; ///< Version of format.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent) AMFRoot(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Root, pParent) AMFNodeElementBase(ENET_Root, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Color /// \struct CAMFImporter_NodeElement_Color
/// Structure that define object node. /// Structure that define object node.
struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement { struct AMFColor : public AMFNodeElementBase {
bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA. std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA.
aiColor4D Color; ///< Constant color. aiColor4D Color; ///< Constant color.
@ -183,109 +174,94 @@ struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement {
/// @brief Constructor. /// @brief Constructor.
/// @param [in] pParent - pointer to parent node. /// @param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent) AMFColor(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Color, pParent) AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() {
, Composed( false )
, Color()
, Profile() {
// empty // empty
} }
}; };
/// \struct CAMFImporter_NodeElement_Material /// \struct CAMFImporter_NodeElement_Material
/// Structure that define material node. /// Structure that define material node.
struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement { struct AMFMaterial : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent) AMFMaterial(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Material, pParent) AMFNodeElementBase(ENET_Material, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Object /// \struct CAMFImporter_NodeElement_Object
/// Structure that define object node. /// Structure that define object node.
struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement { struct AMFObject : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent) AMFObject(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Object, pParent) AMFNodeElementBase(ENET_Object, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Mesh /// \struct CAMFImporter_NodeElement_Mesh
/// Structure that define mesh node. /// Structure that define mesh node.
struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement { struct AMFMesh : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent) AMFMesh(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Mesh, pParent) AMFNodeElementBase(ENET_Mesh, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Vertex /// \struct CAMFImporter_NodeElement_Vertex
/// Structure that define vertex node. /// Structure that define vertex node.
struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement { struct AMFVertex : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent) AMFVertex(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Vertex, pParent) AMFNodeElementBase(ENET_Vertex, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Edge /// \struct CAMFImporter_NodeElement_Edge
/// Structure that define edge node. /// Structure that define edge node.
struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement { struct AMFEdge : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent) AMFEdge(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Edge, pParent) AMFNodeElementBase(ENET_Edge, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Vertices /// \struct CAMFImporter_NodeElement_Vertices
/// Structure that define vertices node. /// Structure that define vertices node.
struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement { struct AMFVertices : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent) AMFVertices(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Vertices, pParent) AMFNodeElementBase(ENET_Vertices, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Volume /// \struct CAMFImporter_NodeElement_Volume
/// Structure that define volume node. /// Structure that define volume node.
struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement { struct AMFVolume : public AMFNodeElementBase {
std::string MaterialID; ///< Which material to use. std::string MaterialID; ///< Which material to use.
std::string Type; ///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed. std::string Type; ///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent) AMFVolume(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Volume, pParent) AMFNodeElementBase(ENET_Volume, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_Coordinates /// \struct CAMFImporter_NodeElement_Coordinates
/// Structure that define coordinates node. /// Structure that define coordinates node.
struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement struct AMFCoordinates : public AMFNodeElementBase {
{
aiVector3D Coordinate; ///< Coordinate. aiVector3D Coordinate; ///< Coordinate.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent) AMFCoordinates(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Coordinates, pParent) AMFNodeElementBase(ENET_Coordinates, pParent) {}
{}
}; };
/// \struct CAMFImporter_NodeElement_TexMap /// \struct CAMFImporter_NodeElement_TexMap
/// Structure that define texture coordinates node. /// Structure that define texture coordinates node.
struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement { struct AMFTexMap : public AMFNodeElementBase {
aiVector3D TextureCoordinate[3]; ///< Texture coordinates. aiVector3D TextureCoordinate[3]; ///< Texture coordinates.
std::string TextureID_R; ///< Texture ID for red color component. std::string TextureID_R; ///< Texture ID for red color component.
std::string TextureID_G; ///< Texture ID for green color component. std::string TextureID_G; ///< Texture ID for green color component.
@ -294,45 +270,35 @@ struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent) AMFTexMap(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_TexMap, pParent) AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() {
, TextureCoordinate{}
, TextureID_R()
, TextureID_G()
, TextureID_B()
, TextureID_A() {
// empty // empty
} }
}; };
/// \struct CAMFImporter_NodeElement_Triangle /// \struct CAMFImporter_NodeElement_Triangle
/// Structure that define triangle node. /// Structure that define triangle node.
struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement { struct AMFTriangle : public AMFNodeElementBase {
size_t V[3]; ///< Triangle vertices. size_t V[3]; ///< Triangle vertices.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent) AMFTriangle(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Triangle, pParent) { AMFNodeElementBase(ENET_Triangle, pParent) {
// empty // empty
} }
}; };
/// Structure that define texture node. /// Structure that define texture node.
struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement { struct AMFTexture : public AMFNodeElementBase {
size_t Width, Height, Depth; ///< Size of the texture. size_t Width, Height, Depth; ///< Size of the texture.
std::vector<uint8_t> Data; ///< Data of the texture. std::vector<uint8_t> Data; ///< Data of the texture.
bool Tiled; bool Tiled;
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent) AMFTexture(AMFNodeElementBase *pParent) :
: CAMFImporter_NodeElement(ENET_Texture, pParent) AMFNodeElementBase(ENET_Texture, pParent), Width(0), Height(0), Depth(0), Data(), Tiled(false) {
, Width( 0 )
, Height( 0 )
, Depth( 0 )
, Data()
, Tiled( false ){
// empty // empty
} }
}; };

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -50,12 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
// Header files, Assimp.
#include <assimp/SceneCombiner.h> #include <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h> #include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
// Header files, stdlib.
#include <iterator> #include <iterator>
namespace Assimp { namespace Assimp {
@ -83,61 +79,61 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
return tcol; return tcol;
} }
void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray, void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray) const { std::vector<AMFColor *> &pVertexColorArray) const {
CAMFImporter_NodeElement_Vertices *vn = nullptr; AMFVertices *vn = nullptr;
size_t col_idx; size_t col_idx;
// All data stored in "vertices", search for it. // All data stored in "vertices", search for it.
for (CAMFImporter_NodeElement *ne_child : pNodeElement.Child) { for (AMFNodeElementBase *ne_child : pNodeElement.Child) {
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices *)ne_child; if (ne_child->Type == AMFNodeElementBase::ENET_Vertices) {
vn = (AMFVertices*)ne_child;
}
} }
// If "vertices" not found then no work for us. // If "vertices" not found then no work for us.
if (vn == nullptr) return; 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. // 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. pVertexCoordinateArray.reserve(vn->Child.size());
// colors count equal vertices count.
pVertexColorArray.resize(vn->Child.size());
col_idx = 0; col_idx = 0;
// Inside vertices collect all data and place to arrays // Inside vertices collect all data and place to arrays
for (CAMFImporter_NodeElement *vn_child : vn->Child) { for (AMFNodeElementBase *vn_child : vn->Child) {
// vertices, colors // vertices, colors
if (vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) { if (vn_child->Type == AMFNodeElementBase::ENET_Vertex) {
// by default clear color for current vertex // by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr; pVertexColorArray[col_idx] = nullptr;
for (CAMFImporter_NodeElement *vtx : vn_child->Child) { for (AMFNodeElementBase *vtx : vn_child->Child) {
if (vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates) { if (vtx->Type == AMFNodeElementBase::ENET_Coordinates) {
pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates *)vtx)->Coordinate); pVertexCoordinateArray.push_back(((AMFCoordinates *)vtx)->Coordinate);
continue; continue;
} }
if (vtx->Type == CAMFImporter_NodeElement::ENET_Color) { if (vtx->Type == AMFNodeElementBase::ENET_Color) {
pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color *)vtx; pVertexColorArray[col_idx] = (AMFColor *)vtx;
continue; 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, ++col_idx;
const std::string &pID_A) { }
size_t TextureConverted_Index; }
std::string TextureConverted_ID; }
// check input data size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) {
if (pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty()) if (r.empty() && g.empty() && b.empty() && a.empty()) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined."); throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
}
// Create ID std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a;
TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A; size_t TextureConverted_Index = 0;
// Check if texture specified by set of IDs is converted already.
TextureConverted_Index = 0;
for (const SPP_Texture &tex_convd : mTexture_Converted) { for (const SPP_Texture &tex_convd : mTexture_Converted) {
if (tex_convd.ID == TextureConverted_ID) { if (tex_convd.ID == TextureConverted_ID) {
return TextureConverted_Index; return TextureConverted_Index;
@ -146,52 +142,60 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
} }
} }
//
// Converted texture not found, create it. // Converted texture not found, create it.
// AMFTexture *src_texture[4] {
CAMFImporter_NodeElement_Texture *src_texture[4]{ nullptr }; nullptr
std::vector<CAMFImporter_NodeElement_Texture *> src_texture_4check; };
std::vector<AMFTexture *> src_texture_4check;
SPP_Texture converted_texture; SPP_Texture converted_texture;
{ // find all specified source textures { // find all specified source textures
CAMFImporter_NodeElement *t_tex; AMFNodeElementBase *t_tex = nullptr;
// R // R
if (!pID_R.empty()) { if (!r.empty()) {
if (!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R); if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(r);
}
src_texture[0] = (CAMFImporter_NodeElement_Texture *)t_tex; src_texture[0] = (AMFTexture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex); src_texture_4check.push_back((AMFTexture *)t_tex);
} else { } else {
src_texture[0] = nullptr; src_texture[0] = nullptr;
} }
// G // G
if (!pID_G.empty()) { if (!g.empty()) {
if (!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G); if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(g);
}
src_texture[1] = (CAMFImporter_NodeElement_Texture *)t_tex; src_texture[1] = (AMFTexture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex); src_texture_4check.push_back((AMFTexture *)t_tex);
} else { } else {
src_texture[1] = nullptr; src_texture[1] = nullptr;
} }
// B // B
if (!pID_B.empty()) { if (!b.empty()) {
if (!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B); if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(b);
}
src_texture[2] = (CAMFImporter_NodeElement_Texture *)t_tex; src_texture[2] = (AMFTexture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex); src_texture_4check.push_back((AMFTexture *)t_tex);
} else { } else {
src_texture[2] = nullptr; src_texture[2] = nullptr;
} }
// A // A
if (!pID_A.empty()) { if (!a.empty()) {
if (!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A); if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(a);
}
src_texture[3] = (CAMFImporter_NodeElement_Texture *)t_tex; src_texture[3] = (AMFTexture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex); src_texture_4check.push_back((AMFTexture *)t_tex);
} else { } else {
src_texture[3] = nullptr; src_texture[3] = nullptr;
} }
@ -213,38 +217,37 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
converted_texture.Depth = src_texture_4check[0]->Depth; converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too. // if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false; converted_texture.Tiled = false;
for (uint8_t i = 0; i < src_texture_4check.size(); i++) for (uint8_t i = 0; i < src_texture_4check.size(); ++i) {
converted_texture.Tiled |= src_texture_4check[i]->Tiled; converted_texture.Tiled |= src_texture_4check[i]->Tiled;
}
// Create format hint. // Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string. strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
if (!pID_R.empty()) converted_texture.FormatHint[4] = '8'; if (!r.empty()) converted_texture.FormatHint[4] = '8';
if (!pID_G.empty()) converted_texture.FormatHint[5] = '8'; if (!g.empty()) converted_texture.FormatHint[5] = '8';
if (!pID_B.empty()) converted_texture.FormatHint[6] = '8'; if (!b.empty()) converted_texture.FormatHint[6] = '8';
if (!pID_A.empty()) converted_texture.FormatHint[7] = '8'; if (!a.empty()) converted_texture.FormatHint[7] = '8';
//
// Сopy data of textures. // Сopy data of textures.
//
size_t tex_size = 0; size_t tex_size = 0;
size_t step = 0; size_t step = 0;
size_t off_g = 0; size_t off_g = 0;
size_t off_b = 0; size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied. // Calculate size of the target array and rule how data will be copied.
if (!pID_R.empty() && nullptr != src_texture[0]) { if (!r.empty() && nullptr != src_texture[0]) {
tex_size += src_texture[0]->Data.size(); tex_size += src_texture[0]->Data.size();
step++, off_g++, off_b++; step++, off_g++, off_b++;
} }
if (!pID_G.empty() && nullptr != src_texture[1]) { if (!g.empty() && nullptr != src_texture[1]) {
tex_size += src_texture[1]->Data.size(); tex_size += src_texture[1]->Data.size();
step++, off_b++; step++, off_b++;
} }
if (!pID_B.empty() && nullptr != src_texture[2]) { if (!b.empty() && nullptr != src_texture[2]) {
tex_size += src_texture[2]->Data.size(); tex_size += src_texture[2]->Data.size();
step++; step++;
} }
if (!pID_A.empty() && nullptr != src_texture[3]) { if (!a.empty() && nullptr != src_texture[3]) {
tex_size += src_texture[3]->Data.size(); tex_size += src_texture[3]->Data.size();
step++; step++;
} }
@ -255,17 +258,17 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void { auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
if (!pID.empty()) { if (!pID.empty()) {
for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) { 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]; AMFTexture *tex = src_texture[pSrcTexNum];
ai_assert(tex); ai_assert(tex);
converted_texture.Data[idx_target] = tex->Data.at(idx_src); 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 }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(pID_R, 0, step, 0); CopyTextureData(r, 0, step, 0);
CopyTextureData(pID_G, off_g, step, 1); CopyTextureData(g, off_g, step, 1);
CopyTextureData(pID_B, off_b, step, 2); CopyTextureData(b, off_b, step, 2);
CopyTextureData(pID_A, step - 1, step, 3); CopyTextureData(a, step - 1, step, 3);
// Store new converted texture ID // Store new converted texture ID
converted_texture.ID = TextureConverted_ID; converted_texture.ID = TextureConverted_ID;
@ -276,7 +279,7 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
} }
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) { void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) {
auto texmap_is_equal = [](const CAMFImporter_NodeElement_TexMap *pTexMap1, const CAMFImporter_NodeElement_TexMap *pTexMap2) -> bool { auto texmap_is_equal = [](const AMFTexMap *pTexMap1, const AMFTexMap *pTexMap2) -> bool {
if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true; if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
if (pTexMap1 == nullptr) return false; if (pTexMap1 == nullptr) return false;
if (pTexMap2 == nullptr) return false; if (pTexMap2 == nullptr) return false;
@ -313,73 +316,80 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
} while (!pInputList.empty()); } while (!pInputList.empty());
} }
void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata *> &metadataList, aiNode &sceneNode) const { void AMFImporter::Postprocess_AddMetadata(const AMFMetaDataArray &metadataList, aiNode &sceneNode) const {
if (!metadataList.empty()) { if (metadataList.empty()) {
if (sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong."); return;
}
if (sceneNode.mMetaData != nullptr) {
throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
}
// copy collected metadata to output node. // copy collected metadata to output node.
sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size())); sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size()));
size_t meta_idx(0); size_t meta_idx(0);
for (const CAMFImporter_NodeElement_Metadata &metadata : metadataList) { for (const AMFMetadata &metadata : metadataList) {
sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value)); sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
} }
} // if(!metadataList.empty())
} }
void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object &pNodeElement, std::list<aiMesh *> &pMeshList, aiNode **pSceneNode) { void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode) {
CAMFImporter_NodeElement_Color *object_color = nullptr; AMFColor *object_color = nullptr;
// create new aiNode and set name as <object> has. // create new aiNode and set name as <object> has.
*pSceneNode = new aiNode; *pSceneNode = new aiNode;
(*pSceneNode)->mName = pNodeElement.ID; (*pSceneNode)->mName = pNodeElement.ID;
// read mesh and color // read mesh and color
for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) { for (const AMFNodeElementBase *ne_child : pNodeElement.Child) {
std::vector<aiVector3D> vertex_arr; std::vector<aiVector3D> vertex_arr;
std::vector<CAMFImporter_NodeElement_Color *> color_arr; std::vector<AMFColor *> color_arr;
// color for object // color for object
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color *)ne_child; if (ne_child->Type == AMFNodeElementBase::ENET_Color) {
object_color = (AMFColor *) ne_child;
}
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) { if (ne_child->Type == AMFNodeElementBase::ENET_Mesh) {
// Create arrays from children of mesh: vertices. // Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr); PostprocessHelper_CreateMeshDataArray(*((AMFMesh *)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh // 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); Postprocess_BuildMeshSet(*((AMFMesh *)ne_child), vertex_arr, color_arr, object_color, meshList, **pSceneNode);
} }
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement) } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
} }
void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray, void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray, const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor, MeshArray &pMeshList, aiNode &pSceneNode) {
const CAMFImporter_NodeElement_Color *pObjectColor, std::list<aiMesh *> &pMeshList, aiNode &pSceneNode) {
std::list<unsigned int> mesh_idx; std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it. // all data stored in "volume", search for it.
for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) { for (const AMFNodeElementBase *ne_child : pNodeElement.Child) {
const CAMFImporter_NodeElement_Color *ne_volume_color = nullptr; const AMFColor *ne_volume_color = nullptr;
const SPP_Material *cur_mat = nullptr; const SPP_Material *cur_mat = nullptr;
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) { if (ne_child->Type == AMFNodeElementBase::ENET_Volume) {
/******************* Get faces *******************/ /******************* Get faces *******************/
const CAMFImporter_NodeElement_Volume *ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume *>(ne_child); const AMFVolume *ne_volume = reinterpret_cast<const AMFVolume *>(ne_child);
std::list<SComplexFace> complex_faces_list; // List of the faces of the volume. std::list<SComplexFace> complex_faces_list; // List of the faces of the volume.
std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh. std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh.
// check if volume use material // check if volume use material
if (!ne_volume->MaterialID.empty()) { if (!ne_volume->MaterialID.empty()) {
if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID); 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 // inside "volume" collect all data and place to arrays or create new objects
for (const CAMFImporter_NodeElement *ne_volume_child : ne_volume->Child) { for (const AMFNodeElementBase *ne_volume_child : ne_volume->Child) {
// color for volume // color for volume
if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color) { if (ne_volume_child->Type == AMFNodeElementBase::ENET_Color) {
ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_volume_child); ne_volume_color = reinterpret_cast<const AMFColor *>(ne_volume_child);
} else if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle) // triangles, triangles colors } else if (ne_volume_child->Type == AMFNodeElementBase::ENET_Triangle) // triangles, triangles colors
{ {
const CAMFImporter_NodeElement_Triangle &tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle *>(ne_volume_child); const AMFTriangle &tri_al = *reinterpret_cast<const AMFTriangle *>(ne_volume_child);
SComplexFace complex_face; SComplexFace complex_face;
@ -388,11 +398,11 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
complex_face.TexMap = nullptr; complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates. // get data from triangle children: color, texture coordinates.
if (tri_al.Child.size()) { if (tri_al.Child.size()) {
for (const CAMFImporter_NodeElement *ne_triangle_child : tri_al.Child) { for (const AMFNodeElementBase *ne_triangle_child : tri_al.Child) {
if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color) if (ne_triangle_child->Type == AMFNodeElementBase::ENET_Color)
complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_triangle_child); complex_face.Color = reinterpret_cast<const AMFColor *>(ne_triangle_child);
else if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap) else if (ne_triangle_child->Type == AMFNodeElementBase::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap *>(ne_triangle_child); complex_face.TexMap = reinterpret_cast<const AMFTexMap *>(ne_triangle_child);
} }
} // if(tri_al.Child.size()) } // if(tri_al.Child.size())
@ -422,15 +432,18 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
if (face.Face.mIndices[idx_vert] > *pBiggerThan) { if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
rv = face.Face.mIndices[idx_vert]; rv = face.Face.mIndices[idx_vert];
found = true; found = true;
break; break;
} }
} }
if (found) break; if (found) {
break;
}
} }
if (!found) return *pBiggerThan; if (!found) {
return *pBiggerThan;
}
} else { } else {
rv = pFaceList.front().Face.mIndices[0]; rv = pFaceList.front().Face.mIndices[0];
} // if(pBiggerThan != nullptr) else } // if(pBiggerThan != nullptr) else
@ -505,9 +518,9 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size()); tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
tmesh->mFaces = new aiFace[tmesh->mNumFaces]; 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 // Create vertices list and optimize indices. Optimization mean following.In AMF all volumes use one big list of vertices. And one volume
// can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10. // 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. // Do you need all this thousands of garbage? Of course no. So, optimization step transform sparse indices set to continuous.
size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles. size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
std::vector<aiVector3D> vert_arr, texcoord_arr; std::vector<aiVector3D> vert_arr, texcoord_arr;
std::vector<aiColor4D> col_arr; std::vector<aiColor4D> col_arr;
@ -566,7 +579,7 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
size_t idx_vert_new = vert_arr.size(); 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 ///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 /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
/// optimisation. /// optimization.
bool *idx_vert_used; bool *idx_vert_used;
idx_vert_used = new bool[VertexCount_Max * 2]; idx_vert_used = new bool[VertexCount_Max * 2];
@ -639,15 +652,15 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
} // if(mesh_idx.size() > 0) } // if(mesh_idx.size() > 0)
} }
void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material &pMaterial) { void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial &pMaterial) {
SPP_Material new_mat; SPP_Material new_mat;
new_mat.ID = pMaterial.ID; new_mat.ID = pMaterial.ID;
for (const CAMFImporter_NodeElement *mat_child : pMaterial.Child) { for (const AMFNodeElementBase *mat_child : pMaterial.Child) {
if (mat_child->Type == CAMFImporter_NodeElement::ENET_Color) { if (mat_child->Type == AMFNodeElementBase::ENET_Color) {
new_mat.Color = (CAMFImporter_NodeElement_Color *)mat_child; new_mat.Color = (AMFColor*)mat_child;
} else if (mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata) { } else if (mat_child->Type == AMFNodeElementBase::ENET_Metadata) {
new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata *)mat_child); new_mat.Metadata.push_back((AMFMetadata *)mat_child);
} }
} // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child) } // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
@ -655,7 +668,7 @@ void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Mater
mMaterial_Converted.push_back(new_mat); mMaterial_Converted.push_back(new_mat);
} }
void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation &pConstellation, std::list<aiNode *> &pNodeList) const { void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const {
aiNode *con_node; aiNode *con_node;
std::list<aiNode *> ch_node; std::list<aiNode *> ch_node;
@ -667,18 +680,18 @@ void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Conste
con_node = new aiNode; con_node = new aiNode;
con_node->mName = pConstellation.ID; con_node->mName = pConstellation.ID;
// Walk through children and search for instances of another objects, constellations. // Walk through children and search for instances of another objects, constellations.
for (const CAMFImporter_NodeElement *ne : pConstellation.Child) { for (const AMFNodeElementBase *ne : pConstellation.Child) {
aiMatrix4x4 tmat; aiMatrix4x4 tmat;
aiNode *t_node; aiNode *t_node;
aiNode *found_node; aiNode *found_node;
if (ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue; if (ne->Type == AMFNodeElementBase::ENET_Metadata) continue;
if (ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>."); if (ne->Type != AMFNodeElementBase::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for conveniance // create alias for conveniance
CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); AMFInstance &als = *((AMFInstance *)ne);
// find referenced object // find referenced object
if (!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID); if (!Find_ConvertedNode(als.ObjectID, nodeArray, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation // create node for applying transformation
t_node = new aiNode; t_node = new aiNode;
@ -707,13 +720,13 @@ void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Conste
con_node->mChildren[ch_idx++] = node; con_node->mChildren[ch_idx++] = node;
// and place "root" of <constellation> node to node list // and place "root" of <constellation> node to node list
pNodeList.push_back(con_node); nodeArray.push_back(con_node);
} }
void AMFImporter::Postprocess_BuildScene(aiScene *pScene) { void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
std::list<aiNode *> node_list; NodeArray nodeArray;
std::list<aiMesh *> mesh_list; MeshArray mesh_list;
std::list<CAMFImporter_NodeElement_Metadata *> meta_list; AMFMetaDataArray meta_list;
// //
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used. // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
@ -723,18 +736,21 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
pScene->mRootNode->mParent = nullptr; pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED; pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
// search for root(<amf>) element // search for root(<amf>) element
CAMFImporter_NodeElement *root_el = nullptr; AMFNodeElementBase *root_el = nullptr;
for (CAMFImporter_NodeElement *ne : mNodeElement_List) { for (AMFNodeElementBase *ne : mNodeElement_List) {
if (ne->Type != CAMFImporter_NodeElement::ENET_Root) continue; if (ne->Type != AMFNodeElementBase::ENET_Root) {
continue;
}
root_el = ne; root_el = ne;
break; break;
} // for(const CAMFImporter_NodeElement* ne: mNodeElement_List) } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found. // Check if root element are found.
if (root_el == nullptr) throw DeadlyImportError("Root(<amf>) element not found."); if (root_el == nullptr) {
throw DeadlyImportError("Root(<amf>) element not found.");
}
// after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>, // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read // <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
@ -742,34 +758,38 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
// //
// 1. <material> // 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet // 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
for (const CAMFImporter_NodeElement *root_child : root_el->Child) { for (const AMFNodeElementBase *root_child : root_el->Child) {
if (root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material *)root_child)); if (root_child->Type == AMFNodeElementBase::ENET_Material) {
Postprocess_BuildMaterial(*((AMFMaterial *)root_child));
}
} }
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>. // After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
// //
// 3. <object> // 3. <object>
for (const CAMFImporter_NodeElement *root_child : root_el->Child) { for (const AMFNodeElementBase *root_child : root_el->Child) {
if (root_child->Type == CAMFImporter_NodeElement::ENET_Object) { if (root_child->Type == AMFNodeElementBase::ENET_Object) {
aiNode *tnode = nullptr; aiNode *tnode = nullptr;
// for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance> // for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object *)root_child), mesh_list, &tnode); Postprocess_BuildNodeAndObject(*((AMFObject *)root_child), mesh_list, &tnode);
if (tnode != nullptr) node_list.push_back(tnode); if (tnode != nullptr) {
nodeArray.push_back(tnode);
}
} }
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child) } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes. // And finally read rest of nodes.
// //
for (const CAMFImporter_NodeElement *root_child : root_el->Child) { for (const AMFNodeElementBase *root_child : root_el->Child) {
// 4. <constellation> // 4. <constellation>
if (root_child->Type == CAMFImporter_NodeElement::ENET_Constellation) { if (root_child->Type == AMFNodeElementBase::ENET_Constellation) {
// <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's. // <object> and <constellation> 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); Postprocess_BuildConstellation(*((AMFConstellation *)root_child), nodeArray);
} }
// 5, <metadata> // 5, <metadata>
if (root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata *)root_child); if (root_child->Type == AMFNodeElementBase::ENET_Metadata) meta_list.push_back((AMFMetadata *)root_child);
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child) } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// at now we can add collected metadata to root node // at now we can add collected metadata to root node
@ -783,17 +803,17 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
// And at this step we are checking that relations. // And at this step we are checking that relations.
nl_clean_loop: nl_clean_loop:
if (node_list.size() > 1) { if (nodeArray.size() > 1) {
// walk through all nodes // walk through all nodes
for (std::list<aiNode *>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) { for (NodeArray::iterator nl_it = nodeArray.begin(); nl_it != nodeArray.end(); ++nl_it) {
// and try to find them in another top nodes. // and try to find them in another top nodes.
std::list<aiNode *>::const_iterator next_it = nl_it; NodeArray::const_iterator next_it = nl_it;
++next_it; ++next_it;
for (; next_it != node_list.end(); ++next_it) { for (; next_it != nodeArray.end(); ++next_it) {
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) { 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. // 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); nodeArray.erase(nl_it);
goto nl_clean_loop; goto nl_clean_loop;
} }
@ -806,10 +826,10 @@ nl_clean_loop:
// //
// //
// Nodes // Nodes
if (!node_list.empty()) { if (!nodeArray.empty()) {
std::list<aiNode *>::const_iterator nl_it = node_list.begin(); NodeArray::const_iterator nl_it = nodeArray.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size()); pScene->mRootNode->mNumChildren = static_cast<unsigned int>(nodeArray.size());
pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) { for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) {
// Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have // Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have
@ -822,7 +842,7 @@ nl_clean_loop:
// //
// Meshes // Meshes
if (!mesh_list.empty()) { if (!mesh_list.empty()) {
std::list<aiMesh *>::const_iterator ml_it = mesh_list.begin(); MeshArray::const_iterator ml_it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size()); pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,24 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaLoader.h" #include "ColladaLoader.h"
#include "ColladaParser.h" #include "ColladaParser.h"
#include <assimp/ColladaMetaData.h> #include <assimp/ColladaMetaData.h>
#include <assimp/Defines.h>
#include <assimp/anim.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/CreateAnimMesh.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/Defines.h>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/anim.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include "math.h" #include <assimp/scene.h>
#include "time.h" #include <math.h>
#include <time.h>
#include <algorithm> #include <algorithm>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
@ -125,21 +122,18 @@ ColladaLoader::~ColladaLoader() {
bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
// check file extension // check file extension
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
const bool readSig = checkSig && (pIOHandler != nullptr);
bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) { if (!readSig) {
if (extension == "dae" || extension == "zae") { if (extension == "dae" || extension == "zae") {
return true; return true;
} }
} } else {
if (readSig) {
// Look for a DAE file inside, but don't extract it // Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile); ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen()) if (zip_archive.isOpen()) {
return !ColladaParser::ReadZaeManifest(zip_archive).empty(); return !ColladaParser::ReadZaeManifest(zip_archive).empty();
} }
}
// XML - too generic, we need to open the file and search for typical keywords // XML - too generic, we need to open the file and search for typical keywords
if (extension == "xml" || !extension.length() || checkSig) { if (extension == "xml" || !extension.length() || checkSig) {
@ -390,7 +384,11 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Colla
if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) { if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
// Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess .... // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
// epsilon chosen to be 0.1 // epsilon chosen to be 0.1
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) + float f = 1.0f;
if ( 0.0f != srcLight->mFalloffExponent ) {
f = 1.f / srcLight->mFalloffExponent;
}
out->mAngleOuterCone = std::acos(std::pow(0.1f, f)) +
out->mAngleInnerCone; out->mAngleInnerCone;
} else { } else {
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle); out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
@ -1251,7 +1249,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// time count and value count must match // time count and value count must match
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
if (e.mTimeAccessor->mCount > 0) { if (e.mTimeAccessor->mCount > 0) {
// find bounding times // find bounding times
@ -1468,7 +1466,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
for (size_t a = 0; a < morphAnims.size(); ++a) { for (size_t a = 0; a < morphAnims.size(); ++a) {
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
} }
anim->mTicksPerSecond = 1; anim->mTicksPerSecond = 1000.0;
mAnims.push_back(anim); mAnims.push_back(anim);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -50,9 +49,12 @@
#include "ColladaHelper.h" #include "ColladaHelper.h"
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/irrXMLWrapper.h> #include <assimp/XmlParser.h>
#include <map>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem; class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
@ -81,25 +83,25 @@ protected:
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive); static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
/** Reads the contents of the file */ /** Reads the contents of the file */
void ReadContents(); void ReadContents(XmlNode &node);
/** Reads the structure of the file */ /** Reads the structure of the file */
void ReadStructure(); void ReadStructure(XmlNode &node);
/** Reads asset information such as coordinate system information and legal blah */ /** Reads asset information such as coordinate system information and legal blah */
void ReadAssetInfo(); void ReadAssetInfo(XmlNode &node);
/** Reads contributor information such as author and legal blah */ /** Reads contributor information such as author and legal blah */
void ReadContributorInfo(); void ReadContributorInfo(XmlNode &node);
/** Reads generic metadata into provided map and renames keys for Assimp */ /** Reads generic metadata into provided map and renames keys for Assimp */
void ReadMetaDataItem(StringMetaData &metadata); void ReadMetaDataItem(XmlNode &node, StringMetaData &metadata);
/** Reads the animation library */ /** Reads the animation library */
void ReadAnimationLibrary(); void ReadAnimationLibrary(XmlNode &node);
/** Reads the animation clip library */ /** Reads the animation clip library */
void ReadAnimationClipLibrary(); void ReadAnimationClipLibrary(XmlNode &node);
/** Unwrap controllers dependency hierarchy */ /** Unwrap controllers dependency hierarchy */
void PostProcessControllers(); void PostProcessControllers();
@ -108,103 +110,103 @@ protected:
void PostProcessRootAnimations(); void PostProcessRootAnimations();
/** Reads an animation into the given parent structure */ /** Reads an animation into the given parent structure */
void ReadAnimation(Collada::Animation *pParent); void ReadAnimation(XmlNode &node, Collada::Animation *pParent);
/** Reads an animation sampler into the given anim channel */ /** Reads an animation sampler into the given anim channel */
void ReadAnimationSampler(Collada::AnimationChannel &pChannel); void ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel);
/** Reads the skeleton controller library */ /** Reads the skeleton controller library */
void ReadControllerLibrary(); void ReadControllerLibrary(XmlNode &node);
/** Reads a controller into the given mesh structure */ /** Reads a controller into the given mesh structure */
void ReadController(Collada::Controller &pController); void ReadController(XmlNode &node, Collada::Controller &pController);
/** Reads the joint definitions for the given controller */ /** Reads the joint definitions for the given controller */
void ReadControllerJoints(Collada::Controller &pController); void ReadControllerJoints(XmlNode &node, Collada::Controller &pController);
/** Reads the joint weights for the given controller */ /** Reads the joint weights for the given controller */
void ReadControllerWeights(Collada::Controller &pController); void ReadControllerWeights(XmlNode &node, Collada::Controller &pController);
/** Reads the image library contents */ /** Reads the image library contents */
void ReadImageLibrary(); void ReadImageLibrary(XmlNode &node);
/** Reads an image entry into the given image */ /** Reads an image entry into the given image */
void ReadImage(Collada::Image &pImage); void ReadImage(XmlNode &node, Collada::Image &pImage);
/** Reads the material library */ /** Reads the material library */
void ReadMaterialLibrary(); void ReadMaterialLibrary(XmlNode &node);
/** Reads a material entry into the given material */ /** Reads a material entry into the given material */
void ReadMaterial(Collada::Material &pMaterial); void ReadMaterial(XmlNode &node, Collada::Material &pMaterial);
/** Reads the camera library */ /** Reads the camera library */
void ReadCameraLibrary(); void ReadCameraLibrary(XmlNode &node);
/** Reads a camera entry into the given camera */ /** Reads a camera entry into the given camera */
void ReadCamera(Collada::Camera &pCamera); void ReadCamera(XmlNode &node, Collada::Camera &pCamera);
/** Reads the light library */ /** Reads the light library */
void ReadLightLibrary(); void ReadLightLibrary(XmlNode &node);
/** Reads a light entry into the given light */ /** Reads a light entry into the given light */
void ReadLight(Collada::Light &pLight); void ReadLight(XmlNode &node, Collada::Light &pLight);
/** Reads the effect library */ /** Reads the effect library */
void ReadEffectLibrary(); void ReadEffectLibrary(XmlNode &node);
/** Reads an effect entry into the given effect*/ /** Reads an effect entry into the given effect*/
void ReadEffect(Collada::Effect &pEffect); void ReadEffect(XmlNode &node, Collada::Effect &pEffect);
/** Reads an COMMON effect profile */ /** Reads an COMMON effect profile */
void ReadEffectProfileCommon(Collada::Effect &pEffect); void ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEffect);
/** Read sampler properties */ /** Read sampler properties */
void ReadSamplerProperties(Collada::Sampler &pSampler); void ReadSamplerProperties(XmlNode &node, Collada::Sampler &pSampler);
/** Reads an effect entry containing a color or a texture defining that color */ /** Reads an effect entry containing a color or a texture defining that color */
void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler); void ReadEffectColor(XmlNode &node, aiColor4D &pColor, Collada::Sampler &pSampler);
/** Reads an effect entry containing a float */ /** Reads an effect entry containing a float */
void ReadEffectFloat(ai_real &pFloat); void ReadEffectFloat(XmlNode &node, ai_real &pFloat);
/** Reads an effect parameter specification of any kind */ /** Reads an effect parameter specification of any kind */
void ReadEffectParam(Collada::EffectParam &pParam); void ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam);
/** Reads the geometry library contents */ /** Reads the geometry library contents */
void ReadGeometryLibrary(); void ReadGeometryLibrary(XmlNode &node);
/** Reads a geometry from the geometry library. */ /** Reads a geometry from the geometry library. */
void ReadGeometry(Collada::Mesh &pMesh); void ReadGeometry(XmlNode &node, Collada::Mesh &pMesh);
/** Reads a mesh from the geometry library */ /** Reads a mesh from the geometry library */
void ReadMesh(Collada::Mesh &pMesh); void ReadMesh(XmlNode &node, Collada::Mesh &pMesh);
/** Reads a source element - a combination of raw data and an accessor defining /** Reads a source element - a combination of raw data and an accessor defining
* things that should not be redefinable. Yes, that's another rant. * things that should not be redefinable. Yes, that's another rant.
*/ */
void ReadSource(); void ReadSource(XmlNode &node);
/** Reads a data array holding a number of elements, and stores it in the global library. /** Reads a data array holding a number of elements, and stores it in the global library.
* Currently supported are array of floats and arrays of strings. * Currently supported are array of floats and arrays of strings.
*/ */
void ReadDataArray(); void ReadDataArray(XmlNode &node);
/** Reads an accessor and stores it in the global library under the given ID - /** Reads an accessor and stores it in the global library under the given ID -
* accessors use the ID of the parent <source> element * accessors use the ID of the parent <source> element
*/ */
void ReadAccessor(const std::string &pID); void ReadAccessor(XmlNode &node, const std::string &pID);
/** Reads input declarations of per-vertex mesh data into the given mesh */ /** Reads input declarations of per-vertex mesh data into the given mesh */
void ReadVertexData(Collada::Mesh &pMesh); void ReadVertexData(XmlNode &node, Collada::Mesh &pMesh);
/** Reads input declarations of per-index mesh data into the given mesh */ /** Reads input declarations of per-index mesh data into the given mesh */
void ReadIndexData(Collada::Mesh &pMesh); void ReadIndexData(XmlNode &node, Collada::Mesh &pMesh);
/** Reads a single input channel element and stores it in the given array, if valid */ /** Reads a single input channel element and stores it in the given array, if valid */
void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels); void ReadInputChannel(XmlNode &node, std::vector<Collada::InputChannel> &poChannels);
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */ /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels, size_t ReadPrimitives(XmlNode &node, Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType); size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
/** Copies the data for a single primitive into the mesh, based on the InputChannels */ /** Copies the data for a single primitive into the mesh, based on the InputChannels */
@ -220,68 +222,29 @@ protected:
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh); void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
/** Reads the library of node hierarchies and scene parts */ /** Reads the library of node hierarchies and scene parts */
void ReadSceneLibrary(); void ReadSceneLibrary(XmlNode &node);
/** Reads a scene node's contents including children and stores it in the given node */ /** Reads a scene node's contents including children and stores it in the given node */
void ReadSceneNode(Collada::Node *pNode); void ReadSceneNode(XmlNode &node, Collada::Node *pNode);
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */ /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
void ReadNodeTransformation(Collada::Node *pNode, Collada::TransformType pType); void ReadNodeTransformation(XmlNode &node, Collada::Node *pNode, Collada::TransformType pType);
/** Reads a mesh reference in a node and adds it to the node's mesh list */ /** Reads a mesh reference in a node and adds it to the node's mesh list */
void ReadNodeGeometry(Collada::Node *pNode); void ReadNodeGeometry(XmlNode &node, Collada::Node *pNode);
/** Reads the collada scene */ /** Reads the collada scene */
void ReadScene(); void ReadScene(XmlNode &node);
// Processes bind_vertex_input and bind elements // Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl); void ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl);
/** Reads embedded textures from a ZAE archive*/ /** Reads embedded textures from a ZAE archive*/
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive); void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected: protected:
/** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX;
void ReportWarning(const char *msg, ...); void ReportWarning(const char *msg, ...);
/** Skips all data until the end node of the current element */
void SkipElement();
/** Skips all data until the end node of the given element */
void SkipElement(const char *pElement);
/** Compares the current xml element name to the given string and returns true if equal */
bool IsElement(const char *pName) const;
/** Tests for the opening tag of the given element, throws an exception if not found */
void TestOpening(const char *pName);
/** Tests for the closing tag of the given element, throws an exception if not found */
void TestClosing(const char *pName);
/** Checks the present element for the presence of the attribute, returns its index
or throws an exception if not found */
int GetAttribute(const char *pAttr) const;
/** Returns the index of the named attribute or -1 if not found. Does not throw,
therefore useful for optional attributes */
int TestAttribute(const char *pAttr) const;
/** Reads the text contents of an element, throws an exception if not given.
Skips leading whitespace. */
const char *GetTextContent();
/** Reads the text contents of an element, returns nullptr if not given.
Skips leading whitespace. */
const char *TestTextContent();
/** Reads a single bool from current text content */
bool ReadBoolFromTextContent();
/** Reads a single float from current text content */
ai_real ReadFloatFromTextContent();
/** Calculates the resulting transformation from all the given transform steps */ /** Calculates the resulting transformation from all the given transform steps */
aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const; aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
@ -293,11 +256,12 @@ protected:
const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const; const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
protected: protected:
/** Filename, for a verbose error message */ // Filename, for a verbose error message
std::string mFileName; std::string mFileName;
/** XML reader, member for everyday use */ // XML reader, member for everyday use
irr::io::IrrXMLReader *mReader; //irr::io::IrrXMLReader *mReader;
XmlParser mXmlParser;
/** All data arrays found in the file by ID. Might be referred to by actually /** All data arrays found in the file by ID. Might be referred to by actually
everyone. Collada, you are a steaming pile of indirection. */ everyone. Collada, you are a steaming pile of indirection. */
@ -372,18 +336,19 @@ protected:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check for element match // Check for element match
inline bool ColladaParser::IsElement(const char *pName) const { /*inline bool ColladaParser::IsElement(const char *pName) const {
ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT); ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT);
return ::strcmp(mReader->getNodeName(), pName) == 0; return ::strcmp(mReader->getNodeName(), pName) == 0;
} }*/
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Finds the item in the given library by its reference, throws if not found // Finds the item in the given library by its reference, throws if not found
template <typename Type> template <typename Type>
const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const { const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL); typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
if (it == pLibrary.end()) if (it == pLibrary.end()) {
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
}
return it->second; return it->second;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -76,23 +76,30 @@ Property* ReadTypedProperty(const Element& element)
ai_assert(element.KeyToken().StringContents() == "P"); ai_assert(element.KeyToken().StringContents() == "P");
const TokenList& tok = element.Tokens(); const TokenList& tok = element.Tokens();
ai_assert(tok.size() >= 5); if (tok.size() < 2) {
return nullptr;
}
const std::string& s = ParseTokenAsString(*tok[1]); const std::string& s = ParseTokenAsString(*tok[1]);
const char* const cs = s.c_str(); const char* const cs = s.c_str();
if (!strcmp(cs,"KString")) { if (!strcmp(cs,"KString")) {
ai_assert(tok.size() >= 5);
return new TypedProperty<std::string>(ParseTokenAsString(*tok[4])); return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
} }
else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) { else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
ai_assert(tok.size() >= 5);
return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0); return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
} }
else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) { else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
ai_assert(tok.size() >= 5);
return new TypedProperty<int>(ParseTokenAsInt(*tok[4])); return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
} }
else if (!strcmp(cs, "ULongLong")) { else if (!strcmp(cs, "ULongLong")) {
ai_assert(tok.size() >= 5);
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4])); return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
} }
else if (!strcmp(cs, "KTime")) { else if (!strcmp(cs, "KTime")) {
ai_assert(tok.size() >= 5);
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4])); return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
} }
else if (!strcmp(cs,"Vector3D") || else if (!strcmp(cs,"Vector3D") ||
@ -103,6 +110,7 @@ Property* ReadTypedProperty(const Element& element)
!strcmp(cs,"Lcl Rotation") || !strcmp(cs,"Lcl Rotation") ||
!strcmp(cs,"Lcl Scaling") !strcmp(cs,"Lcl Scaling")
) { ) {
ai_assert(tok.size() >= 7);
return new TypedProperty<aiVector3D>(aiVector3D( return new TypedProperty<aiVector3D>(aiVector3D(
ParseTokenAsFloat(*tok[4]), ParseTokenAsFloat(*tok[4]),
ParseTokenAsFloat(*tok[5]), ParseTokenAsFloat(*tok[5]),
@ -110,6 +118,7 @@ Property* ReadTypedProperty(const Element& element)
); );
} }
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) { else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
ai_assert(tok.size() >= 5);
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4])); return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
} }
return nullptr; return nullptr;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -67,8 +65,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
using namespace Assimp; using namespace Assimp;
using namespace irr;
using namespace irr::io;
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
"Irrlicht Scene Reader", "Irrlicht Scene Reader",
@ -298,8 +294,7 @@ inline void FindSuitableMultiple(int &angle) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) { void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) {
ai_assert(nullptr != root); ai_assert(nullptr != root && nullptr != real);
ai_assert(nullptr != real);
// XXX totally WIP - doesn't produce proper results, need to evaluate // XXX totally WIP - doesn't produce proper results, need to evaluate
// whether there's any use for Irrlicht's proprietary scene format // whether there's any use for Irrlicht's proprietary scene format
@ -401,12 +396,6 @@ void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNode
if (360 == lcm) if (360 == lcm)
break; break;
#if 0
// This can be a division through zero, but we don't care
float f1 = (float)lcm / angles[0];
float f2 = (float)lcm / angles[1];
float f3 = (float)lcm / angles[2];
#endif
// find out how many time units we'll need for the finest // find out how many time units we'll need for the finest
// track (in seconds) - this defines the number of output // track (in seconds) - this defines the number of output
@ -567,6 +556,10 @@ void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNode
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// This function is maybe more generic than we'd need it here // This function is maybe more generic than we'd need it here
void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) { void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
if (nullptr == mat) {
return;
}
// Check whether there are texture properties defined - setup // Check whether there are texture properties defined - setup
// the desired texture mapping mode for all of them and ignore // the desired texture mapping mode for all of them and ignore
// all UV settings we might encounter. WE HAVE NO UVS! // all UV settings we might encounter. WE HAVE NO UVS!
@ -671,7 +664,7 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} }
// NOTE: Each mesh should have exactly one material assigned, // NOTE: Each mesh should have exactly one material assigned,
// but we do it in a separate loop if this behaviour changes // but we do it in a separate loop if this behavior changes
// in future. // in future.
for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) {
// Process material flags // Process material flags
@ -704,9 +697,9 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} }
// If we have a second texture coordinate set and a second texture // If we have a second texture coordinate set and a second texture
// (either lightmap, normalmap, 2layered material) we need to // (either light-map, normal-map, 2layered material) we need to
// setup the correct UV index for it. The texture can either // setup the correct UV index for it. The texture can either
// be diffuse (lightmap & 2layer) or a normal map (normal & parallax) // be diffuse (light-map & 2layer) or a normal map (normal & parallax)
if (mesh->HasTextureCoords(1)) { if (mesh->HasTextureCoords(1)) {
int idx = 1; int idx = 1;
@ -729,8 +722,8 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
// Generate the sphere model. Our input parameter to // Generate the sphere model. Our input parameter to
// the sphere generation algorithm is the number of // the sphere generation algorithm is the number of
// subdivisions of each triangle - but here we have // subdivisions of each triangle - but here we have
// the number of poylgons on a specific axis. Just // the number of polygons on a specific axis. Just
// use some hardcoded limits to approximate this ... // use some hard-coded limits to approximate this ...
unsigned int mul = root->spherePolyCountX * root->spherePolyCountY; unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
if (mul < 100) if (mul < 100)
mul = 2; mul = 2;
@ -770,13 +763,13 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} break; } break;
case Node::SKYBOX: { case Node::SKYBOX: {
// A skybox is defined by six materials // A sky-box is defined by six materials
if (root->materials.size() < 6) { if (root->materials.size() < 6) {
ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox"); ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
break; break;
} }
// copy those materials and generate 6 meshes for our new skybox // copy those materials and generate 6 meshes for our new sky-box
materials.reserve(materials.size() + 6); materials.reserve(materials.size() + 6);
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
materials.insert(materials.end(), root->materials[i].first); materials.insert(materials.end(), root->materials[i].first);
@ -861,8 +854,7 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void IRRImporter::InternReadFile(const std::string &pFile, void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file // Check whether we can read from the file
@ -871,8 +863,11 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
// Construct the irrXML parser // Construct the irrXML parser
CIrrXML_IOStreamReader st(file.get()); XmlParser st;
reader = createIrrXMLReader((IFileReadCallBack *)&st); if (!st.parse( file.get() )) {
return;
}
pugi::xml_node rootElement = st.getRootNode();
// The root node of the scene // The root node of the scene
Node *root = new Node(Node::DUMMY); Node *root = new Node(Node::DUMMY);
@ -882,7 +877,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
// Current node parent // Current node parent
Node *curParent = root; Node *curParent = root;
// Scenegraph node we're currently working on // Scene-graph node we're currently working on
Node *curNode = nullptr; Node *curNode = nullptr;
// List of output cameras // List of output cameras
@ -902,11 +897,12 @@ void IRRImporter::InternReadFile(const std::string &pFile,
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0; unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
// Parse the XML file // Parse the XML file
while (reader->read()) {
switch (reader->getNodeType()) {
case EXN_ELEMENT:
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) { //while (reader->read()) {
for (pugi::xml_node child : rootElement.children())
switch (child.type()) {
case pugi::node_element:
if (!ASSIMP_stricmp(child.name(), "node")) {
// *********************************************************************** // ***********************************************************************
/* What we're going to do with the node depends /* What we're going to do with the node depends
* on its type: * on its type:
@ -927,47 +923,47 @@ void IRRImporter::InternReadFile(const std::string &pFile,
* materials assigned (except lights, cameras and dummies, of course). * materials assigned (except lights, cameras and dummies, of course).
*/ */
// *********************************************************************** // ***********************************************************************
const char *sz = reader->getAttributeValueSafe("type"); //const char *sz = reader->getAttributeValueSafe("type");
pugi::xml_attribute attrib = child.attribute("type");
Node *nd; Node *nd;
if (!ASSIMP_stricmp(sz, "mesh") || !ASSIMP_stricmp(sz, "octTree")) { if (!ASSIMP_stricmp(attrib.name(), "mesh") || !ASSIMP_stricmp(attrib.name(), "octTree")) {
// OctTree's and meshes are treated equally // OctTree's and meshes are treated equally
nd = new Node(Node::MESH); nd = new Node(Node::MESH);
} else if (!ASSIMP_stricmp(sz, "cube")) { } else if (!ASSIMP_stricmp(attrib.name(), "cube")) {
nd = new Node(Node::CUBE); nd = new Node(Node::CUBE);
++guessedMeshCnt; ++guessedMeshCnt;
// meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron)); } else if (!ASSIMP_stricmp(attrib.name(), "skybox")) {
} else if (!ASSIMP_stricmp(sz, "skybox")) {
nd = new Node(Node::SKYBOX); nd = new Node(Node::SKYBOX);
guessedMeshCnt += 6; guessedMeshCnt += 6;
} else if (!ASSIMP_stricmp(sz, "camera")) { } else if (!ASSIMP_stricmp(attrib.name(), "camera")) {
nd = new Node(Node::CAMERA); nd = new Node(Node::CAMERA);
// Setup a temporary name for the camera // Setup a temporary name for the camera
aiCamera *cam = new aiCamera(); aiCamera *cam = new aiCamera();
cam->mName.Set(nd->name); cam->mName.Set(nd->name);
cameras.push_back(cam); cameras.push_back(cam);
} else if (!ASSIMP_stricmp(sz, "light")) { } else if (!ASSIMP_stricmp(attrib.name(), "light")) {
nd = new Node(Node::LIGHT); nd = new Node(Node::LIGHT);
// Setup a temporary name for the light // Setup a temporary name for the light
aiLight *cam = new aiLight(); aiLight *cam = new aiLight();
cam->mName.Set(nd->name); cam->mName.Set(nd->name);
lights.push_back(cam); lights.push_back(cam);
} else if (!ASSIMP_stricmp(sz, "sphere")) { } else if (!ASSIMP_stricmp(attrib.name(), "sphere")) {
nd = new Node(Node::SPHERE); nd = new Node(Node::SPHERE);
++guessedMeshCnt; ++guessedMeshCnt;
} else if (!ASSIMP_stricmp(sz, "animatedMesh")) { } else if (!ASSIMP_stricmp(attrib.name(), "animatedMesh")) {
nd = new Node(Node::ANIMMESH); nd = new Node(Node::ANIMMESH);
} else if (!ASSIMP_stricmp(sz, "empty")) { } else if (!ASSIMP_stricmp(attrib.name(), "empty")) {
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} else if (!ASSIMP_stricmp(sz, "terrain")) { } else if (!ASSIMP_stricmp(attrib.name(), "terrain")) {
nd = new Node(Node::TERRAIN); nd = new Node(Node::TERRAIN);
} else if (!ASSIMP_stricmp(sz, "billBoard")) { } else if (!ASSIMP_stricmp(attrib.name(), "billBoard")) {
// We don't support billboards, so ignore them // We don't support billboards, so ignore them
ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp"); ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} else { } else {
ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(sz)); ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(attrib.name()));
/* We skip the contents of nodes we don't know. /* We skip the contents of nodes we don't know.
* We parse the transformation and all animators * We parse the transformation and all animators
@ -976,24 +972,19 @@ void IRRImporter::InternReadFile(const std::string &pFile,
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} }
/* Attach the newly created node to the scenegraph /* Attach the newly created node to the scene-graph
*/ */
curNode = nd; curNode = nd;
nd->parent = curParent; nd->parent = curParent;
curParent->children.push_back(nd); curParent->children.push_back(nd);
} else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) { } else if (!ASSIMP_stricmp(child.name(), "materials")) {
inMaterials = true; inMaterials = true;
} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) { } else if (!ASSIMP_stricmp(child.name(), "animators")) {
inAnimator = true; inAnimator = true;
} else if (!ASSIMP_stricmp(reader->getNodeName(), "attributes")) { } else if (!ASSIMP_stricmp(child.name(), "attributes")) {
/* We should have a valid node here // We should have a valid node here
* FIX: no ... the scene root node is also contained in an attributes block // FIX: no ... the scene root node is also contained in an attributes block
*/
if (!curNode) { if (!curNode) {
#if 0
ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but "
"there is no node active");
#endif
continue; continue;
} }
@ -1001,19 +992,16 @@ void IRRImporter::InternReadFile(const std::string &pFile,
// Materials can occur for nearly any type of node // Materials can occur for nearly any type of node
if (inMaterials && curNode->type != Node::DUMMY) { if (inMaterials && curNode->type != Node::DUMMY) {
/* This is a material description - parse it! // This is a material description - parse it!
*/
curNode->materials.push_back(std::pair<aiMaterial *, unsigned int>()); curNode->materials.push_back(std::pair<aiMaterial *, unsigned int>());
std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back(); std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back();
p.first = ParseMaterial(p.second); p.first = ParseMaterial(p.second);
++guessedMatCnt; ++guessedMatCnt;
continue; continue;
} else if (inAnimator) { } else if (inAnimator) {
/* This is an animation path - add a new animator // This is an animation path - add a new animator
* to the list. // to the list.
*/
curNode->animators.push_back(Animator()); curNode->animators.push_back(Animator());
curAnim = &curNode->animators.back(); curAnim = &curNode->animators.back();
@ -1023,9 +1011,12 @@ void IRRImporter::InternReadFile(const std::string &pFile,
/* Parse all elements in the attributes block /* Parse all elements in the attributes block
* and process them. * and process them.
*/ */
while (reader->read()) { // while (reader->read()) {
if (reader->getNodeType() == EXN_ELEMENT) { for (pugi::xml_node attrib : child.children()) {
if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) { if (attrib.type() == pugi::node_element) {
//if (reader->getNodeType() == EXN_ELEMENT) {
//if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
VectorProperty prop; VectorProperty prop;
ReadVectorProperty(prop); ReadVectorProperty(prop);
@ -1082,14 +1073,16 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
} else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop);
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") { if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
curAnim->loop = prop.value; curAnim->loop = prop.value;
} }
} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
} else if (!ASSIMP_stricmp(attrib.name(), "float")) {
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop);
@ -1137,7 +1130,8 @@ void IRRImporter::InternReadFile(const std::string &pFile,
curNode->sphereRadius = prop.value; curNode->sphereRadius = prop.value;
} }
} }
} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
} else if (!ASSIMP_stricmp(attrib.name(), "int")) {
IntProperty prop; IntProperty prop;
ReadIntProperty(prop); ReadIntProperty(prop);
@ -1146,7 +1140,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
curAnim->timeForWay = prop.value; curAnim->timeForWay = prop.value;
} }
} else { } else {
// sphere polgon numbers in each direction // sphere polygon numbers in each direction
if (Node::SPHERE == curNode->type) { if (Node::SPHERE == curNode->type) {
if (prop.name == "PolyCountX") { if (prop.name == "PolyCountX") {
@ -1156,7 +1150,8 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
} else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop);
if (prop.value.length()) { if (prop.value.length()) {
@ -1237,14 +1232,15 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) { //} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
} else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) {
break; break;
} }
} }
} }
break; break;
case EXN_ELEMENT_END: /*case EXN_ELEMENT_END:
// If we reached the end of a node, we need to continue processing its parent // If we reached the end of a node, we need to continue processing its parent
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) { if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
@ -1265,13 +1261,13 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) { } else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
inAnimator = false; inAnimator = false;
} }
break; break;*/
default: default:
// GCC complains that not all enumeration values are handled // GCC complains that not all enumeration values are handled
break; break;
} }
} //}
// Now iterate through all cameras and compute their final (horizontal) FOV // Now iterate through all cameras and compute their final (horizontal) FOV
for (aiCamera *cam : cameras) { for (aiCamera *cam : cameras) {
@ -1285,22 +1281,19 @@ void IRRImporter::InternReadFile(const std::string &pFile,
batch.LoadAll(); batch.LoadAll();
/* Allocate a tempoary scene data structure // Allocate a temporary scene data structure
*/
aiScene *tempScene = new aiScene(); aiScene *tempScene = new aiScene();
tempScene->mRootNode = new aiNode(); tempScene->mRootNode = new aiNode();
tempScene->mRootNode->mName.Set("<IRRRoot>"); tempScene->mRootNode->mName.Set("<IRRRoot>");
/* Copy the cameras to the output array // Copy the cameras to the output array
*/
if (!cameras.empty()) { if (!cameras.empty()) {
tempScene->mNumCameras = (unsigned int)cameras.size(); tempScene->mNumCameras = (unsigned int)cameras.size();
tempScene->mCameras = new aiCamera *[tempScene->mNumCameras]; tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras); ::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
} }
/* Copy the light sources to the output array // Copy the light sources to the output array
*/
if (!lights.empty()) { if (!lights.empty()) {
tempScene->mNumLights = (unsigned int)lights.size(); tempScene->mNumLights = (unsigned int)lights.size();
tempScene->mLights = new aiLight *[tempScene->mNumLights]; tempScene->mLights = new aiLight *[tempScene->mNumLights];
@ -1318,9 +1311,8 @@ void IRRImporter::InternReadFile(const std::string &pFile,
meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2)); meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
materials.reserve(guessedMatCnt + (guessedMatCnt >> 2)); materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
/* Now process our scenegraph recursively: generate final // Now process our scene-graph recursively: generate final
* meshes and generate animation channels for all nodes. // meshes and generate animation channels for all nodes.
*/
unsigned int defMatIdx = UINT_MAX; unsigned int defMatIdx = UINT_MAX;
GenerateGraph(root, tempScene->mRootNode, tempScene, GenerateGraph(root, tempScene->mRootNode, tempScene,
batch, meshes, anims, attach, materials, defMatIdx); batch, meshes, anims, attach, materials, defMatIdx);
@ -1351,37 +1343,31 @@ void IRRImporter::InternReadFile(const std::string &pFile,
::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *)); ::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
} }
/* Copy all materials to the output array // Copy all materials to the output array
*/
if (!materials.empty()) { if (!materials.empty()) {
tempScene->mNumMaterials = (unsigned int)materials.size(); tempScene->mNumMaterials = (unsigned int)materials.size();
tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials]; tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials); ::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
} }
/* Now merge all sub scenes and attach them to the correct // Now merge all sub scenes and attach them to the correct
* attachment points in the scenegraph. // attachment points in the scenegraph.
*/
SceneCombiner::MergeScenes(&pScene, tempScene, attach, SceneCombiner::MergeScenes(&pScene, tempScene, attach,
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
0)); 0));
/* If we have no meshes | no materials now set the INCOMPLETE // If we have no meshes | no materials now set the INCOMPLETE
* scene flag. This is necessary if we failed to load all // scene flag. This is necessary if we failed to load all
* models from external files // models from external files
*/
if (!pScene->mNumMeshes || !pScene->mNumMaterials) { if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE"); ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }
/* Finished ... everything destructs automatically and all // Finished ... everything destructs automatically and all
* temporary scenes have already been deleted by MergeScenes() // temporary scenes have already been deleted by MergeScenes()
*/
delete root; delete root;
delete reader;
} }
#endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER #endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IRRLoader.h /** @file IRRLoader.h
* @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format) * @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format)
* importer class. * importer class.
@ -83,7 +81,7 @@ protected:
private: private:
/** Data structure for a scenegraph node animator /** Data structure for a scene-graph node animator
*/ */
struct Animator { struct Animator {
// Type of the animator // Type of the animator
@ -129,7 +127,7 @@ private:
int timeForWay; int timeForWay;
}; };
/** Data structure for a scenegraph node in an IRR file /** Data structure for a scene-graph node in an IRR file
*/ */
struct Node struct Node
{ {
@ -227,8 +225,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Fill the scenegraph recursively /// Fill the scene-graph recursively
*/
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
BatchLoader& batch, BatchLoader& batch,
std::vector<aiMesh*>& meshes, std::vector<aiMesh*>& meshes,
@ -237,27 +234,22 @@ private:
std::vector<aiMaterial*>& materials, std::vector<aiMaterial*>& materials,
unsigned int& defaultMatIdx); unsigned int& defaultMatIdx);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Generate a mesh that consists of just a single quad /// Generate a mesh that consists of just a single quad
*/
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1, aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
const SkyboxVertex& v2, const SkyboxVertex& v2,
const SkyboxVertex& v3, const SkyboxVertex& v3,
const SkyboxVertex& v4); const SkyboxVertex& v4);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build a skybox /// Build a sky-box
* ///
* @param meshes Receives 6 output meshes /// @param meshes Receives 6 output meshes
* @param materials The last 6 materials are assigned to the newly /// @param materials The last 6 materials are assigned to the newly
* created meshes. The names of the materials are adjusted. /// created meshes. The names of the materials are adjusted.
*/
void BuildSkybox(std::vector<aiMesh*>& meshes, void BuildSkybox(std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*> materials); std::vector<aiMaterial*> materials);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Copy a material for a mesh to the output material list /** Copy a material for a mesh to the output material list
* *
@ -271,7 +263,6 @@ private:
unsigned int& defMatIdx, unsigned int& defMatIdx,
aiMesh* mesh); aiMesh* mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Compute animations for a specific node /** Compute animations for a specific node
* *
@ -281,13 +272,11 @@ private:
void ComputeAnimations(Node* root, aiNode* real, void ComputeAnimations(Node* root, aiNode* real,
std::vector<aiNodeAnim*>& anims); std::vector<aiNodeAnim*>& anims);
private: private:
/// Configuration option: desired output FPS
/** Configuration option: desired output FPS */
double fps; double fps;
/** Configuration option: speed flag was set? */ /// Configuration option: speed flag was set?
bool configSpeedFlag; bool configSpeedFlag;
}; };

View File

@ -43,24 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file Implementation of the IrrMesh importer class */ /** @file Implementation of the IrrMesh importer class */
#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
#include "IRRMeshLoader.h" #include "IRRMeshLoader.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <memory>
#include <assimp/IOSystem.hpp>
#include <assimp/mesh.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/material.h>
#include <assimp/scene.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp; using namespace Assimp;
using namespace irr;
using namespace irr::io;
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
"Irrlicht Mesh Reader", "Irrlicht Mesh Reader",
@ -77,18 +73,19 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
IRRMeshImporter::IRRMeshImporter() IRRMeshImporter::IRRMeshImporter() :
{} BaseImporter(),
IrrlichtBase() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
IRRMeshImporter::~IRRMeshImporter() IRRMeshImporter::~IRRMeshImporter() {}
{}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
{
/* NOTE: A simple check for the file extension is not enough /* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic * here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and * and could be collada, too. So we need to open the file and
@ -96,9 +93,9 @@ bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, b
*/ */
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
if (extension == "irrmesh")return true; if (extension == "irrmesh")
else if (extension == "xml" || checkSig) return true;
{ else if (extension == "xml" || checkSig) {
/* If CanRead() is called to check whether the loader /* If CanRead() is called to check whether the loader
* supports a specific file extension in general we * supports a specific file extension in general we
* must return true here. * must return true here.
@ -112,8 +109,7 @@ bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, b
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all file extensions which are handled by this class // Get a list of all file extensions which are handled by this class
const aiImporterDesc* IRRMeshImporter::GetInfo () const const aiImporterDesc *IRRMeshImporter::GetInfo() const {
{
return &desc; return &desc;
} }
@ -134,18 +130,19 @@ static void releaseMesh( aiMesh **mesh ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void IRRMeshImporter::InternReadFile(const std::string &pFile, void IRRMeshImporter::InternReadFile(const std::string &pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene *pScene, IOSystem *pIOHandler) {
{
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file // Check whether we can read from the file
if (file.get() == nullptr) { if (file.get() == NULL)
throw DeadlyImportError("Failed to open IRRMESH file " + pFile + "."); throw DeadlyImportError("Failed to open IRRMESH file " + pFile + "");
}
// Construct the irrXML parser // Construct the irrXML parser
CIrrXML_IOStreamReader st(file.get()); XmlParser parser;
reader = createIrrXMLReader((IFileReadCallBack*) &st); if (!parser.parse( file.get() )) {
return;
}
XmlNode root = parser.getRootNode();
// final data // final data
std::vector<aiMaterial *> materials; std::vector<aiMaterial *> materials;
@ -168,11 +165,9 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
bool useColors = false; bool useColors = false;
// Parse the XML file // Parse the XML file
while (reader->read()) { for (pugi::xml_node child : root.children()) {
switch (reader->getNodeType()) { if (child.type() == pugi::node_element) {
case EXN_ELEMENT: if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) {
if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) {
// end of previous buffer. A material and a mesh should be there // end of previous buffer. A material and a mesh should be there
if (!curMat || !curMesh) { if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
@ -194,17 +189,17 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curBitangents.clear(); curBitangents.clear();
} }
if (!ASSIMP_stricmp(child.name(), "material")) {
if (!ASSIMP_stricmp(reader->getNodeName(),"material")) {
if (curMat) { if (curMat) {
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please"); ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
releaseMaterial(&curMat); releaseMaterial(&curMat);
} }
curMat = ParseMaterial(curMatFlags); curMat = ParseMaterial(curMatFlags);
} }
/* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices")) /* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
{ pugi::xml_attribute attr = child.attribute("vertexCount");
int num = reader->getAttributeValueAsInt("vertexCount"); int num = attr.as_int();
//int num = reader->getAttributeValueAsInt("vertexCount");
if (!num) { if (!num) {
// This is possible ... remove the mesh from the list and skip further reading // This is possible ... remove the mesh from the list and skip further reading
@ -222,8 +217,9 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curUVs.reserve(num); curUVs.reserve(num);
// Determine the file format // Determine the file format
const char* t = reader->getAttributeValueSafe("type"); //const char *t = reader->getAttributeValueSafe("type");
if (!ASSIMP_stricmp("2tcoords", t)) { pugi::xml_attribute t = child.attribute("type");
if (!ASSIMP_stricmp("2tcoords", t.name())) {
curUV2s.reserve(num); curUV2s.reserve(num);
vertexFormat = 1; vertexFormat = 1;
@ -239,28 +235,23 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
if (curMatFlags & AI_IRRMESH_MAT_lightmap) { if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0)); mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
} } else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid){
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0)); mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
} } else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1)); mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
} }
} }
} } else if (!ASSIMP_stricmp("tangents", t.name())) {
else if (!ASSIMP_stricmp("tangents", t)) {
curTangents.reserve(num); curTangents.reserve(num);
curBitangents.reserve(num); curBitangents.reserve(num);
vertexFormat = 2; vertexFormat = 2;
} } else if (ASSIMP_stricmp("standard", t.name())) {
else if (ASSIMP_stricmp("standard", t)) {
releaseMaterial(&curMat); releaseMaterial(&curMat);
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format"); ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
} } else
else vertexFormat = 0; vertexFormat = 0;
textMeaning = 1; textMeaning = 1;
} } else if (!ASSIMP_stricmp(child.name(), "indices")) {
else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) {
if (curVertices.empty() && curMat) { if (curVertices.empty() && curMat) {
releaseMaterial(&curMat); releaseMaterial(&curMat);
throw DeadlyImportError("IRRMESH: indices must come after vertices"); throw DeadlyImportError("IRRMESH: indices must come after vertices");
@ -272,7 +263,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curMesh = new aiMesh(); curMesh = new aiMesh();
// allocate storage for all faces // allocate storage for all faces
curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount"); pugi::xml_attribute attr = child.attribute("indexCount");
curMesh->mNumVertices = attr.as_int();
if (!curMesh->mNumVertices) { if (!curMesh->mNumVertices) {
// This is possible ... remove the mesh from the list and skip further reading // This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices"); ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
@ -320,18 +312,18 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
} }
} }
break; //break;
case EXN_TEXT: //case EXN_TEXT: {
{ const char *sz = child.child_value();
const char* sz = reader->getNodeData();
if (textMeaning == 1) { if (textMeaning == 1) {
textMeaning = 0; textMeaning = 0;
// read vertices // read vertices
do { do {
SkipSpacesAndLineEnd(&sz); SkipSpacesAndLineEnd(&sz);
aiVector3D temp;aiColor4D c; aiVector3D temp;
aiColor4D c;
// Read the vertex position // Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x); sz = fast_atoreal_move<float>(sz, (float &)temp.x);
@ -365,7 +357,6 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curColors.push_back(c); curColors.push_back(c);
SkipSpaces(&sz); SkipSpaces(&sz);
// read the first UV coordinate set // read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x); sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz); SkipSpaces(&sz);
@ -419,8 +410,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
*/ */
while (SkipLine(&sz)); while (SkipLine(&sz));
} } else if (textMeaning == 2) {
else if (textMeaning == 2) {
textMeaning = 0; textMeaning = 0;
// read indices // read indices
@ -479,14 +469,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
aiMaterial *mat = (aiMaterial *)curMat; aiMaterial *mat = (aiMaterial *)curMat;
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY); mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
} }
}} }
break; }
default:
// GCC complains here ...
break;
};
} }
// End of the last buffer. A material and a mesh should be there // End of the last buffer. A material and a mesh should be there
@ -495,16 +479,15 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial(&curMat); releaseMaterial(&curMat);
releaseMesh(&curMesh); releaseMesh(&curMesh);
} } else {
else {
materials.push_back(curMat); materials.push_back(curMat);
meshes.push_back(curMesh); meshes.push_back(curMesh);
} }
} }
if (materials.empty()) if (materials.empty()) {
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file"); throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
}
// now generate the output scene // now generate the output scene
pScene->mNumMeshes = (unsigned int)meshes.size(); pScene->mNumMeshes = (unsigned int)meshes.size();
@ -525,12 +508,9 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mRootNode->mMeshes[i] = i; pScene->mRootNode->mMeshes[i] = i;
}
// clean up and return
delete reader;
AI_DEBUG_INVALIDATE_PTR(reader);
} }
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER #endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -47,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_IRRMESHLOADER_H_INCLUDED #ifndef AI_IRRMESHLOADER_H_INCLUDED
#define AI_IRRMESHLOADER_H_INCLUDED #define AI_IRRMESHLOADER_H_INCLUDED
#include <assimp/BaseImporter.h>
#include "IRRShared.h" #include "IRRShared.h"
#include <assimp/BaseImporter.h>
#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
@ -61,15 +60,11 @@ namespace Assimp {
* irrEdit. As IrrEdit itself is capable of importing quite many file formats, * irrEdit. As IrrEdit itself is capable of importing quite many file formats,
* it might be a good file format for data exchange. * it might be a good file format for data exchange.
*/ */
class IRRMeshImporter : public BaseImporter, public IrrlichtBase class IRRMeshImporter : public BaseImporter, public IrrlichtBase {
{
public: public:
IRRMeshImporter(); IRRMeshImporter();
~IRRMeshImporter(); ~IRRMeshImporter();
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. * See BaseImporter::CanRead() for details.
@ -78,7 +73,6 @@ public:
bool checkSig) const; bool checkSig) const;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
@ -91,7 +85,6 @@ protected:
*/ */
void InternReadFile(const std::string &pFile, aiScene *pScene, void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler); IOSystem *pIOHandler);
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -45,8 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Shared utilities for the IRR and IRRMESH loaders * @brief Shared utilities for the IRR and IRRMESH loaders
*/ */
//This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted. //This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER)) #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
@ -56,10 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/material.h> #include <assimp/material.h>
using namespace Assimp; using namespace Assimp;
using namespace irr;
using namespace irr::io;
// Transformation matrix to convert from Assimp to IRR space // Transformation matrix to convert from Assimp to IRR space
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 ( const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
@ -70,125 +63,94 @@ const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a property in hexadecimal format (i.e. ffffffff) // read a property in hexadecimal format (i.e. ffffffff)
void IrrlichtBase::ReadHexProperty (HexProperty& out) void IrrlichtBase::ReadHexProperty(HexProperty &out ) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")) {
{ out.name = std::string( attrib.value() );
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.name(),"value")) {
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// parse the hexadecimal value // parse the hexadecimal value
out.value = strtoul16(reader->getAttributeValue(i)); out.value = strtoul16(attrib.name());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a decimal property // read a decimal property
void IrrlichtBase::ReadIntProperty (IntProperty& out) void IrrlichtBase::ReadIntProperty(IntProperty & out) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")) {
{ out.name = std::string(attrib.value());
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.value(),"value")) {
{ // parse the int value
out.name = std::string( reader->getAttributeValue(i) ); out.value = strtol10(attrib.name());
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// parse the ecimal value
out.value = strtol10(reader->getAttributeValue(i));
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a string property // read a string property
void IrrlichtBase::ReadStringProperty (StringProperty& out) void IrrlichtBase::ReadStringProperty( StringProperty& out) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")) {
{ out.name = std::string(attrib.value());
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// simple copy the string // simple copy the string
out.value = std::string (reader->getAttributeValue(i)); out.value = std::string(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a boolean property // read a boolean property
void IrrlichtBase::ReadBoolProperty (BoolProperty& out) void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")){
{ out.name = std::string(attrib.value());
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// true or false, case insensitive // true or false, case insensitive
out.value = (ASSIMP_stricmp( reader->getAttributeValue(i), out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
"true") ? false : true);
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a float property // read a float property
void IrrlichtBase::ReadFloatProperty (FloatProperty& out) void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")) {
{ out.name = std::string(attrib.value());
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// just parse the float // just parse the float
out.value = fast_atof( reader->getAttributeValue(i) ); out.value = fast_atof(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a vector property // read a vector property
void IrrlichtBase::ReadVectorProperty (VectorProperty& out) void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
{ for (pugi::xml_attribute attrib : mNode->attributes()) {
for (int i = 0; i < reader->getAttributeCount();++i) if (!ASSIMP_stricmp(attrib.name(), "name")) {
{ out.name = std::string(attrib.value());
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name")) } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// three floats, separated with commas // three floats, separated with commas
const char* ptr = reader->getAttributeValue(i); const char *ptr = attrib.value();
SkipSpaces(&ptr); SkipSpaces(&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x ); ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) if (',' != *ptr) {
{
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
} }
else SkipSpaces(ptr+1,&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y ); ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) if (',' != *ptr) {
{
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
} }
else SkipSpaces(ptr+1,&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z ); ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
} }
} }
@ -196,22 +158,19 @@ void IrrlichtBase::ReadVectorProperty (VectorProperty& out)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a string to a proper aiMappingMode // Convert a string to a proper aiMappingMode
int ConvertMappingMode(const std::string& mode) int ConvertMappingMode(const std::string& mode) {
{ if (mode == "texture_clamp_repeat") {
if (mode == "texture_clamp_repeat")
{
return aiTextureMapMode_Wrap; return aiTextureMapMode_Wrap;
} } else if (mode == "texture_clamp_mirror") {
else if (mode == "texture_clamp_mirror")
return aiTextureMapMode_Mirror; return aiTextureMapMode_Mirror;
}
return aiTextureMapMode_Clamp; return aiTextureMapMode_Clamp;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Parse a material from the XML file // Parse a material from the XML file
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
{
aiMaterial* mat = new aiMaterial(); aiMaterial* mat = new aiMaterial();
aiColor4D clr; aiColor4D clr;
aiString s; aiString s;
@ -220,30 +179,17 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
int cnt = 0; // number of used texture channels int cnt = 0; // number of used texture channels
unsigned int nd = 0; unsigned int nd = 0;
// Continue reading from the file for (pugi::xml_node child : mNode->children()) {
while (reader->read()) if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
{
switch (reader->getNodeType())
{
case EXN_ELEMENT:
// Hex properties
if (!ASSIMP_stricmp(reader->getNodeName(),"color"))
{
HexProperty prop; HexProperty prop;
ReadHexProperty(prop); ReadHexProperty(prop);
if (prop.name == "Diffuse") if (prop.name == "Diffuse") {
{
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
} } else if (prop.name == "Ambient") {
else if (prop.name == "Ambient")
{
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
} } else if (prop.name == "Specular") {
else if (prop.name == "Specular")
{
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
} }
@ -253,127 +199,78 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
// emitted by the described surface. In fact I think // emitted by the described surface. In fact I think
// IRRLICHT ignores this property, too. // IRRLICHT ignores this property, too.
#if 0 #if 0
else if (prop.name == "Emissive") else if (prop.name == "Emissive") {
{
ColorFromARGBPacked(prop.value,clr); ColorFromARGBPacked(prop.value,clr);
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE); mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
} }
#endif #endif
} } else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
// Float properties
else if (!ASSIMP_stricmp(reader->getNodeName(),"float"))
{
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop);
if (prop.name == "Shininess") if (prop.name == "Shininess") {
{
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS); mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
} }
} } else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
// Bool properties
else if (!ASSIMP_stricmp(reader->getNodeName(),"bool"))
{
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop);
if (prop.name == "Wireframe") if (prop.name == "Wireframe") {
{
int val = (prop.value ? true : false); int val = (prop.value ? true : false);
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME); mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
} } else if (prop.name == "GouraudShading") {
else if (prop.name == "GouraudShading") int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
{
int val = (prop.value ? aiShadingMode_Gouraud
: aiShadingMode_NoShading);
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL); mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
} } else if (prop.name == "BackfaceCulling") {
else if (prop.name == "BackfaceCulling")
{
int val = (!prop.value); int val = (!prop.value);
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED); mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
} }
} } else if (!ASSIMP_stricmp(child.name(), "texture") ||
// String properties - textures and texture related properties !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
else if (!ASSIMP_stricmp(reader->getNodeName(),"texture") ||
!ASSIMP_stricmp(reader->getNodeName(),"enum"))
{
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop);
if (prop.value.length()) if (prop.value.length()) {
{
// material type (shader) // material type (shader)
if (prop.name == "Type") if (prop.name == "Type") {
{ if (prop.value == "solid") {
if (prop.value == "solid")
{
// default material ... // default material ...
} } else if (prop.value == "trans_vertex_alpha") {
else if (prop.value == "trans_vertex_alpha")
{
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha; matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
} } else if (prop.value == "lightmap") {
else if (prop.value == "lightmap")
{
matFlags = AI_IRRMESH_MAT_lightmap; matFlags = AI_IRRMESH_MAT_lightmap;
} } else if (prop.value == "solid_2layer") {
else if (prop.value == "solid_2layer")
{
matFlags = AI_IRRMESH_MAT_solid_2layer; matFlags = AI_IRRMESH_MAT_solid_2layer;
} } else if (prop.value == "lightmap_m2") {
else if (prop.value == "lightmap_m2")
{
matFlags = AI_IRRMESH_MAT_lightmap_m2; matFlags = AI_IRRMESH_MAT_lightmap_m2;
} } else if (prop.value == "lightmap_m4") {
else if (prop.value == "lightmap_m4")
{
matFlags = AI_IRRMESH_MAT_lightmap_m4; matFlags = AI_IRRMESH_MAT_lightmap_m4;
} } else if (prop.value == "lightmap_light") {
else if (prop.value == "lightmap_light")
{
matFlags = AI_IRRMESH_MAT_lightmap_light; matFlags = AI_IRRMESH_MAT_lightmap_light;
} } else if (prop.value == "lightmap_light_m2") {
else if (prop.value == "lightmap_light_m2")
{
matFlags = AI_IRRMESH_MAT_lightmap_light_m2; matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
} } else if (prop.value == "lightmap_light_m4") {
else if (prop.value == "lightmap_light_m4")
{
matFlags = AI_IRRMESH_MAT_lightmap_light_m4; matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
} } else if (prop.value == "lightmap_add") {
else if (prop.value == "lightmap_add")
{
matFlags = AI_IRRMESH_MAT_lightmap_add; matFlags = AI_IRRMESH_MAT_lightmap_add;
} } else if (prop.value == "normalmap_solid" ||
// Normal and parallax maps are treated equally prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
else if (prop.value == "normalmap_solid" ||
prop.value == "parallaxmap_solid")
{
matFlags = AI_IRRMESH_MAT_normalmap_solid; matFlags = AI_IRRMESH_MAT_normalmap_solid;
} } else if (prop.value == "normalmap_trans_vertex_alpha" ||
else if (prop.value == "normalmap_trans_vertex_alpha" || prop.value == "parallaxmap_trans_vertex_alpha") {
prop.value == "parallaxmap_trans_vertex_alpha")
{
matFlags = AI_IRRMESH_MAT_normalmap_tva; matFlags = AI_IRRMESH_MAT_normalmap_tva;
} } else if (prop.value == "normalmap_trans_add" ||
else if (prop.value == "normalmap_trans_add" || prop.value == "parallaxmap_trans_add") {
prop.value == "parallaxmap_trans_add")
{
matFlags = AI_IRRMESH_MAT_normalmap_ta; matFlags = AI_IRRMESH_MAT_normalmap_ta;
} } else {
else {
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: " + prop.value); ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: " + prop.value);
} }
} }
// Up to 4 texture channels are supported // Up to 4 texture channels are supported
if (prop.name == "Texture1") if (prop.name == "Texture1") {
{
// Always accept the primary texture channel // Always accept the primary texture channel
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
} } else if (prop.name == "Texture2" && cnt == 1) {
else if (prop.name == "Texture2" && cnt == 1)
{
// 2-layer material lightmapped? // 2-layer material lightmapped?
if (matFlags & AI_IRRMESH_MAT_lightmap) { if (matFlags & AI_IRRMESH_MAT_lightmap) {
++cnt; ++cnt;
@ -382,9 +279,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} } else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
// alternatively: normal or parallax mapping
else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) {
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
@ -415,49 +310,39 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
} }
// Texture mapping options // Texture mapping options
if (prop.name == "TextureWrap1" && cnt >= 1) if (prop.name == "TextureWrap1" && cnt >= 1) {
{
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
} } else if (prop.name == "TextureWrap2" && cnt >= 2) {
else if (prop.name == "TextureWrap2" && cnt >= 2)
{
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
if (matFlags & AI_IRRMESH_MAT_lightmap) { if (matFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
} } else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
} } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
} }
} } else if (prop.name == "TextureWrap3" && cnt >= 3) {
else if (prop.name == "TextureWrap3" && cnt >= 3)
{
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
} } else if (prop.name == "TextureWrap4" && cnt >= 4) {
else if (prop.name == "TextureWrap4" && cnt >= 4)
{
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
} }
} }
} }
break; //break;
case EXN_ELEMENT_END: /*case EXN_ELEMENT_END:
/* Assume there are no further nested nodes in <material> elements // Assume there are no further nested nodes in <material> elements
*/ if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
if (/* IRRMESH */ !ASSIMP_stricmp(reader->getNodeName(),"material") || !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
/* IRR */ !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
{ {
// Now process lightmapping flags // Now process lightmapping flags
// We should have at least one textur to do that .. // We should have at least one textur to do that ..
@ -492,6 +377,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
// GCC complains here ... // GCC complains here ...
break; break;
} }
}*/
} }
ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete"); ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");

View File

@ -7,20 +7,18 @@
#ifndef INCLUDED_AI_IRRSHARED_H #ifndef INCLUDED_AI_IRRSHARED_H
#define INCLUDED_AI_IRRSHARED_H #define INCLUDED_AI_IRRSHARED_H
#include <assimp/irrXMLWrapper.h>
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h>
#include <stdint.h> #include <stdint.h>
struct aiMaterial; struct aiMaterial;
namespace Assimp { namespace Assimp {
/** @brief Matrix to convert from Assimp to IRR and backwards /** @brief Matrix to convert from Assimp to IRR and backwards
*/ */
extern const aiMatrix4x4 AI_TO_IRR_MATRIX; extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
// Default: 0 = solid, one texture // Default: 0 = solid, one texture
#define AI_IRRMESH_MAT_solid_2layer 0x10000 #define AI_IRRMESH_MAT_solid_2layer 0x10000
@ -58,15 +56,21 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
* Declares some irrlight-related xml parsing utilities and provides tools * Declares some irrlight-related xml parsing utilities and provides tools
* to load materials from IRR and IRRMESH files. * to load materials from IRR and IRRMESH files.
*/ */
class IrrlichtBase class IrrlichtBase {
{
protected: protected:
IrrlichtBase() :
mNode(nullptr) {
// empty
}
~IrrlichtBase() {
// empty
}
/** @brief Data structure for a simple name-value property /** @brief Data structure for a simple name-value property
*/ */
template <class T> template <class T>
struct Property struct Property {
{
std::string name; std::string name;
T value; T value;
}; };
@ -78,9 +82,9 @@ protected:
typedef Property<aiVector3D> VectorProperty; typedef Property<aiVector3D> VectorProperty;
typedef Property<int> IntProperty; typedef Property<int> IntProperty;
/** XML reader instance /// XML reader instance
*/ XmlParser mParser;
irr::io::IrrXMLReader* reader; pugi::xml_node *mNode;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Parse a material description from the XML /** Parse a material description from the XML
@ -101,18 +105,15 @@ protected:
void ReadIntProperty(IntProperty &out); void ReadIntProperty(IntProperty &out);
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Unpack a hex color, e.g. 0xdcdedfff // Unpack a hex color, e.g. 0xdcdedfff
inline void ColorFromARGBPacked(uint32_t in, aiColor4D& clr) inline void ColorFromARGBPacked(uint32_t in, aiColor4D &clr) {
{
clr.a = ((in >> 24) & 0xff) / 255.f; clr.a = ((in >> 24) & 0xff) / 255.f;
clr.r = ((in >> 16) & 0xff) / 255.f; clr.r = ((in >> 16) & 0xff) / 255.f;
clr.g = ((in >> 8) & 0xff) / 255.f; clr.g = ((in >> 8) & 0xff) / 255.f;
clr.b = ((in)&0xff) / 255.f; clr.b = ((in)&0xff) / 255.f;
} }
} // end namespace Assimp } // end namespace Assimp
#endif // !! INCLUDED_AI_IRRSHARED_H #endif // !! INCLUDED_AI_IRRSHARED_H

View File

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

View File

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

View File

@ -197,12 +197,15 @@ M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
break; break;
case m3dpf_float: case m3dpf_float:
if (mat->Get(aiProps[k].pKey, aiProps[k].type, if (mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, f) == AI_SUCCESS) aiProps[k].index, f) == AI_SUCCESS) {
uint32_t f_uint32;
memcpy(&f_uint32, &f, sizeof(uint32_t));
addProp(&m3d->material[mi], addProp(&m3d->material[mi],
m3d_propertytypes[k].id, m3d_propertytypes[k].id,
/* not (uint32_t)f, because we don't want to convert /* not (uint32_t)f, because we don't want to convert
* it, we want to see it as 32 bits of memory */ * it, we want to see it as 32 bits of memory */
*((uint32_t *)&f)); f_uint32);
}
break; break;
case m3dpf_uint8: case m3dpf_uint8:
if (mat->Get(aiProps[k].pKey, aiProps[k].type, if (mat->Get(aiProps[k].pKey, aiProps[k].type,

View File

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

View File

@ -133,6 +133,9 @@ unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
saved_output_ = m3d_save(m3d_, quality, flags, &size); saved_output_ = m3d_save(m3d_, quality, flags, &size);
return saved_output_; return saved_output_;
#else #else
(void)quality;
(void)flags;
(void)size;
return nullptr; return nullptr;
#endif #endif
} }

View File

@ -84,7 +84,7 @@ typedef uint16_t M3D_INDEX;
#ifndef M3D_BONEMAXLEVEL #ifndef M3D_BONEMAXLEVEL
#define M3D_BONEMAXLEVEL 8 #define M3D_BONEMAXLEVEL 8
#endif #endif
#ifndef _MSC_VER #if !defined(_MSC_VER) || defined(__clang__)
#ifndef _inline #ifndef _inline
#define _inline __inline__ #define _inline __inline__
#endif #endif
@ -101,13 +101,13 @@ typedef uint16_t M3D_INDEX;
#define _register #define _register
#endif #endif
#if _MSC_VER > 1920 #if _MSC_VER > 1920 && !defined(__clang__)
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4100 4127 4189 4505 4244 4403 4701 4703) # pragma warning(disable : 4100 4127 4189 4505 4244 4403 4701 4703)
# if (_MSC_VER > 1800 ) # if (_MSC_VER > 1800 )
# pragma warning(disable : 5573 5744) # pragma warning(disable : 5573 5744)
# endif # endif
#endif // _WIN32 #endif // _MSC_VER
/*** File format structures ***/ /*** File format structures ***/
@ -686,7 +686,11 @@ typedef struct
} _m3dstbi__result_info; } _m3dstbi__result_info;
#define STBI_ASSERT(v) #define STBI_ASSERT(v)
#ifdef _MSC_VER
#define STBI_NOTUSED(v) (void)(v)
#else
#define STBI_NOTUSED(v) (void)sizeof(v) #define STBI_NOTUSED(v) (void)sizeof(v)
#endif
#define STBI__BYTECAST(x) ((unsigned char)((x)&255)) #define STBI__BYTECAST(x) ((unsigned char)((x)&255))
#define STBI_MALLOC(sz) M3D_MALLOC(sz) #define STBI_MALLOC(sz) M3D_MALLOC(sz)
#define STBI_REALLOC(p, newsz) M3D_REALLOC(p, newsz) #define STBI_REALLOC(p, newsz) M3D_REALLOC(p, newsz)
@ -699,10 +703,6 @@ _inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s) {
return 0; return 0;
} }
_inline static int _m3dstbi__at_eof(_m3dstbi__context *s) {
return s->img_buffer >= s->img_buffer_end;
}
static void _m3dstbi__skip(_m3dstbi__context *s, int n) { static void _m3dstbi__skip(_m3dstbi__context *s, int n) {
if (n < 0) { if (n < 0) {
s->img_buffer = s->img_buffer_end; s->img_buffer = s->img_buffer_end;
@ -3590,7 +3590,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
case 4: f = (float)(*((float *)(data + 0))); break; case 4: f = (float)(*((float *)(data + 0))); break;
case 8: f = (float)(*((double *)(data + 0))); break; case 8: f = (float)(*((double *)(data + 0))); break;
} }
h->cmd[i].arg[k] = *((uint32_t *)&f); memcpy(&(h->cmd[i].arg[k]), &f, sizeof(uint32_t));
data += model->vc_s; data += model->vc_s;
break; break;
case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break; case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break;
@ -4347,7 +4347,7 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s; char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s;
char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL; char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL;
unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE], *norm = NULL; unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE], *norm = NULL;
unsigned int i, j, k, l, n, len, chunklen, *length; unsigned int i = 0, j = 0, k = 0, l = 0, n = 0, len = 0, chunklen = 0, *length = NULL;
M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z; M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z;
M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL;
uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0;
@ -5578,9 +5578,9 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
} else } else
out--; out--;
break; break;
case m3dpf_uint8: *out++ = m->prop[i].value.num; break; case m3dpf_uint8: *out++ = (uint8_t)m->prop[i].value.num; break;
case m3dpf_uint16: case m3dpf_uint16:
*((uint16_t *)out) = m->prop[i].value.num; *((uint16_t *)out) = (uint16_t)m->prop[i].value.num;
out += 2; out += 2;
break; break;
case m3dpf_uint32: case m3dpf_uint32:
@ -5655,7 +5655,7 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ? face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ?
0 : 0 :
2); 2);
*out++ = k; *out++ = (uint8_t)k;
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]); out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]);
if (k & 1) if (k & 1)
@ -5889,7 +5889,7 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
} }
#endif #endif
#endif #endif /* M3D_IMPLEMENTATION */
#ifdef __cplusplus #ifdef __cplusplus
} }
@ -6147,11 +6147,11 @@ public:
#endif /* impl */ #endif /* impl */
} // namespace M3D } // namespace M3D
#ifdef _WIN32 #endif /* M3D_CPPWRAPPER */
# pragma warning(pop)
#endif // _WIN32
#endif #if _MSC_VER > 1920 && !defined(__clang__)
# pragma warning(pop)
#endif /* _MSC_VER */
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -234,35 +234,6 @@ inline char_t getFloat(char_t it, char_t end, ai_real &value) {
return it; return it;
} }
/** @brief Will perform a simple tokenize.
* @param str String to tokenize.
* @param tokens Array with tokens, will be empty if no token was found.
* @param delimiters Delimiter for tokenize.
* @return Number of found token.
*/
template <class string_type>
unsigned int tokenize(const string_type &str, std::vector<string_type> &tokens,
const string_type &delimiters) {
// Skip delimiters at beginning.
typename string_type::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
typename string_type::size_type pos = str.find_first_of(delimiters, lastPos);
while (string_type::npos != pos || string_type::npos != lastPos) {
// Found a token, add it to the vector.
string_type tmp = str.substr(lastPos, pos - lastPos);
if (!tmp.empty() && ' ' != tmp[0])
tokens.push_back(tmp);
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
return static_cast<unsigned int>(tokens.size());
}
template <class string_type> template <class string_type>
string_type trim_whitespaces(string_type str) { string_type trim_whitespaces(string_type str) {

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -48,16 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OgreStructs.h" #include "OgreStructs.h"
#include <assimp/StreamReader.h> #include <assimp/StreamReader.h>
namespace Assimp namespace Assimp {
{ namespace Ogre {
namespace Ogre
{
typedef Assimp::StreamReaderLE MemoryStreamReader; typedef Assimp::StreamReaderLE MemoryStreamReader;
typedef std::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr; typedef std::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr;
class OgreBinarySerializer class OgreBinarySerializer {
{
public: public:
/// Imports mesh and returns the result. /// Imports mesh and returns the result.
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ /** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
@ -71,8 +67,7 @@ public:
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
private: private:
enum AssetMode enum AssetMode {
{
AM_Mesh, AM_Mesh,
AM_Skeleton AM_Skeleton
}; };
@ -80,8 +75,7 @@ private:
OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) : OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
m_currentLen(0), m_currentLen(0),
m_reader(reader), m_reader(reader),
assetMode(mode) assetMode(mode) {
{
} }
static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
@ -158,8 +152,7 @@ private:
AssetMode assetMode; AssetMode assetMode;
}; };
enum MeshChunkId enum MeshChunkId {
{
M_HEADER = 0x1000, M_HEADER = 0x1000,
// char* version : Version number check // char* version : Version number check
M_MESH = 0x3000, M_MESH = 0x3000,
@ -353,8 +346,7 @@ static std::string MeshHeaderToString(MeshChunkId id)
} }
*/ */
enum SkeletonChunkId enum SkeletonChunkId {
{
SKELETON_HEADER = 0x1000, SKELETON_HEADER = 0x1000,
// char* version : Version number check // char* version : Version number check
SKELETON_BLENDMODE = 0x1010, // optional SKELETON_BLENDMODE = 0x1010, // optional
@ -416,8 +408,8 @@ static std::string SkeletonHeaderToString(SkeletonChunkId id)
return "Unknown_SkeletonChunkId"; return "Unknown_SkeletonChunkId";
} }
*/ */
} // Ogre } // namespace Ogre
} // Assimp } // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
#endif // AI_OGREBINARYSERIALIZER_H_INC #endif // AI_OGREBINARYSERIALIZER_H_INC

View File

@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OgreImporter.h" #include "OgreImporter.h"
#include "OgreBinarySerializer.h" #include "OgreBinarySerializer.h"
#include "OgreXmlSerializer.h" #include "OgreXmlSerializer.h"
#include <assimp/Importer.hpp>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/Importer.hpp>
#include <memory> #include <memory>
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
@ -61,51 +61,41 @@ static const aiImporterDesc desc = {
"mesh mesh.xml" "mesh mesh.xml"
}; };
namespace Assimp namespace Assimp {
{ namespace Ogre {
namespace Ogre
{
const aiImporterDesc* OgreImporter::GetInfo() const const aiImporterDesc *OgreImporter::GetInfo() const {
{
return &desc; return &desc;
} }
void OgreImporter::SetupProperties(const Importer* pImp) void OgreImporter::SetupProperties(const Importer *pImp) {
{
m_userDefinedMaterialLibFile = pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material"); m_userDefinedMaterialLibFile = pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false); m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
} }
bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const {
{
if (!checkSig) { if (!checkSig) {
return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false); return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
} }
if (EndsWith(pFile, ".mesh.xml", false)) if (EndsWith(pFile, ".mesh.xml", false)) {
{
const char *tokens[] = { "<mesh>" }; const char *tokens[] = { "<mesh>" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} } else {
else
{
/// @todo Read and validate first header chunk? /// @todo Read and validate first header chunk?
return EndsWith(pFile, ".mesh", false); return EndsWith(pFile, ".mesh", false);
} }
} }
void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) {
{
// Open source file // Open source file
IOStream *f = pIOHandler->Open(pFile, "rb"); IOStream *f = pIOHandler->Open(pFile, "rb");
if (!f) { if (!f) {
throw DeadlyImportError("Failed to open file " + pFile); throw DeadlyImportError("Failed to open file ", pFile);
} }
// Binary .mesh import // Binary .mesh import
if (EndsWith(pFile, ".mesh", false)) if (EndsWith(pFile, ".mesh", false)) {
{
/// @note MemoryStreamReader takes ownership of f. /// @note MemoryStreamReader takes ownership of f.
MemoryStreamReader reader(f); MemoryStreamReader reader(f);
@ -122,15 +112,16 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
mesh->ConvertToAssimpScene(pScene); mesh->ConvertToAssimpScene(pScene);
} }
// XML .mesh.xml import // XML .mesh.xml import
else else {
{
/// @note XmlReader does not take ownership of f, hence the scoped ptr. /// @note XmlReader does not take ownership of f, hence the scoped ptr.
std::unique_ptr<IOStream> scopedFile(f); std::unique_ptr<IOStream> scopedFile(f);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get())); XmlParser xmlParser;
std::unique_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
//std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get()));
//std::unique_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
xmlParser.parse(scopedFile.get());
// Import mesh // Import mesh
std::unique_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(reader.get())); std::unique_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(&xmlParser));
// Import skeleton // Import skeleton
OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get()); OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get());
@ -143,7 +134,7 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
} }
} }
} // Ogre } // namespace Ogre
} // Assimp } // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -46,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <memory> #include <memory>
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
@ -56,128 +56,80 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace Ogre { namespace Ogre {
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; //AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) {
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
if (!error.empty()) { if (!error.empty()) {
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'");
} else { } else {
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); throw DeadlyImportError("Attribute '", name, "' does not exist in node '", nodeName, "'");
} }
} }
template <> template <>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const { int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(xmlNode.name(), name, "Not found");
} }
pugi::xml_attribute attr = xmlNode.attribute(name);
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name)); return static_cast<int32_t>(attr.as_int());
} }
template <> template <>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const { uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(xmlNode.name(), name, "Not found");
} }
// @note This is hackish. But we are never expecting unsigned values that go outside the // @note This is hackish. But we are never expecting unsigned values that go outside the
// int32_t range. Just monitor for negative numbers and kill the import. // int32_t range. Just monitor for negative numbers and kill the import.
int32_t temp = ReadAttribute<int32_t>(name); int32_t temp = ReadAttribute<int32_t>(xmlNode, name);
if (temp < 0) { if (temp < 0) {
ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value"); ThrowAttibuteError(xmlNode.name(), name, "Found a negative number value where expecting a uint32_t value");
} }
return static_cast<uint32_t>(temp); return static_cast<uint32_t>(temp);
} }
template <> template <>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const { uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(xmlNode.name(), name, "Not found");
} }
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name)); return static_cast<uint16_t>(xmlNode.attribute(name).as_int());
} }
template <> template <>
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const { float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(xmlNode.name(), name, "Not found");
} }
return m_reader->getAttributeValueAsFloat(name); return xmlNode.attribute(name).as_float();
} }
template <> template <>
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const { std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const {
const char *value = m_reader->getAttributeValue(name); if (!XmlParser::hasAttribute(xmlNode, name)) {
if (nullptr == value) { ThrowAttibuteError(xmlNode.name(), name, "Not found");
ThrowAttibuteError(m_reader, name);
} }
return std::string(value); return xmlNode.attribute(name).as_string();
} }
template <> template <>
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const { bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name) const {
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name)); std::string value = Ogre::ToLower(ReadAttribute<std::string>(xmlNode, name));
if (ASSIMP_stricmp(value, "true") == 0) { if (ASSIMP_stricmp(value, "true") == 0) {
return true; return true;
} else if (ASSIMP_stricmp(value, "false") == 0) { } else if (ASSIMP_stricmp(value, "false") == 0) {
return false; return false;
} else { }
ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
ThrowAttibuteError(xmlNode.name(), name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
return false; return false;
} }
}
bool OgreXmlSerializer::HasAttribute(const char *name) const {
return (m_reader->getAttributeValue(name) != 0);
}
std::string &OgreXmlSerializer::NextNode() {
do {
if (!m_reader->read()) {
m_currentNodeName = "";
return m_currentNodeName;
}
} while (m_reader->getNodeType() != irr::io::EXN_ELEMENT);
CurrentNodeName(true);
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
ASSIMP_LOG_DEBUG"<" + m_currentNodeName + ">");
#endif
return m_currentNodeName;
}
bool OgreXmlSerializer::CurrentNodeNameEquals(const std::string &name) const {
return (ASSIMP_stricmp(m_currentNodeName, name) == 0);
}
std::string OgreXmlSerializer::CurrentNodeName(bool forceRead) {
if (forceRead)
m_currentNodeName = std::string(m_reader->getNodeName());
return m_currentNodeName;
}
std::string &OgreXmlSerializer::SkipCurrentNode() {
#if (OGRE_XML_SERIALIZER_DEBUG == 1)
ASSIMP_LOG_DEBUG("Skipping node <" + m_currentNodeName + ">");
#endif
for (;;) {
if (!m_reader->read()) {
m_currentNodeName = "";
return m_currentNodeName;
}
if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END) {
continue;
} else if (std::string(m_reader->getNodeName()) == m_currentNodeName) {
break;
}
}
return NextNode();
}
// Mesh XML constants // Mesh XML constants
@ -186,18 +138,18 @@ static const char *nnMesh = "mesh";
static const char *nnSharedGeometry = "sharedgeometry"; static const char *nnSharedGeometry = "sharedgeometry";
static const char *nnSubMeshes = "submeshes"; static const char *nnSubMeshes = "submeshes";
static const char *nnSubMesh = "submesh"; static const char *nnSubMesh = "submesh";
static const char *nnSubMeshNames = "submeshnames"; //static const char *nnSubMeshNames = "submeshnames";
static const char *nnSkeletonLink = "skeletonlink"; static const char *nnSkeletonLink = "skeletonlink";
static const char *nnLOD = "levelofdetail"; //static const char *nnLOD = "levelofdetail";
static const char *nnExtremes = "extremes"; //static const char *nnExtremes = "extremes";
static const char *nnPoses = "poses"; //static const char *nnPoses = "poses";
static const char *nnAnimations = "animations"; static const char *nnAnimations = "animations";
// <submesh> // <submesh>
static const char *nnFaces = "faces"; static const char *nnFaces = "faces";
static const char *nnFace = "face"; static const char *nnFace = "face";
static const char *nnGeometry = "geometry"; static const char *nnGeometry = "geometry";
static const char *nnTextures = "textures"; //static const char *nnTextures = "textures";
// <mesh/submesh> // <mesh/submesh>
static const char *nnBoneAssignments = "boneassignments"; static const char *nnBoneAssignments = "boneassignments";
@ -206,14 +158,14 @@ static const char *nnBoneAssignments = "boneassignments";
static const char *nnVertexBuffer = "vertexbuffer"; static const char *nnVertexBuffer = "vertexbuffer";
// <vertexbuffer> // <vertexbuffer>
static const char *nnVertex = "vertex"; //static const char *nnVertex = "vertex";
static const char *nnPosition = "position"; static const char *nnPosition = "position";
static const char *nnNormal = "normal"; static const char *nnNormal = "normal";
static const char *nnTangent = "tangent"; static const char *nnTangent = "tangent";
static const char *nnBinormal = "binormal"; //static const char *nnBinormal = "binormal";
static const char *nnTexCoord = "texcoord"; static const char *nnTexCoord = "texcoord";
static const char *nnColorDiffuse = "colour_diffuse"; //static const char *nnColorDiffuse = "colour_diffuse";
static const char *nnColorSpecular = "colour_specular"; //static const char *nnColorSpecular = "colour_specular";
// <boneassignments> // <boneassignments>
static const char *nnVertexBoneAssignment = "vertexboneassignment"; static const char *nnVertexBoneAssignment = "vertexboneassignment";
@ -224,7 +176,7 @@ static const char *nnVertexBoneAssignment = "vertexboneassignment";
static const char *nnSkeleton = "skeleton"; static const char *nnSkeleton = "skeleton";
static const char *nnBones = "bones"; static const char *nnBones = "bones";
static const char *nnBoneHierarchy = "bonehierarchy"; static const char *nnBoneHierarchy = "bonehierarchy";
static const char *nnAnimationLinks = "animationlinks"; //static const char *nnAnimationLinks = "animationlinks";
// <bones> // <bones>
static const char *nnBone = "bone"; static const char *nnBone = "bone";
@ -247,15 +199,23 @@ static const char *nnTranslate = "translate";
static const char *nnRotate = "rotate"; static const char *nnRotate = "rotate";
// Common XML constants // Common XML constants
static const char *anX = "x"; static const char *anX = "x";
static const char *anY = "y"; static const char *anY = "y";
static const char *anZ = "z"; static const char *anZ = "z";
// Mesh // Mesh
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) { OgreXmlSerializer::OgreXmlSerializer(XmlParser *parser) :
OgreXmlSerializer serializer(reader); mParser(parser) {
// empty
}
MeshXml *OgreXmlSerializer::ImportMesh(XmlParser *parser) {
if (nullptr == parser) {
return nullptr;
}
OgreXmlSerializer serializer(parser);
MeshXml *mesh = new MeshXml(); MeshXml *mesh = new MeshXml();
serializer.ReadMesh(mesh); serializer.ReadMesh(mesh);
@ -264,60 +224,53 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
} }
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
if (NextNode() != nnMesh) { XmlNode root = mParser->getRootNode();
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>"); if (nullptr == root) {
throw DeadlyImportError("Root node is <" + std::string(root.name()) + "> expecting <mesh>");
}
XmlNode startNode = root.child(nnMesh);
if (startNode.empty()) {
throw DeadlyImportError("Root node is <" + std::string(root.name()) + "> expecting <mesh>");
}
for (XmlNode currentNode : startNode.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnSharedGeometry) {
mesh->sharedVertexData = new VertexDataXml();
ReadGeometry(currentNode, mesh->sharedVertexData);
} else if (currentName == nnSubMeshes) {
for (XmlNode &subMeshesNode : currentNode.children()) {
const std::string &currentSMName = subMeshesNode.name();
if (currentSMName == nnSubMesh) {
ReadSubMesh(subMeshesNode, mesh);
}
}
} else if (currentName == nnBoneAssignments) {
ReadBoneAssignments(currentNode, mesh->sharedVertexData);
} else if (currentName == nnSkeletonLink) {
}
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh");
NextNode();
// Root level nodes
while (m_currentNodeName == nnSharedGeometry ||
m_currentNodeName == nnSubMeshes ||
m_currentNodeName == nnSkeletonLink ||
m_currentNodeName == nnBoneAssignments ||
m_currentNodeName == nnLOD ||
m_currentNodeName == nnSubMeshNames ||
m_currentNodeName == nnExtremes ||
m_currentNodeName == nnPoses ||
m_currentNodeName == nnAnimations) {
if (m_currentNodeName == nnSharedGeometry) {
mesh->sharedVertexData = new VertexDataXml();
ReadGeometry(mesh->sharedVertexData);
} else if (m_currentNodeName == nnSubMeshes) {
NextNode();
while (m_currentNodeName == nnSubMesh) {
ReadSubMesh(mesh);
}
} else if (m_currentNodeName == nnBoneAssignments) {
ReadBoneAssignments(mesh->sharedVertexData);
} else if (m_currentNodeName == nnSkeletonLink) {
mesh->skeletonRef = ReadAttribute<std::string>("name");
ASSIMP_LOG_VERBOSE_DEBUG_F("Read skeleton link ", mesh->skeletonRef);
NextNode();
}
// Assimp incompatible/ignored nodes
else
SkipCurrentNode();
}
} }
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) { void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) {
dest->count = ReadAttribute<uint32_t>("vertexcount"); dest->count = ReadAttribute<uint32_t>(node, "vertexcount");
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices"); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices");
NextNode(); for (XmlNode currentNode : node.children()) {
while (m_currentNodeName == nnVertexBuffer) { const std::string &currentName = currentNode.name();
ReadGeometryVertexBuffer(dest); if (currentName == nnVertexBuffer) {
ReadGeometryVertexBuffer(currentNode, dest);
}
} }
} }
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) {
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions")); bool positions = (XmlParser::hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions"));
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals")); bool normals = (XmlParser::hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals"));
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents")); bool tangents = (XmlParser::hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents"));
uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0); uint32_t uvs = (XmlParser::hasAttribute(node, "texture_coords") ? ReadAttribute<uint32_t>(node, "texture_coords") : 0);
// Not having positions is a error only if a previous vertex buffer did not have them. // Not having positions is a error only if a previous vertex buffer did not have them.
if (!positions && !dest->HasPositions()) { if (!positions && !dest->HasPositions()) {
@ -344,109 +297,57 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
} }
} }
bool warnBinormal = true; for (XmlNode currentNode : node.children("vertex")) {
bool warnColorDiffuse = true; for (XmlNode vertexNode : currentNode.children()) {
bool warnColorSpecular = true; const std::string &currentName = vertexNode.name();
if (positions && currentName == nnPosition) {
NextNode();
while (m_currentNodeName == nnVertex ||
m_currentNodeName == nnPosition ||
m_currentNodeName == nnNormal ||
m_currentNodeName == nnTangent ||
m_currentNodeName == nnBinormal ||
m_currentNodeName == nnTexCoord ||
m_currentNodeName == nnColorDiffuse ||
m_currentNodeName == nnColorSpecular) {
if (m_currentNodeName == nnVertex) {
NextNode();
}
/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
if (positions && m_currentNodeName == nnPosition) {
aiVector3D pos; aiVector3D pos;
pos.x = ReadAttribute<float>(anX); pos.x = ReadAttribute<float>(vertexNode, anX);
pos.y = ReadAttribute<float>(anY); pos.y = ReadAttribute<float>(vertexNode, anY);
pos.z = ReadAttribute<float>(anZ); pos.z = ReadAttribute<float>(vertexNode, anZ);
dest->positions.push_back(pos); dest->positions.push_back(pos);
} else if (normals && m_currentNodeName == nnNormal) { } else if (normals && currentName == nnNormal) {
aiVector3D normal; aiVector3D normal;
normal.x = ReadAttribute<float>(anX); normal.x = ReadAttribute<float>(vertexNode, anX);
normal.y = ReadAttribute<float>(anY); normal.y = ReadAttribute<float>(vertexNode, anY);
normal.z = ReadAttribute<float>(anZ); normal.z = ReadAttribute<float>(vertexNode, anZ);
dest->normals.push_back(normal); dest->normals.push_back(normal);
} else if (tangents && m_currentNodeName == nnTangent) { } else if (tangents && currentName == nnTangent) {
aiVector3D tangent; aiVector3D tangent;
tangent.x = ReadAttribute<float>(anX); tangent.x = ReadAttribute<float>(vertexNode, anX);
tangent.y = ReadAttribute<float>(anY); tangent.y = ReadAttribute<float>(vertexNode, anY);
tangent.z = ReadAttribute<float>(anZ); tangent.z = ReadAttribute<float>(vertexNode, anZ);
dest->tangents.push_back(tangent); dest->tangents.push_back(tangent);
} else if (uvs > 0 && m_currentNodeName == nnTexCoord) { } else if (uvs > 0 && currentName == nnTexCoord) {
for (auto &curUvs : dest->uvs) { for (auto &curUvs : dest->uvs) {
if (m_currentNodeName != nnTexCoord) {
throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex");
}
aiVector3D uv; aiVector3D uv;
uv.x = ReadAttribute<float>("u"); uv.x = ReadAttribute<float>(vertexNode, "u");
uv.y = (ReadAttribute<float>("v") * -1) + 1; // Flip UV from Ogre to Assimp form uv.y = (ReadAttribute<float>(vertexNode, "v") * -1) + 1; // Flip UV from Ogre to Assimp form
curUvs.push_back(uv); curUvs.push_back(uv);
NextNode();
}
// Continue main loop as above already read next node
continue;
} else {
/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
bool warn = true;
if (m_currentNodeName == nnBinormal) {
if (warnBinormal) {
warnBinormal = false;
} else {
warn = false;
}
} else if (m_currentNodeName == nnColorDiffuse) {
if (warnColorDiffuse) {
warnColorDiffuse = false;
} else {
warn = false;
}
} else if (m_currentNodeName == nnColorSpecular) {
if (warnColorSpecular) {
warnColorSpecular = false;
} else {
warn = false;
} }
} }
if (warn) {
ASSIMP_LOG_WARN_F("Vertex buffer attribute read not implemented for element: ", m_currentNodeName);
} }
} }
// Advance
NextNode();
}
// Sanity checks // Sanity checks
if (dest->positions.size() != dest->count) { if (dest->positions.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->positions.size(), " positions when should have read ", dest->count);
} }
if (normals && dest->normals.size() != dest->count) { if (normals && dest->normals.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->normals.size(), " normals when should have read ", dest->count);
} }
if (tangents && dest->tangents.size() != dest->count) { if (tangents && dest->tangents.size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count); throw DeadlyImportError("Read only ", dest->tangents.size(), " tangents when should have read ", dest->count);
} }
for (unsigned int i = 0; i < dest->uvs.size(); ++i) { for (unsigned int i = 0; i < dest->uvs.size(); ++i) {
if (dest->uvs[i].size() != dest->count) { if (dest->uvs[i].size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() throw DeadlyImportError("Read only ", dest->uvs[i].size(),
<< " uvs for uv index " << i << " when should have read " << dest->count); " uvs for uv index ", i, " when should have read ", dest->count);
} }
} }
} }
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
static const char *anMaterial = "material"; static const char *anMaterial = "material";
static const char *anUseSharedVertices = "usesharedvertices"; static const char *anUseSharedVertices = "usesharedvertices";
static const char *anCount = "count"; static const char *anCount = "count";
@ -457,11 +358,11 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
SubMeshXml *submesh = new SubMeshXml(); SubMeshXml *submesh = new SubMeshXml();
if (HasAttribute(anMaterial)) { if (XmlParser::hasAttribute(node, anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(anMaterial); submesh->materialRef = ReadAttribute<std::string>(node, anMaterial);
} }
if (HasAttribute(anUseSharedVertices)) { if (XmlParser::hasAttribute(node, anUseSharedVertices)) {
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices); submesh->usesSharedVertexData = ReadAttribute<bool>(node, anUseSharedVertices);
} }
ASSIMP_LOG_VERBOSE_DEBUG_F("Reading SubMesh ", mesh->subMeshes.size()); ASSIMP_LOG_VERBOSE_DEBUG_F("Reading SubMesh ", mesh->subMeshes.size());
@ -474,54 +375,42 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
bool quadWarned = false; bool quadWarned = false;
NextNode(); for (XmlNode &currentNode : node.children()) {
while (m_currentNodeName == nnFaces || const std::string &currentName = currentNode.name();
m_currentNodeName == nnGeometry || if (currentName == nnFaces) {
m_currentNodeName == nnTextures || submesh->indexData->faceCount = ReadAttribute<uint32_t>(currentNode, anCount);
m_currentNodeName == nnBoneAssignments) {
if (m_currentNodeName == nnFaces) {
submesh->indexData->faceCount = ReadAttribute<uint32_t>(anCount);
submesh->indexData->faces.reserve(submesh->indexData->faceCount); submesh->indexData->faces.reserve(submesh->indexData->faceCount);
for (XmlNode currentChildNode : currentNode.children()) {
NextNode(); const std::string &currentChildName = currentChildNode.name();
while (m_currentNodeName == nnFace) { if (currentChildName == nnFace) {
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
face.mIndices = new unsigned int[3]; face.mIndices = new unsigned int[3];
face.mIndices[0] = ReadAttribute<uint32_t>(anV1); face.mIndices[0] = ReadAttribute<uint32_t>(currentChildNode, anV1);
face.mIndices[1] = ReadAttribute<uint32_t>(anV2); face.mIndices[1] = ReadAttribute<uint32_t>(currentChildNode, anV2);
face.mIndices[2] = ReadAttribute<uint32_t>(anV3); face.mIndices[2] = ReadAttribute<uint32_t>(currentChildNode, anV3);
/// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it) /// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it)
if (!quadWarned && HasAttribute(anV4)) { if (!quadWarned && XmlParser::hasAttribute(currentChildNode, anV4)) {
ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!"); ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!");
quadWarned = true; quadWarned = true;
} }
submesh->indexData->faces.push_back(face); submesh->indexData->faces.push_back(face);
// Advance
NextNode();
} }
}
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) { if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount);
} else { } else {
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount); throw DeadlyImportError("Read only ", submesh->indexData->faces.size(), " faces when should have read ", submesh->indexData->faceCount);
} }
} else if (m_currentNodeName == nnGeometry) { } else if (currentName == nnGeometry) {
if (submesh->usesSharedVertexData) { if (submesh->usesSharedVertexData) {
throw DeadlyImportError("Found <geometry> in <submesh> when use shared geometry is true. Invalid mesh file."); throw DeadlyImportError("Found <geometry> in <submesh> when use shared geometry is true. Invalid mesh file.");
} }
submesh->vertexData = new VertexDataXml(); submesh->vertexData = new VertexDataXml();
ReadGeometry(submesh->vertexData); ReadGeometry(currentNode, submesh->vertexData);
} else if (m_currentNodeName == nnBoneAssignments) { } else if (currentName == nnBoneAssignments) {
ReadBoneAssignments(submesh->vertexData); ReadBoneAssignments(currentNode, submesh->vertexData);
}
// Assimp incompatible/ignored nodes
else {
SkipCurrentNode();
} }
} }
@ -529,7 +418,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
mesh->subMeshes.push_back(submesh); mesh->subMeshes.push_back(submesh);
} }
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) { void OgreXmlSerializer::ReadBoneAssignments(XmlNode &node, VertexDataXml *dest) {
if (!dest) { if (!dest) {
throw DeadlyImportError("Cannot read bone assignments, vertex data is null."); throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
} }
@ -539,18 +428,17 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
static const char *anWeight = "weight"; static const char *anWeight = "weight";
std::set<uint32_t> influencedVertices; std::set<uint32_t> influencedVertices;
for (XmlNode &currentNode : node.children()) {
NextNode(); const std::string &currentName = currentNode.name();
while (m_currentNodeName == nnVertexBoneAssignment) { if (currentName == nnVertexBoneAssignment) {
VertexBoneAssignment ba; VertexBoneAssignment ba;
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex); ba.vertexIndex = ReadAttribute<uint32_t>(currentNode, anVertexIndex);
ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex); ba.boneIndex = ReadAttribute<uint16_t>(currentNode, anBoneIndex);
ba.weight = ReadAttribute<float>(anWeight); ba.weight = ReadAttribute<float>(currentNode, anWeight);
dest->boneAssignments.push_back(ba); dest->boneAssignments.push_back(ba);
influencedVertices.insert(ba.vertexIndex); influencedVertices.insert(ba.vertexIndex);
}
NextNode();
} }
/** Normalize bone weights. /** Normalize bone weights.
@ -593,152 +481,153 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
mesh->skeletonRef = mesh->skeletonRef + ".xml"; mesh->skeletonRef = mesh->skeletonRef + ".xml";
} }
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!reader.get()) if (!xmlParser.get())
return false; return false;
Skeleton *skeleton = new Skeleton(); Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get()); OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton); XmlNode root = xmlParser->getRootNode();
serializer.ReadSkeleton(root, skeleton);
mesh->skeleton = skeleton; mesh->skeleton = skeleton;
return true; return true;
} }
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) { bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
if (!mesh || mesh->skeletonRef.empty()) if (!mesh || mesh->skeletonRef.empty()) {
return false; return false;
}
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!reader.get()) if (!xmlParser.get()) {
return false; return false;
}
Skeleton *skeleton = new Skeleton(); Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get()); OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton); XmlNode root = xmlParser->getRootNode();
serializer.ReadSkeleton(root, skeleton);
mesh->skeleton = skeleton; mesh->skeleton = skeleton;
return true; return true;
} }
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) { XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename) {
if (!EndsWith(filename, ".skeleton.xml", false)) { if (!EndsWith(filename, ".skeleton.xml", false)) {
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file."); ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
return XmlReaderPtr(); return XmlParserPtr();
} }
if (!pIOHandler->Exists(filename)) { if (!pIOHandler->Exists(filename)) {
ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh."); ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
return XmlReaderPtr(); return XmlParserPtr();
} }
std::unique_ptr<IOStream> file(pIOHandler->Open(filename)); std::unique_ptr<IOStream> file(pIOHandler->Open(filename));
if (!file.get()) { if (!file.get()) {
throw DeadlyImportError("Failed to open skeleton file " + filename); throw DeadlyImportError("Failed to open skeleton file ", filename);
} }
std::unique_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get())); XmlParserPtr xmlParser = XmlParserPtr(new XmlParser);
XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); if (!xmlParser->parse(file.get())) {
if (!reader.get()) {
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
} }
return reader; return xmlParser;
} }
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
if (NextNode() != nnSkeleton) { if (node.name() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>"); throw DeadlyImportError("Root node is <" + std::string(node.name()) + "> expecting <skeleton>");
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
// Optional blend mode from root node // Optional blend mode from root node
if (HasAttribute("blendmode")) { if (XmlParser::hasAttribute(node, "blendmode")) {
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); skeleton->blendMode = (ToLower(ReadAttribute<std::string>(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
} }
NextNode(); for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
// Root level nodes if (currentName == nnBones) {
while (m_currentNodeName == nnBones || ReadBones(currentNode, skeleton);
m_currentNodeName == nnBoneHierarchy || } else if (currentName == nnBoneHierarchy) {
m_currentNodeName == nnAnimations || ReadBoneHierarchy(currentNode, skeleton);
m_currentNodeName == nnAnimationLinks) { } else if (currentName == nnAnimations) {
if (m_currentNodeName == nnBones) ReadAnimations(currentNode, skeleton);
ReadBones(skeleton); }
else if (m_currentNodeName == nnBoneHierarchy)
ReadBoneHierarchy(skeleton);
else if (m_currentNodeName == nnAnimations)
ReadAnimations(skeleton);
else
SkipCurrentNode();
} }
} }
void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) { void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) { if (skeleton->bones.empty()) {
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones"); throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
} }
ASSIMP_LOG_VERBOSE_DEBUG(" - Animations"); ASSIMP_LOG_VERBOSE_DEBUG(" - Animations");
NextNode(); for (XmlNode &currentNode : node.children()) {
while (m_currentNodeName == nnAnimation) { const std::string currentName = currentNode.name();
if (currentName == nnAnimation) {
Animation *anim = new Animation(skeleton); Animation *anim = new Animation(skeleton);
anim->name = ReadAttribute<std::string>("name"); anim->name = ReadAttribute<std::string>(currentNode, "name");
anim->length = ReadAttribute<float>("length"); anim->length = ReadAttribute<float>(currentNode, "length");
for (XmlNode &currentChildNode : currentNode.children()) {
if (NextNode() != nnTracks) { const std::string currentChildName = currentNode.name();
throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << anim->name); if (currentChildName == nnTracks) {
} ReadAnimationTracks(currentChildNode, anim);
ReadAnimationTracks(anim);
skeleton->animations.push_back(anim); skeleton->animations.push_back(anim);
} else {
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)"); throw DeadlyImportError("No <tracks> found in <animation> ", anim->name);
}
}
}
} }
} }
void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) { void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
NextNode(); for (XmlNode &currentNode : node.children()) {
while (m_currentNodeName == nnTrack) { const std::string currentName = currentNode.name();
if (currentName == nnTrack) {
VertexAnimationTrack track; VertexAnimationTrack track;
track.type = VertexAnimationTrack::VAT_TRANSFORM; track.type = VertexAnimationTrack::VAT_TRANSFORM;
track.boneName = ReadAttribute<std::string>("bone"); track.boneName = ReadAttribute<std::string>(currentNode, "bone");
for (XmlNode &currentChildNode : currentNode.children()) {
if (NextNode() != nnKeyFrames) { const std::string currentChildName = currentNode.name();
throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << dest->name); if (currentChildName == nnKeyFrames) {
} ReadAnimationKeyFrames(currentChildNode, dest, &track);
ReadAnimationKeyFrames(dest, &track);
dest->tracks.push_back(track); dest->tracks.push_back(track);
} else {
throw DeadlyImportError("No <keyframes> found in <track> ", dest->name);
}
}
}
} }
} }
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) { void OgreXmlSerializer::ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest) {
const aiVector3D zeroVec(0.f, 0.f, 0.f); const aiVector3D zeroVec(0.f, 0.f, 0.f);
for (XmlNode &currentNode : node.children()) {
NextNode();
while (m_currentNodeName == nnKeyFrame) {
TransformKeyFrame keyframe; TransformKeyFrame keyframe;
keyframe.timePos = ReadAttribute<float>("time"); const std::string currentName = currentNode.name();
if (currentName == nnKeyFrame) {
NextNode(); keyframe.timePos = ReadAttribute<float>(currentNode, "time");
while (m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale) { for (XmlNode &currentChildNode : currentNode.children()) {
if (m_currentNodeName == nnTranslate) { const std::string currentChildName = currentNode.name();
keyframe.position.x = ReadAttribute<float>(anX); if (currentChildName == nnTranslate) {
keyframe.position.y = ReadAttribute<float>(anY); keyframe.position.x = ReadAttribute<float>(currentChildNode, anX);
keyframe.position.z = ReadAttribute<float>(anZ); keyframe.position.y = ReadAttribute<float>(currentChildNode, anY);
} else if (m_currentNodeName == nnRotate) { keyframe.position.z = ReadAttribute<float>(currentChildNode, anZ);
float angle = ReadAttribute<float>("angle"); } else if (currentChildName == nnRotate) {
float angle = ReadAttribute<float>(currentChildNode, "angle");
if (NextNode() != nnAxis) { for (XmlNode &currentChildChildNode : currentNode.children()) {
throw DeadlyImportError("No axis specified for keyframe rotation in animation " + anim->name); const std::string currentChildChildName = currentNode.name();
} if (currentChildChildName == nnAxis) {
aiVector3D axis; aiVector3D axis;
axis.x = ReadAttribute<float>(anX); axis.x = ReadAttribute<float>(currentChildChildNode, anX);
axis.y = ReadAttribute<float>(anY); axis.y = ReadAttribute<float>(currentChildChildNode, anY);
axis.z = ReadAttribute<float>(anZ); axis.z = ReadAttribute<float>(currentChildChildNode, anZ);
if (axis.Equal(zeroVec)) { if (axis.Equal(zeroVec)) {
axis.x = 1.0f; axis.x = 1.0f;
if (angle != 0) { if (angle != 0) {
@ -746,35 +635,39 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
} }
} }
keyframe.rotation = aiQuaternion(axis, angle); keyframe.rotation = aiQuaternion(axis, angle);
} else if (m_currentNodeName == nnScale) {
keyframe.scale.x = ReadAttribute<float>(anX);
keyframe.scale.y = ReadAttribute<float>(anY);
keyframe.scale.z = ReadAttribute<float>(anZ);
} }
NextNode();
} }
} else if (currentChildName == nnScale) {
keyframe.scale.x = ReadAttribute<float>(currentChildNode, anX);
keyframe.scale.y = ReadAttribute<float>(currentChildNode, anY);
keyframe.scale.z = ReadAttribute<float>(currentChildNode, anZ);
}
}
}
dest->transformKeyFrames.push_back(keyframe); dest->transformKeyFrames.push_back(keyframe);
} }
} }
void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) { void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) { if (skeleton->bones.empty()) {
throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones"); throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
} }
while (NextNode() == nnBoneParent) { for (XmlNode &currentNode : node.children()) {
const std::string name = ReadAttribute<std::string>("bone"); const std::string currentName = currentNode.name();
const std::string parentName = ReadAttribute<std::string>("parent"); if (currentName == nnBoneParent) {
const std::string name = ReadAttribute<std::string>(currentNode, "bone");
const std::string parentName = ReadAttribute<std::string>(currentNode, "parent");
Bone *bone = skeleton->BoneByName(name); Bone *bone = skeleton->BoneByName(name);
Bone *parent = skeleton->BoneByName(parentName); Bone *parent = skeleton->BoneByName(parentName);
if (bone && parent) if (bone && parent) {
parent->AddChild(bone); parent->AddChild(bone);
else } else {
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); throw DeadlyImportError("Failed to find bones for parenting: Child ", name, " for parent ", parentName);
}
}
} }
// Calculate bone matrices for root bones. Recursively calculates their children. // Calculate bone matrices for root bones. Recursively calculates their children.
@ -792,56 +685,53 @@ static bool BoneCompare(Bone *a, Bone *b) {
return (a->id < b->id); return (a->id < b->id);
} }
void OgreXmlSerializer::ReadBones(Skeleton *skeleton) { void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG(" - Bones"); ASSIMP_LOG_VERBOSE_DEBUG(" - Bones");
NextNode(); for (XmlNode &currentNode : node.children()) {
while (m_currentNodeName == nnBone) { const std::string currentName = currentNode.name();
if (currentName == nnBone) {
Bone *bone = new Bone(); Bone *bone = new Bone();
bone->id = ReadAttribute<uint16_t>("id"); bone->id = ReadAttribute<uint16_t>(currentNode, "id");
bone->name = ReadAttribute<std::string>("name"); bone->name = ReadAttribute<std::string>(currentNode, "name");
for (XmlNode &currentChildNode : currentNode.children()) {
NextNode(); const std::string currentChildName = currentNode.name();
while (m_currentNodeName == nnPosition || if (currentChildName == nnRotation) {
m_currentNodeName == nnRotation || bone->position.x = ReadAttribute<float>(currentChildNode, anX);
m_currentNodeName == nnScale) { bone->position.y = ReadAttribute<float>(currentChildNode, anY);
if (m_currentNodeName == nnPosition) { bone->position.z = ReadAttribute<float>(currentChildNode, anZ);
bone->position.x = ReadAttribute<float>(anX); } else if (currentChildName == nnScale) {
bone->position.y = ReadAttribute<float>(anY); float angle = ReadAttribute<float>(currentChildNode, "angle");
bone->position.z = ReadAttribute<float>(anZ); for (XmlNode currentChildChildNode : currentChildNode.children()) {
} else if (m_currentNodeName == nnRotation) { const std::string &currentChildChildName = currentChildChildNode.name();
float angle = ReadAttribute<float>("angle"); if (currentChildChildName == nnAxis) {
if (NextNode() != nnAxis) {
throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id);
}
aiVector3D axis; aiVector3D axis;
axis.x = ReadAttribute<float>(anX); axis.x = ReadAttribute<float>(currentChildChildNode, anX);
axis.y = ReadAttribute<float>(anY); axis.y = ReadAttribute<float>(currentChildChildNode, anY);
axis.z = ReadAttribute<float>(anZ); axis.z = ReadAttribute<float>(currentChildChildNode, anZ);
bone->rotation = aiQuaternion(axis, angle); bone->rotation = aiQuaternion(axis, angle);
} else if (m_currentNodeName == nnScale) { } else {
/// @todo Implement taking scale into account in matrix/pose calculations! throw DeadlyImportError("No axis specified for bone rotation in bone ", bone->id);
if (HasAttribute("factor")) { }
float factor = ReadAttribute<float>("factor"); }
} else if (currentChildName == nnScale) {
if (XmlParser::hasAttribute(currentChildNode, "factor")) {
float factor = ReadAttribute<float>(currentChildNode, "factor");
bone->scale.Set(factor, factor, factor); bone->scale.Set(factor, factor, factor);
} else { } else {
if (HasAttribute(anX)) if (XmlParser::hasAttribute(currentChildNode, anX))
bone->scale.x = ReadAttribute<float>(anX); bone->scale.x = ReadAttribute<float>(currentChildNode, anX);
if (HasAttribute(anY)) if (XmlParser::hasAttribute(currentChildNode, anY))
bone->scale.y = ReadAttribute<float>(anY); bone->scale.y = ReadAttribute<float>(currentChildNode, anY);
if (HasAttribute(anZ)) if (XmlParser::hasAttribute(currentChildNode, anZ))
bone->scale.z = ReadAttribute<float>(anZ); bone->scale.z = ReadAttribute<float>(currentChildNode, anZ);
} }
} }
NextNode();
} }
skeleton->bones.push_back(bone); skeleton->bones.push_back(bone);
} }
}
// Order bones by Id // Order bones by Id
std::sort(skeleton->bones.begin(), skeleton->bones.end(), BoneCompare); std::sort(skeleton->bones.begin(), skeleton->bones.end(), BoneCompare);
@ -854,7 +744,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name);
if (b->id != static_cast<uint16_t>(i)) { if (b->id != static_cast<uint16_t>(i)) {
throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i); throw DeadlyImportError("Bone ids are not in sequence starting from 0. Missing index ", i);
} }
} }
} }

View File

@ -46,73 +46,57 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
#include "OgreStructs.h" #include "OgreStructs.h"
#include <assimp/irrXMLWrapper.h> #include <assimp/XmlParser.h>
namespace Assimp namespace Assimp {
{
namespace Ogre
{
typedef irr::io::IrrXMLReader XmlReader; namespace Ogre {
typedef std::shared_ptr<XmlReader> XmlReaderPtr;
class OgreXmlSerializer using XmlParserPtr = std::shared_ptr<::Assimp::XmlParser> ;
{
class OgreXmlSerializer {
public: public:
/// Imports mesh and returns the result. /// Imports mesh and returns the result.
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ /// @note Fatal unrecoverable errors will throw a DeadlyImportError.
static MeshXml *ImportMesh(XmlReader *reader); static MeshXml *ImportMesh(XmlParser *parser);
/// Imports skeleton to @c mesh. /// Imports skeleton to @c mesh.
/** If mesh does not have a skeleton reference or the skeleton file /// If mesh does not have a skeleton reference or the skeleton file
cannot be found it is not a fatal DeadlyImportError. /// cannot be found it is not a fatal DeadlyImportError.
@return If skeleton import was successful. */ /// @return If skeleton import was successful.
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); static bool ImportSkeleton(IOSystem *pIOHandler, MeshXml *mesh);
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); static bool ImportSkeleton(IOSystem *pIOHandler, Mesh *mesh);
private: private:
explicit OgreXmlSerializer(XmlReader *reader) : explicit OgreXmlSerializer(XmlParser *xmlParser);
m_reader(reader)
{
}
static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); static XmlParserPtr OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename);
// Mesh // Mesh
void ReadMesh(MeshXml *mesh); void ReadMesh(MeshXml *mesh);
void ReadSubMesh(MeshXml *mesh); void ReadSubMesh(XmlNode &node, MeshXml *mesh);
void ReadGeometry(XmlNode &node, VertexDataXml *dest);
void ReadGeometry(VertexDataXml *dest); void ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest);
void ReadGeometryVertexBuffer(VertexDataXml *dest); void ReadBoneAssignments(XmlNode &node, VertexDataXml *dest);
void ReadBoneAssignments(VertexDataXml *dest);
// Skeleton // Skeleton
void ReadSkeleton(Skeleton *skeleton); void ReadSkeleton(XmlNode &node, Skeleton *skeleton);
void ReadBones(XmlNode &node, Skeleton *skeleton);
void ReadBones(Skeleton *skeleton); void ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton);
void ReadBoneHierarchy(Skeleton *skeleton); void ReadAnimations(XmlNode &node, Skeleton *skeleton);
void ReadAnimationTracks(XmlNode &node, Animation *dest);
void ReadAnimations(Skeleton *skeleton); void ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest);
void ReadAnimationTracks(Animation *dest);
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest);
template <typename T> template <typename T>
T ReadAttribute(const char *name) const; T ReadAttribute(XmlNode &xmlNode, const char *name) const;
bool HasAttribute(const char *name) const;
std::string &NextNode(); private:
std::string &SkipCurrentNode(); XmlParser *mParser;
bool CurrentNodeNameEquals(const std::string &name) const;
std::string CurrentNodeName(bool forceRead = false);
XmlReader *m_reader;
std::string m_currentNodeName;
}; };
} // Ogre
} // Assimp } // namespace Ogre
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
#endif // AI_OGREXMLSERIALIZER_H_INC #endif // AI_OGREXMLSERIALIZER_H_INC

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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