Merge branch 'master' of https://github.com/assimp/assimp into tdb/pbrt3_exporter

pull/3580/head
Matt Pharr 2021-01-11 19:57:10 -08:00
commit 1042845414
782 changed files with 76040 additions and 81857 deletions

View File

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -7,40 +7,117 @@ on:
branches: [ master ]
jobs:
linux:
runs-on: ubuntu-latest
job:
name: ${{ matrix.name }}-build-and-test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include:
- name: windows-latest-cl.exe
os: windows-latest
cxx: cl.exe
cc: cl.exe
- name: ubuntu-latest-clang++
os: ubuntu-latest
cxx: clang++
cc: clang
- name: macos-latest-clang++
os: macos-latest
cxx: clang++
cc: clang
- name: ubuntu-latest-g++
os: ubuntu-latest
cxx: g++
cc: gcc
- name: ubuntu-gcc-hunter
os: ubuntu-latest
toolchain: ninja-gcc-cxx17-fpic
- name: macos-clang-hunter
os: macos-latest
toolchain: ninja-clang-cxx17-fpic
- name: windows-msvc-hunter
os: windows-latest
toolchain: ninja-vs-win64-cxx17
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build .
- name: test
run: cd bin && ./unit
- uses: actions/checkout@v2
mac:
runs-on: macos-latest
- uses: lukka/get-cmake@latest
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build .
- name: test
run: cd bin && ./unit
- uses: ilammy/msvc-dev-cmd@v1
windows:
runs-on: windows-latest
- name: Set Compiler Environment
if: "!endsWith(matrix.name, 'hunter')"
uses: lukka/set-shell-env@v1
with:
CXX: ${{ matrix.cxx }}
CC: ${{ matrix.cc }}
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build . --config Release
- name: test
- 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: |
cd bin\Release
.\unit
curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
- name: Set Windows specific CMake arguments
if: contains(matrix.name, 'windows')
id: windows_extra_cmake_args
run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1"
- name: Set Hunter specific CMake arguments
if: contains(matrix.name, 'hunter')
id: hunter_extra_cmake_args
run: echo "::set-output name=args::-DBUILD_SHARED_LIBS=OFF -DASSIMP_HUNTER_ENABLED=ON -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/polly/${{ matrix.toolchain }}.cmake"
- name: configure and build
uses: lukka/run-cmake@v3
env:
DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: Exclude certain tests in Hunter specific builds
if: contains(matrix.name, 'hunter')
id: hunter_extra_test_args
run: echo "::set-output name=args::--gtest_filter=-utOpenGEXImportExport.Importissue1340_EmptyCameraObject:utColladaZaeImportExport.importBlenFromFileTest"
- name: test
run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
shell: bash
- uses: actions/upload-artifact@v2
if: matrix.name == 'windows-msvc'
with:
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
path: build/bin

56
.github/workflows/sanitizer.yml vendored 100644
View File

@ -0,0 +1,56 @@
name: C/C++ Sanitizer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
job1:
name: adress-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
CXX: clang++
CC: clang
- name: configure and build
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_ASAN=ON'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: test
run: cd build/bin && ./unit
shell: bash
job2:
name: undefined-behavior-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
CXX: clang++
CC: clang
- name: configure and build
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_UBSAN=ON'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: test
run: cd build/bin && ./unit
shell: bash

6
.gitignore vendored
View File

@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/
tools/assimp_view/assimp_viewer.vcxproj.user
*.pyc
### Rust ###
# Generated by Cargo; will have compiled files and executables
port/assimp_rs/target/
# Backup files generated by rustfmt
port/assimp_rs/**/*.rs.bk
# Unix editor backups
*~
test/gtest/src/gtest-stamp/gtest-gitinfo.txt

View File

@ -1,3 +0,0 @@
set(ASSIMP_INCLUDE_DIRS
"@PROJECT_SOURCE_DIR@"
"@PROJECT_BINARY_DIR@")

View File

@ -1,11 +0,0 @@
set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View File

@ -34,7 +34,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#----------------------------------------------------------------------
SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW)
SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)
CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
@ -44,8 +46,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED)
include("cmake/HunterGate.cmake")
HunterGate(
URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
URL "https://github.com/cpp-pm/hunter/archive/v0.23.269.tar.gz"
SHA1 "64024b7b95b4c86d50ae05b926814448c93a70a0"
)
add_definitions(-DASSIMP_USE_HUNTER)
@ -108,10 +110,6 @@ OPTION ( ASSIMP_ERROR_MAX
"Enable all warnings."
OFF
)
OPTION ( ASSIMP_WERROR
"Treat warnings as errors."
OFF
)
OPTION ( ASSIMP_ASAN
"Enable AddressSanitizer."
OFF
@ -120,10 +118,6 @@ OPTION ( ASSIMP_UBSAN
"Enable Undefined Behavior sanitizer."
OFF
)
OPTION ( ASSIMP_SYSTEM_IRRXML
"Use system installed Irrlicht/IrrXML library."
OFF
)
OPTION ( ASSIMP_BUILD_DOCS
"Build documentation using Doxygen."
OFF
@ -138,6 +132,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF
)
IF ( WIN32 )
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)"
OFF )
ENDIF()
IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
IF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
@ -243,30 +243,40 @@ IF( UNIX )
INCLUDE(GNUInstallDirs)
ENDIF()
# Grouped compiler settings
# Grouped compiler settings ########################################
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
# hide all not-exported symbols
SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSE()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
ENDIF()
ELSEIF(MSVC)
# enable multi-core compilation with MSVC
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351)
ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
ELSEIF( CMAKE_COMPILER_IS_MINGW )
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
@ -311,16 +321,6 @@ IF (ASSIMP_ERROR_MAX)
ENDIF()
ENDIF()
IF (ASSIMP_WERROR)
MESSAGE(STATUS "Treating warnings as errors")
IF (MSVC)
ADD_COMPILE_OPTIONS(/WX)
ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
ENDIF()
ENDIF()
IF (ASSIMP_ASAN)
MESSAGE(STATUS "AddressSanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@ -329,34 +329,27 @@ ENDIF()
IF (ASSIMP_UBSAN)
MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
ENDIF()
INCLUDE (FindPkgMacros)
INCLUDE (PrecompiledHeader)
# If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR),
# write the library/executable files to the respective directories in the
# source tree. During an out-of-source build, however, do not litter this
# directory, since that is probably what the user wanted to avoid.
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
ELSE()
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
ENDIF ()
# Set Assimp project output directory variables.
SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
# Cache these to allow the user to override them manually.
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
"Path the built library files are installed to." )
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
"Path the header files are installed to." )
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
"Path the tool executables are installed to." )
# Macro used to set the output directories of a target to the
# respective Assimp output directories.
MACRO(TARGET_USE_COMMON_OUTPUT_DIRECTORY target)
set_target_properties(${target} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${ASSIMP_RUNTIME_OUTPUT_DIRECTORY}
LIBRARY_OUTPUT_DIRECTORY ${ASSIMP_LIBRARY_OUTPUT_DIRECTORY}
ARCHIVE_OUTPUT_DIRECTORY ${ASSIMP_ARCHIVE_OUTPUT_DIRECTORY}
)
ENDMACRO()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
@ -367,23 +360,60 @@ ELSE()
ENDIF()
# Only generate this target if no higher-level project already has
IF (NOT TARGET uninstall)
IF (NOT TARGET uninstall AND ASSIMP_INSTALL)
# add make uninstall capability
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF()
IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(INCLUDE_INSTALL_DIR "include")
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs)
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
ELSE()
# Cache these to allow the user to override them on non-Unix platforms
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
"Path the built library files are installed to." )
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
"Path the header files are installed to." )
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
"Path the tool executables are installed to." )
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
ENDIF()
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
# Configuration
IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-hunter-config.cmake.in")
set(NAMESPACE "${PROJECT_NAME}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(NAMESPACE "${PROJECT_NAME}::")
ELSE()
set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-plain-config.cmake.in")
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE)
set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets")
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}Config.cmake")
ENDIF()
set(INCLUDE_INSTALL_DIR "include")
# Include module with fuction 'write_basic_package_version_file'
include(CMakePackageConfigHelpers)
@ -391,11 +421,8 @@ IF(ASSIMP_HUNTER_ENABLED)
# Note: PROJECT_VERSION is used as a VERSION
write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
# Use variables:
# * TARGETS_EXPORT_NAME
# * PROJECT_NAME
configure_package_config_file(
"cmake/assimp-hunter-config.cmake.in"
${CMAKE_CONFIG_TEMPLATE_FILE}
"${PROJECT_CONFIG}"
INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
)
@ -403,52 +430,20 @@ IF(ASSIMP_HUNTER_ENABLED)
install(
FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
DESTINATION "${CONFIG_INSTALL_DIR}"
COMPONENT ${LIBASSIMP-DEV_COMPONENT}
)
install(
EXPORT "${TARGETS_EXPORT_NAME}"
NAMESPACE "${NAMESPACE}"
DESTINATION "${CONFIG_INSTALL_DIR}"
COMPONENT ${LIBASSIMP-DEV_COMPONENT}
)
ELSE()
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
IF (is_multi_config)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake")
ELSE()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
ENDIF()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
#we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
INSTALL(FILES
"${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
${PACKAGE_TARGETS_FILE}
DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
ENDIF()
IF( ASSIMP_BUILD_DOCS )
ADD_SUBDIRECTORY(doc)
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 zlib
IF(ASSIMP_HUNTER_ENABLED)
@ -575,10 +570,6 @@ ELSE ()
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
ENDIF ()
IF(NOT ASSIMP_HUNTER_ENABLED)
ADD_SUBDIRECTORY(contrib)
ENDIF()
ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# The viewer for windows only
@ -673,7 +664,8 @@ if(WIN32)
ENDIF()
IF(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
SET(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
SET(ASSIMP_MSVC_VERSION ${MCVS_PREFIX})
ELSE()
IF(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120")

141
Readme.md
View File

@ -2,9 +2,8 @@ Open Asset Import Library (assimp)
==================================
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
### Current project status ###
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
[![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
<a href="https://scan.coverity.com/projects/5607">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5607/badge.svg"/>
@ -17,114 +16,22 @@ A library to import and export various 3d-model-formats including scene-post-pro
<br>
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
### Latest Doc's ###
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
### Get involved ###
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
Monthly donations via Patreon:
<br>[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp)
<br>
One-off donations via PayPal:
<br>[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
<br>
Please check our Wiki as well: https://github.com/assimp/assimp/wiki
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
#### Supported file formats ####
__Importers__:
- 3D
- [3DS](https://en.wikipedia.org/wiki/.3ds)
- [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format)
- AC
- [AC3D](https://en.wikipedia.org/wiki/AC3D)
- ACC
- AMJ
- ASE
- ASK
- B3D
- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
- CMS
- COB
- [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA)
- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF)
- ENFF
- [FBX](https://en.wikipedia.org/wiki/FBX)
- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0):
At the moment for glTF2.0 the following extensions are supported:
+ KHR_lights_punctual ( 5.0 )
+ KHR_materials_pbrSpecularGlossiness ( 5.0 )
+ KHR_materials_unlit ( 5.0 )
+ KHR_texture_transform ( 5.1 under test )
- HMB
- IFC-STEP
- IRR / IRRMESH
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
- LWS
- LXO
- [M3D](https://bztsrc.gitlab.io/model3d)
- MD2
- MD3
- MD5
- MDC
- MDL
- MESH / MESH.XML
- MOT
- MS3D
- NDO
- NFF
- [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
- [OFF](https://en.wikipedia.org/wiki/OFF_(file_format))
- [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange)
- [PLY](https://en.wikipedia.org/wiki/PLY_(file_format))
- PMX
- PRJ
- Q3O
- Q3S
- RAW
- SCN
- SIB
- SMD
- [STP](https://en.wikipedia.org/wiki/ISO_10303-21)
- [STL](https://en.wikipedia.org/wiki/STL_(file_format))
- TER
- UC
- VTA
- X
- [X3D](https://en.wikipedia.org/wiki/X3D)
- XGL
- ZGL
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported
__Exporters__:
- DAE (Collada)
- STL
- OBJ
- PLY
- X
- 3DS
- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
- ASSBIN
- STEP
- glTF 1.0 (partial)
- glTF 2.0 (partial)
- 3MF ( experimental )
- FBX ( experimental )
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md)
### Building ###
Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do.
@ -166,7 +73,7 @@ The source code is organized in the following way:
For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
(CHMs for Windows are included in some release packages and should be located right here in the root folder).
If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
If the docs don't solve your problem, ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
@ -179,6 +86,38 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
a pull request with your changes against the main repository's `master` branch.
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/assimp/assimp/graphs/contributors"><img src="https://opencollective.com/assimp/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/assimp/contribute)]
#### Individuals
<a href="https://opencollective.com/assimp"><img src="https://opencollective.com/assimp/individuals.svg?width=890"></a>
Monthly donations via Patreon:
<br>[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp)
<br>
One-off donations via PayPal:
<br>[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
<br>
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/assimp/contribute)]
<a href="https://opencollective.com/assimp/organization/0/website"><img src="https://opencollective.com/assimp/organization/0/avatar.svg"></a>
### License ###
Our license is based on the modified, __3-clause BSD__-License.

View File

@ -1,48 +0,0 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
# Copyright (c) 2006-2020, assimp team
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the
# following conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the assimp team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the assimp team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#----------------------------------------------------------------------
set( PACKAGE_VERSION "@ASSIMP_VERSION@" )
if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@")
set(PACKAGE_VERSION_EXACT 1)
endif()
if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_VERSION@" )
set(PACKAGE_VERSION_COMPATIBLE 1)
elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" )
# for now backward compatible if minor version is less
if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ )
set(PACKAGE_VERSION_COMPATIBLE 1)
endif()
endif()
set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@")

View File

@ -1 +0,0 @@
include(${CMAKE_CURRENT_LIST_DIR}/assimpTargets.cmake)

View File

@ -1,7 +1,5 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@/
libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @CMAKE_PROJECT_NAME@
Description: Import various well-known 3D model formats in an uniform manner.

View File

@ -1,123 +0,0 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Debug".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
if(MSVC)
if(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
else()
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC_VERSION LESS 1910)
set(MSVC_PREFIX "vc140")
elseif( MSVC_VERSION LESS 1920)
set(MSVC_PREFIX "vc141")
elseif( MSVC_VERSION LESS 1930)
set(MSVC_PREFIX "vc142")
else()
set(MSVC_PREFIX "vc150")
endif()
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
else()
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
endif()
else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
else()
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
endif()
endif()
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
set( ASSIMP_LINK_FLAGS "" )
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
if(ASSIMP_BUILD_SHARED_LIBS)
set( ASSIMP_LIBRARIES ${sharedLibraryName})
else()
set( ASSIMP_LIBRARIES ${staticLibraryName})
endif()
# for compatibility with pkg-config
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
MARK_AS_ADVANCED(
ASSIMP_ROOT_DIR
ASSIMP_CXX_FLAGS
ASSIMP_LINK_FLAGS
ASSIMP_INCLUDE_DIRS
ASSIMP_LIBRARIES
ASSIMP_CFLAGS_OTHER
ASSIMP_LDFLAGS_OTHER
ASSIMP_LIBRARY_SUFFIX
ASSIMP_BUILD_SHARED_LIBS
)

View File

@ -1,122 +0,0 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
if(MSVC)
if(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
else()
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC_VERSION LESS 1910)
set(MSVC_PREFIX "vc140")
elseif( MSVC_VERSION LESS 1920)
set(MSVC_PREFIX "vc141")
elseif( MSVC_VERSION LESS 1930)
set(MSVC_PREFIX "vc142")
else()
set(MSVC_PREFIX "vc150")
endif()
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
else()
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
endif()
else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
else()
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
endif()
endif()
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
set( ASSIMP_LINK_FLAGS "" )
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
if(ASSIMP_BUILD_SHARED_LIBS)
set( ASSIMP_LIBRARIES ${sharedLibraryName})
else()
set( ASSIMP_LIBRARIES ${staticLibraryName})
endif()
# for compatibility with pkg-config
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
MARK_AS_ADVANCED(
ASSIMP_ROOT_DIR
ASSIMP_CXX_FLAGS
ASSIMP_LINK_FLAGS
ASSIMP_INCLUDE_DIRS
ASSIMP_LIBRARIES
ASSIMP_CFLAGS_OTHER
ASSIMP_LDFLAGS_OTHER
ASSIMP_LIBRARY_SUFFIX
ASSIMP_BUILD_SHARED_LIBS
)

View File

@ -1,104 +0,0 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function
cmake_policy(SET CMP0012 NEW)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget assimp::assimp)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target assimp::assimp
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
set_target_properties(assimp::assimp PROPERTIES
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
INTERFACE_assimp_MAJOR_VERSION "1"
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include"
#INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
endif()
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/assimpTargets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
if(NOT EXISTS "${file}" )
message(FATAL_ERROR "The imported target \"${target}\" references the file
\"${file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

View File

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

View File

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

View File

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

View File

@ -0,0 +1,9 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
set(ASSIMP_ROOT_DIR ${PACKAGE_PREFIX_DIR})
set(ASSIMP_LIBRARIES assimp::assimp)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
get_property(ASSIMP_INCLUDE_DIRS TARGET assimp::assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
set(ASSIMP_LIBRARY_DIRS "")

View File

@ -1,483 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#include "D3MFImporter.h"
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <assimp/StringComparison.h>
#include <assimp/StringUtils.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <memory>
#include "D3MFOpcPackage.h"
#include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h"
#include <assimp/fast_atof.h>
#include <iomanip>
namespace Assimp {
namespace D3MF {
class XmlSerializer {
public:
using MatArray = std::vector<aiMaterial*>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
XmlSerializer(XmlReader* xmlReader)
: mMeshes()
, mMatArray()
, mActiveMatGroup( 99999999 )
, mMatId2MatArray()
, xmlReader(xmlReader){
// empty
}
~XmlSerializer() {
// empty
}
void ImportXml(aiScene* scene) {
if ( nullptr == scene ) {
return;
}
scene->mRootNode = new aiNode();
std::vector<aiNode*> children;
std::string nodeName;
while(ReadToEndElement(D3MF::XmlTag::model)) {
nodeName = xmlReader->getNodeName();
if( nodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(scene));
} else if( nodeName == D3MF::XmlTag::build) {
//
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
ReadBaseMaterials();
} else if ( nodeName == D3MF::XmlTag::meta ) {
ReadMetadata();
}
}
if ( scene->mRootNode->mName.length == 0 ) {
scene->mRootNode->mName.Set( "3MF" );
}
// import the metadata
if ( !mMetaData.empty() ) {
const size_t numMeta( mMetaData.size() );
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>( numMeta ) );
for ( size_t i = 0; i < numMeta; ++i ) {
aiString val( mMetaData[ i ].value );
scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
// import the materials
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
if ( 0 != scene->mNumMaterials ) {
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
}
// create the scenegraph
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
}
private:
aiNode* ReadObject(aiScene* scene) {
std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds;
const char *attrib( nullptr );
std::string name, type;
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
if ( nullptr != attrib ) {
name = attrib;
}
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
if ( nullptr != attrib ) {
type = attrib;
}
node->mParent = scene->mRootNode;
node->mName.Set(name);
size_t meshIdx = mMeshes.size();
while(ReadToEndElement(D3MF::XmlTag::object)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh();
mesh->mName.Set(name);
mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx));
++meshIdx;
}
}
node->mNumMeshes = static_cast<unsigned int>(meshIds.size());
node->mMeshes = new unsigned int[node->mNumMeshes];
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
return node.release();
}
aiMesh *ReadMesh() {
aiMesh* mesh = new aiMesh();
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
ImportVertices(mesh);
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
ImportTriangles(mesh);
}
}
return mesh;
}
void ReadMetadata() {
const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
xmlReader->read();
const std::string value = xmlReader->getNodeData();
if ( name.empty() ) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back( entry );
}
void ImportVertices(aiMesh* mesh) {
std::vector<aiVector3D> vertices;
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex());
}
}
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
aiVector3D ReadVertex() {
aiVector3D vertex;
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr);
vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr);
return vertex;
}
void ImportTriangles(aiMesh* mesh) {
std::vector<aiFace> faces;
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
const std::string nodeName( xmlReader->getNodeName() );
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
faces.push_back(ReadTriangle());
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
if ( nullptr != pidToken ) {
int matIdx( std::atoi( pidToken ) );
mesh->mMaterialIndex = matIdx;
}
}
}
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
aiFace ReadTriangle() {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str())));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str())));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str())));
return face;
}
void ReadBaseMaterials() {
std::vector<unsigned int> MatIdArray;
const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
if ( nullptr != baseMaterialId ) {
unsigned int id = std::atoi( baseMaterialId );
const size_t newMatIdx( mMatArray.size() );
if ( id != mActiveMatGroup ) {
mActiveMatGroup = id;
MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
if ( mMatId2MatArray.end() == it ) {
MatIdArray.clear();
mMatId2MatArray[ id ] = MatIdArray;
} else {
MatIdArray = it->second;
}
}
MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
}
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
mMatArray.push_back( readMaterialDef() );
}
}
bool parseColor( const char *color, aiColor4D &diffuse ) {
if ( nullptr == color ) {
return false;
}
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
const size_t len( strlen( color ) );
if ( 9 != len && 7 != len) {
return false;
}
const char *buf( color );
if ( '#' != *buf ) {
return false;
}
++buf;
char comp[ 3 ] = { 0,0,'\0' };
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
if(7 == len)
return true;
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
return true;
}
void assignDiffuseColor( aiMaterial *mat ) {
const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
aiColor4D diffuse;
if ( parseColor( color, diffuse ) ) {
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
}
}
aiMaterial *readMaterialDef() {
aiMaterial *mat( nullptr );
const char *name( nullptr );
const std::string nodeName( xmlReader->getNodeName() );
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
std::string stdMatName;
aiString matName;
std::string strId( to_string( mActiveMatGroup ) );
stdMatName += "id";
stdMatName += strId;
stdMatName += "_";
if ( nullptr != name ) {
stdMatName += std::string( name );
} else {
stdMatName += "basemat";
}
matName.Set( stdMatName );
mat = new aiMaterial;
mat->AddProperty( &matName, AI_MATKEY_NAME );
assignDiffuseColor( mat );
}
return mat;
}
private:
bool ReadToStartElement(const std::string& startTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
return false;
}
bool ReadToEndElement(const std::string& closeTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false;
}
}
ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
private:
struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::vector<aiMesh*> mMeshes;
MatArray mMatArray;
unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray;
XmlReader* xmlReader;
};
} //namespace D3MF
static const aiImporterDesc desc = {
"3mf Importer",
"",
"",
"http://3mf.io/",
aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
0,
0,
0,
0,
"3mf"
};
D3MFImporter::D3MFImporter()
: BaseImporter() {
// empty
}
D3MFImporter::~D3MFImporter() {
// empty
}
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension( GetExtension( filename ) );
if(extension == desc.mFileExtensions ) {
return true;
} else if ( !extension.length() || checkSig ) {
if ( nullptr == pIOHandler ) {
return false;
}
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
return false;
}
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
return opcPackage.validate();
}
return false;
}
void D3MFImporter::SetupProperties(const Importer * /*pImp*/) {
// empty
}
const aiImporterDesc *D3MFImporter::GetInfo() const {
return &desc;
}
void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
D3MF::XmlSerializer xmlSerializer(xmlReader.get());
xmlSerializer.ImportXml(pScene);
}
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_3MF_IMPORTER

View File

@ -1,705 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter.cpp
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
// Header files, Assimp.
#include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
#include <assimp/fast_atof.h>
#include <assimp/DefaultIOSystem.h>
// Header files, stdlib.
#include <memory>
namespace Assimp
{
/// \var aiImporterDesc AMFImporter::Description
/// Conastant which hold importer description
const aiImporterDesc AMFImporter::Description = {
"Additive manufacturing file format(AMF) Importer",
"smalcom",
"",
"See documentation in source code. Chapter: Limitations.",
aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
0,
0,
0,
0,
"amf"
};
void AMFImporter::Clear()
{
mNodeElement_Cur = nullptr;
mUnit.clear();
mMaterial_Converted.clear();
mTexture_Converted.clear();
// Delete all elements
if(!mNodeElement_List.empty())
{
for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }
mNodeElement_List.clear();
}
}
AMFImporter::~AMFImporter()
{
if(mReader != nullptr) delete mReader;
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
Clear();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const
{
for(CAMFImporter_NodeElement* ne: mNodeElement_List)
{
if((ne->ID == pID) && (ne->Type == pType))
{
if(pNodeElement != nullptr) *pNodeElement = ne;
return true;
}
}// for(CAMFImporter_NodeElement* ne: mNodeElement_List)
return false;
}
bool AMFImporter::Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const
{
aiString node_name(pID.c_str());
for(aiNode* node: pNodeList)
{
if(node->mName == node_name)
{
if(pNode != nullptr) *pNode = node;
return true;
}
}// for(aiNode* node: pNodeList)
return false;
}
bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const
{
for(const SPP_Material& mat: mMaterial_Converted)
{
if(mat.ID == pID)
{
if(pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
return true;
}
}// for(const SPP_Material& mat: mMaterial_Converted)
return false;
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: throw set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::Throw_CloseNotFound(const std::string& pNode)
{
throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
}
void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName)
{
throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
}
void AMFImporter::Throw_IncorrectAttrValue(const std::string& pAttrName)
{
throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
}
void AMFImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription)
{
throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
}
void AMFImporter::Throw_ID_NotFound(const std::string& pID) const
{
throw DeadlyImportError("Not found node with name \"" + pID + "\".");
}
/*********************************************************************************************************************************************/
/************************************************************* Functions: XML set ************************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::XML_CheckNode_MustHaveChildren()
{
if(mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children.");
}
void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
{
static const size_t Uns_Skip_Len = 3;
const char* Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
static bool skipped_before[Uns_Skip_Len] = { false, false, false };
std::string nn(mReader->getNodeName());
bool found = false;
bool close_found = false;
size_t sk_idx;
for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
{
if(nn != Uns_Skip[sk_idx]) continue;
found = true;
if(mReader->isEmptyElement())
{
close_found = true;
goto casu_cres;
}
while(mReader->read())
{
if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName()))
{
close_found = true;
goto casu_cres;
}
}
}// for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
casu_cres:
if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
if(!close_found) Throw_CloseNotFound(nn);
if(!skipped_before[sk_idx])
{
skipped_before[sk_idx] = true;
ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
}
}
bool AMFImporter::XML_SearchNode(const std::string& pNodeName)
{
while(mReader->read())
{
if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
}
return false;
}
bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
{
std::string val(mReader->getAttributeValue(pAttrIdx));
if((val == "false") || (val == "0"))
return false;
else if((val == "true") || (val == "1"))
return true;
else
throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
}
float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
{
std::string val;
float tvalf;
ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx)
{
return strtoul10(mReader->getAttributeValue(pAttrIdx));
}
float AMFImporter::XML_ReadNode_GetVal_AsFloat()
{
std::string val;
float tvalf;
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32()
{
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
return strtoul10(mReader->getNodeData());
}
void AMFImporter::XML_ReadNode_GetVal_AsString(std::string& pValue)
{
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT)
throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
pValue = mReader->getNodeData();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: parse set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode)
{
mNodeElement_Cur->Child.push_back(pNode);// add new element to current element child list.
mNodeElement_Cur = pNode;// switch current element to new one.
}
void AMFImporter::ParseHelper_Node_Exit()
{
// check if we can walk up.
if(mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
}
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString)
{
size_t instr_len;
pOutString.clear();
instr_len = strlen(pInStr);
if(!instr_len) return;
pOutString.reserve(instr_len * 3 / 2);
// check and correct floats in format ".x". Must be "x.y".
if(pInStr[0] == '.') pOutString.push_back('0');
pOutString.push_back(pInStr[0]);
for(size_t ci = 1; ci < instr_len; ci++)
{
if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t')))
{
pOutString.push_back('0');
pOutString.push_back('.');
}
else
{
pOutString.push_back(pInStr[ci]);
}
}
}
static bool ParseHelper_Decode_Base64_IsBase64(const char pChar)
{
return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
}
void AMFImporter::ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const
{
// With help from
// René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html
const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uint8_t tidx = 0;
uint8_t arr4[4], arr3[3];
// check input data
if(pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
// prepare output place
pOutputData.clear();
pOutputData.reserve(pInputBase64.size() / 4 * 3);
for(size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--)
{
if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
{
arr4[tidx++] = pInputBase64[in_idx++];
if(tidx == 4)
{
for(tidx = 0; tidx < 4; tidx++) arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]);
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for(tidx = 0; tidx < 3; tidx++) pOutputData.push_back(arr3[tidx]);
tidx = 0;
}// if(tidx == 4)
}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
else
{
in_idx++;
}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else
}
if(tidx)
{
for(uint8_t i = tidx; i < 4; i++) arr4[i] = 0;
for(uint8_t i = 0; i < 4; i++) arr4[i] = (uint8_t)(base64_chars.find(arr4[i]));
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for(uint8_t i = 0; i < (tidx - 1); i++) pOutputData.push_back(arr3[i]);
}
}
void AMFImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
{
irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file
if(file.get() == NULL) throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
// generate a XML reader for it
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
//
// start reading
// search for root tag <amf>
if(XML_SearchNode("amf"))
ParseNode_Root();
else
throw DeadlyImportError("Root node \"amf\" not found.");
delete mReader;
// restore old XMLreader
mReader = OldReader;
}
// <amf
// unit="" - The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
// version="" - Version of file format.
// >
// </amf>
// Root XML element.
// Multi elements - No.
void AMFImporter::ParseNode_Root()
{
std::string unit, version;
CAMFImporter_NodeElement *ne( nullptr );
// 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
if(!mUnit.empty())
{
if((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit");
}
// create root node element.
ne = new CAMFImporter_NodeElement_Root(nullptr);
mNodeElement_Cur = ne;// set first "current" element
// and assign attribute's values
((CAMFImporter_NodeElement_Root*)ne)->Unit = unit;
((CAMFImporter_NodeElement_Root*)ne)->Version = version;
// Check for child nodes
if(!mReader->isEmptyElement())
{
MACRO_NODECHECK_LOOPBEGIN("amf");
if(XML_CheckNode_NameEqual("object")) { ParseNode_Object(); continue; }
if(XML_CheckNode_NameEqual("material")) { ParseNode_Material(); continue; }
if(XML_CheckNode_NameEqual("texture")) { ParseNode_Texture(); continue; }
if(XML_CheckNode_NameEqual("constellation")) { ParseNode_Constellation(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("amf");
mNodeElement_Cur = ne;// force restore "current" element
}// if(!mReader->isEmptyElement())
mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
}
// <constellation
// id="" - The Object ID of the new constellation being defined.
// >
// </constellation>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Constellation()
{
std::string id;
CAMFImporter_NodeElement* ne( nullptr );
// 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.
ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur);
CAMFImporter_NodeElement_Constellation& als = *((CAMFImporter_NodeElement_Constellation*)ne);// alias for convenience
if(!id.empty()) als.ID = id;
// Check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("constellation");
if(XML_CheckNode_NameEqual("instance")) { ParseNode_Instance(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("constellation");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <instance
// objectid="" - The Object ID of the new constellation being defined.
// >
// </instance>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Instance()
{
std::string objectid;
CAMFImporter_NodeElement* ne( nullptr );
// Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// used object id must be defined, check that.
if(objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
// create and define new grouping object.
ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);// alias for convenience
als.ObjectID = objectid;
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool read_flag[6] = { false, false, false, false, false, false };
als.Delta.Set(0, 0, 0);
als.Rotation.Set(0, 0, 0);
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("instance");
MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
MACRO_NODECHECK_LOOPEND("instance");
ParseHelper_Node_Exit();
// also convert degrees to radians.
als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <object
// id="" - A unique ObjectID for the new object being defined.
// >
// </object>
// An object definition.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Object()
{
std::string id;
CAMFImporter_NodeElement* ne( nullptr );
// Read attributes for node <object>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new geometry object.
ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur);
CAMFImporter_NodeElement_Object& als = *((CAMFImporter_NodeElement_Object*)ne);// alias for convenience
if(!id.empty()) als.ID = id;
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("object");
if(XML_CheckNode_NameEqual("color"))
{
// Check if color already defined for object.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if(XML_CheckNode_NameEqual("mesh")) { ParseNode_Mesh(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("object");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <metadata
// type="" - The type of the attribute.
// >
// </metadata>
// Specify additional information about an entity.
// Multi elements - Yes.
// Parent element - <amf>, <object>, <volume>, <material>, <vertex>.
//
// Reserved types are:
// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user.
// "Description" - A description of the content of the entity
// "URL" - A link to an external resource relating to the entity
// "Author" - Specifies the name(s) of the author(s) of the entity
// "Company" - Specifying the company generating the entity
// "CAD" - specifies the name of the originating CAD software and version
// "Revision" - specifies the revision of the entity
// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
void AMFImporter::ParseNode_Metadata()
{
std::string type, value;
CAMFImporter_NodeElement* ne( nullptr );
// read attribute
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// and value of node.
value = mReader->getNodeData();
// Create node element and assign read data.
ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur);
((CAMFImporter_NodeElement_Metadata*)ne)->Type = type;
((CAMFImporter_NodeElement_Metadata*)ne)->Value = value;
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
/*********************************************************************************************************************************************/
/******************************************************** Functions: BaseImporter set ********************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const
{
const std::string extension = GetExtension(pFile);
if ( extension == "amf" ) {
return true;
}
if(!extension.length() || pCheckSig)
{
const char* tokens[] = { "<amf" };
return SearchFileHeaderForToken( pIOHandler, pFile, tokens, 1 );
}
return false;
}
void AMFImporter::GetExtensionList(std::set<std::string>& pExtensionList)
{
pExtensionList.insert("amf");
}
const aiImporterDesc* AMFImporter::GetInfo () const
{
return &Description;
}
void AMFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
Clear();// delete old graph.
ParseFile(pFile, pIOHandler);
Postprocess_BuildScene(pScene);
// scene graph is ready, exit.
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -1,432 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter.hpp
/// \brief AMF-format files importer for Assimp.
/// \date 2016
/// \author smal.root@gmail.com
// Thanks to acorn89 for support.
#pragma once
#ifndef INCLUDED_AI_AMF_IMPORTER_H
#define INCLUDED_AI_AMF_IMPORTER_H
#include "AMFImporter_Node.hpp"
// Header files, Assimp.
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include "assimp/types.h"
#include <assimp/BaseImporter.h>
#include <assimp/irrXMLWrapper.h>
// Header files, stdlib.
#include <set>
namespace Assimp {
/// \class AMFImporter
/// Class that holding scene graph which include: geometry, metadata, materials etc.
///
/// Implementing features.
///
/// Limitations.
///
/// 1. When for texture mapping used set of source textures (r, g, b, a) not only one then attribute "tiled" for all set will be true if it true in any of
/// source textures.
/// Example. Triangle use for texture mapping three textures. Two of them has "tiled" set to false and one - set to true. In scene all three textures
/// will be tiled.
///
/// Unsupported features:
/// 1. Node <composite>, formulas in <composite> and <color>. For implementing this feature can be used expression parser "muParser" like in project
/// "amf_tools".
/// 2. Attribute "profile" in node <color>.
/// 3. Curved geometry: <edge>, <normal> and children nodes of them.
/// 4. Attributes: "unit" and "version" in <amf> read but do nothing.
/// 5. <metadata> stored only for root node <amf>.
/// 6. Color averaging of vertices for which <triangle>'s set different colors.
///
/// Supported nodes:
/// General:
/// <amf>; <constellation>; <instance> and children <deltax>, <deltay>, <deltaz>, <rx>, <ry>, <rz>; <metadata>;
///
/// Geometry:
/// <object>; <mesh>; <vertices>; <vertex>; <coordinates> and children <x>, <y>, <z>; <volume>; <triangle> and children <v1>, <v2>, <v3>;
///
/// Material:
/// <color> and children <r>, <g>, <b>, <a>; <texture>; <material>;
/// two variants of texture coordinates:
/// new - <texmap> and children <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>
/// old - <map> and children <u1>, <u2>, <u3>, <v1>, <v2>, <v3>
///
class AMFImporter : public BaseImporter {
private:
struct SPP_Material;// forward declaration
/// \struct SPP_Composite
/// Data type for post-processing step. More suitable container for part of material's composition.
struct SPP_Composite {
SPP_Material* Material;///< Pointer to material - part of composition.
std::string Formula;///< Formula for calculating ratio of \ref Material.
};
/// \struct SPP_Material
/// Data type for post-processing step. More suitable container for material.
struct SPP_Material {
std::string ID;///< Material ID.
std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material.
CAMFImporter_NodeElement_Color* Color;///< Color of material.
std::list<SPP_Composite> Composition;///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate.
/// \param [in] pX - "x" coordinate.
/// \param [in] pY - "y" coordinate.
/// \param [in] pZ - "z" coordinate.
/// \return calculated color.
aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
};
/// Data type for post-processing step. More suitable container for texture.
struct SPP_Texture {
std::string ID;
size_t Width, Height, Depth;
bool Tiled;
char FormatHint[9];// 8 for string + 1 for terminator.
uint8_t *Data;
};
/// Data type for post-processing step. Contain face data.
struct SComplexFace {
aiFace Face;///< Face vertices.
const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face.
const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
};
/// Clear all temporary data.
void Clear();
/***********************************************/
/************* Functions: find set *************/
/***********************************************/
/// Find specified node element in node elements list ( \ref mNodeElement_List).
/// \param [in] pID - ID(name) of requested node element.
/// \param [in] pType - type of node element.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node element is found, else - false.
bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const;
/// Find requested aiNode in node list.
/// \param [in] pID - ID(name) of requested node.
/// \param [in] pNodeList - list of nodes where to find the node.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node is found, else - false.
bool Find_ConvertedNode(const std::string& pID, std::list<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.
/// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \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
/// contain nullptr.
void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const;
/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
/// to converted textures list.
/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
/// \param [in] pID_R - ID of source "red" texture.
/// \param [in] pID_G - ID of source "green" texture.
/// \param [in] pID_B - ID of source "blue" texture.
/// \param [in] pID_A - ID of source "alpha" texture.
/// \return index of the texture in array of the converted textures.
size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A);
/// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
/// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
/// processing.
/// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated);
/// Check if child elements of node element is metadata and add it to scene node.
/// \param [in] pMetadataList - reference to list with collected metadata.
/// \param [out] pSceneNode - scene node in which metadata will be added.
void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const;
/// To create aiMesh and aiNode for it from <object>.
/// \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] pSceneNode - pointer to place where new aiNode will be created.
void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode);
/// Create mesh for every <volume> in <mesh>.
/// \param [in] pNodeElement - reference to node element which kept <mesh> data.
/// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all <volume>'s.
/// \param [in] pVertexColorArray - reference to vertices colors for all <volume>'s. If color for vertex is not set then corresponding member of array
/// contain nullptr.
/// \param [in] pObjectColor - pointer to colors for <object>. If color is not set then argument contain nullptr.
/// \param [in] pMaterialList - reference to a list with defined materials.
/// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor,
std::list<aiMesh*>& pMeshList, aiNode& pSceneNode);
/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial);
/// Create and add to aiNode's list new part of scene graph defined by <constellation>.
/// \param [in] pConstellation - reference to <constellation> node.
/// \param [out] pNodeList - reference to aiNode's list.
void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const;
/// Build Assimp scene graph in aiScene from collected data.
/// \param [out] pScene - pointer to aiScene where tree will be built.
void Postprocess_BuildScene(aiScene* pScene);
/// Call that function when close tag of node not found and exception must be raised.
/// E.g.:
/// <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.
/// \param [in] pInputBase64 - reference to input Base64-encoded string.
/// \param [out] pOutputData - reference to output array for decoded data.
void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const;
/// Parse <AMF> node of the file.
void ParseNode_Root();
/// Parse <constellation> node of the file.
void ParseNode_Constellation();
/// Parse <instance> node of the file.
void ParseNode_Instance();
/// Parse <material> node of the file.
void ParseNode_Material();
/// Parse <metadata> node.
void ParseNode_Metadata();
/// Parse <object> node of the file.
void ParseNode_Object();
/// Parse <texture> node of the file.
void ParseNode_Texture();
/// Parse <coordinates> node of the file.
void ParseNode_Coordinates();
/// Parse <edge> node of the file.
void ParseNode_Edge();
/// Parse <mesh> node of the file.
void ParseNode_Mesh();
/// Parse <triangle> node of the file.
void ParseNode_Triangle();
/// Parse <vertex> node of the file.
void ParseNode_Vertex();
/// Parse <vertices> node of the file.
void ParseNode_Vertices();
/// Parse <volume> node of the file.
void ParseNode_Volume();
/// Parse <color> node of the file.
void ParseNode_Color();
/// 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>.
void ParseNode_TexMap(const bool pUseOldName = false);
public:
/// Default constructor.
AMFImporter() AI_NO_EXCEPT
: mNodeElement_Cur(nullptr)
, mReader(nullptr) {
// empty
}
/// Default destructor.
~AMFImporter();
/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
/// Also exception can be thrown if trouble will found.
/// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile(const std::string& pFile, IOSystem* pIOHandler);
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const;
void GetExtensionList(std::set<std::string>& pExtensionList);
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
const aiImporterDesc* GetInfo ()const;
AMFImporter(const AMFImporter& pScene) = delete;
AMFImporter& operator=(const AMFImporter& pScene) = delete;
private:
static const aiImporterDesc Description;
CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
std::string mUnit;
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.
};
}// namespace Assimp
#endif // INCLUDED_AI_AMF_IMPORTER_H

View File

@ -1,357 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Geometry.cpp
/// \brief Parsing data from geometry nodes.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
namespace Assimp
{
// <mesh>
// </mesh>
// A 3D mesh hull.
// Multi elements - Yes.
// Parent element - <object>.
void AMFImporter::ParseNode_Mesh()
{
CAMFImporter_NodeElement* ne;
// create new mesh object.
ne = new CAMFImporter_NodeElement_Mesh(mNodeElement_Cur);
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool vert_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("mesh");
if(XML_CheckNode_NameEqual("vertices"))
{
// Check if data already defined.
if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
// read data and set flag about it
ParseNode_Vertices();
vert_read = true;
continue;
}
if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; }
MACRO_NODECHECK_LOOPEND("mesh");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <vertices>
// </vertices>
// The list of vertices to be used in defining triangles.
// Multi elements - No.
// Parent element - <mesh>.
void AMFImporter::ParseNode_Vertices()
{
CAMFImporter_NodeElement* ne;
// create new mesh object.
ne = new CAMFImporter_NodeElement_Vertices(mNodeElement_Cur);
// Check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertices");
if(XML_CheckNode_NameEqual("vertex")) { ParseNode_Vertex(); continue; }
MACRO_NODECHECK_LOOPEND("vertices");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <vertex>
// </vertex>
// A vertex to be referenced in triangles.
// Multi elements - Yes.
// Parent element - <vertices>.
void AMFImporter::ParseNode_Vertex()
{
CAMFImporter_NodeElement* ne;
// create new mesh object.
ne = new CAMFImporter_NodeElement_Vertex(mNodeElement_Cur);
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false;
bool coord_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertex");
if(XML_CheckNode_NameEqual("color"))
{
// Check if data already defined.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if(XML_CheckNode_NameEqual("coordinates"))
{
// Check if data already defined.
if(coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Coordinates();
coord_read = true;
continue;
}
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("vertex");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <coordinates>
// </coordinates>
// Specifies the 3D location of this vertex.
// Multi elements - No.
// Parent element - <vertex>.
//
// Children elements:
// <x>, <y>, <z>
// Multi elements - No.
// X, Y, or Z coordinate, respectively, of a vertex position in space.
void AMFImporter::ParseNode_Coordinates()
{
CAMFImporter_NodeElement* ne;
// create new color object.
ne = new CAMFImporter_NodeElement_Coordinates(mNodeElement_Cur);
CAMFImporter_NodeElement_Coordinates& als = *((CAMFImporter_NodeElement_Coordinates*)ne);// alias for convenience
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool read_flag[3] = { false, false, false };
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("coordinates");
MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x);
MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y);
MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z);
MACRO_NODECHECK_LOOPEND("coordinates");
ParseHelper_Node_Exit();
// check that all components was defined
if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined.");
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <volume
// materialid="" - Which material to use.
// type="" - What this volume describes can be “region” or “support”. If none specified, “object” is assumed. If support, then the geometric
// requirements 1-8 listed in section 5 do not need to be maintained.
// >
// </volume>
// Defines a volume from the established vertex list.
// Multi elements - Yes.
// Parent element - <mesh>.
void AMFImporter::ParseNode_Volume()
{
std::string materialid;
std::string type;
CAMFImporter_NodeElement* ne;
// 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
((CAMFImporter_NodeElement_Volume*)ne)->MaterialID = materialid;
((CAMFImporter_NodeElement_Volume*)ne)->Type = type;
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("volume");
if(XML_CheckNode_NameEqual("color"))
{
// Check if data already defined.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <volume>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if(XML_CheckNode_NameEqual("triangle")) { ParseNode_Triangle(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("volume");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <triangle>
// </triangle>
// Defines a 3D triangle from three vertices, according to the right-hand rule (counter-clockwise when looking from the outside).
// Multi elements - Yes.
// Parent element - <volume>.
//
// Children elements:
// <v1>, <v2>, <v3>
// Multi elements - No.
// Index of the desired vertices in a triangle or edge.
void AMFImporter::ParseNode_Triangle()
{
CAMFImporter_NodeElement* ne;
// create new color object.
ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
CAMFImporter_NodeElement_Triangle& als = *((CAMFImporter_NodeElement_Triangle*)ne);// alias for convenience
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false, tex_read = false;
bool read_flag[3] = { false, false, false };
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("triangle");
if(XML_CheckNode_NameEqual("color"))
{
// Check if data already defined.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <triangle>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if(XML_CheckNode_NameEqual("texmap"))// new name of node: "texmap".
{
// Check if data already defined.
if(tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for <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();
// check that all components was defined
if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined.");
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -1,340 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Node.hpp
/// \brief Elements of scene graph.
/// \date 2016
/// \author smal.root@gmail.com
#pragma once
#ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H
#define INCLUDED_AI_AMF_IMPORTER_NODE_H
// Header files, stdlib.
#include <list>
#include <string>
#include <vector>
// Header files, Assimp.
#include "assimp/types.h"
#include "assimp/scene.h"
/// \class CAMFImporter_NodeElement
/// Base class for elements of nodes.
class CAMFImporter_NodeElement {
public:
/// Define what data type contain node element.
enum EType {
ENET_Color, ///< Color element: <color>.
ENET_Constellation,///< Grouping element: <constellation>.
ENET_Coordinates, ///< Coordinates element: <coordinates>.
ENET_Edge, ///< Edge element: <edge>.
ENET_Instance, ///< Grouping element: <constellation>.
ENET_Material, ///< Material element: <material>.
ENET_Metadata, ///< Metadata element: <metadata>.
ENET_Mesh, ///< Metadata element: <mesh>.
ENET_Object, ///< Element which hold object: <object>.
ENET_Root, ///< Root element: <amf>.
ENET_Triangle, ///< Triangle element: <triangle>.
ENET_TexMap, ///< Texture coordinates element: <texmap> or <map>.
ENET_Texture, ///< Texture element: <texture>.
ENET_Vertex, ///< Vertex element: <vertex>.
ENET_Vertices, ///< Vertex element: <vertices>.
ENET_Volume, ///< Volume element: <volume>.
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
const EType Type;///< Type of element.
std::string ID;///< ID of element.
CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root.
std::list<CAMFImporter_NodeElement*> Child;///< Child elements.
public: /// Destructor, virtual..
virtual ~CAMFImporter_NodeElement() {
// empty
}
/// Disabled copy constructor and co.
CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete;
CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete;
CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete;
CAMFImporter_NodeElement() = delete;
protected:
/// In constructor inheritor must set element type.
/// \param [in] pType - element type.
/// \param [in] pParent - parent element.
CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent)
: Type(pType)
, ID()
, Parent(pParent)
, Child() {
// empty
}
};// class IAMFImporter_NodeElement
/// \struct CAMFImporter_NodeElement_Constellation
/// A collection of objects or constellations with specific relative locations.
struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Constellation, pParent)
{}
};// struct CAMFImporter_NodeElement_Constellation
/// \struct CAMFImporter_NodeElement_Instance
/// Part of constellation.
struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
std::string ObjectID;///< ID of object for instantiation.
/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
/// create an instance of the object in the current constellation.
aiVector3D Delta;
/// \var Rotation - The rotation, in degrees, to rotate the referenced object about its x, y, and z axes, respectively, to create an
/// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z.
aiVector3D Rotation;
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Instance, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Metadata
/// Structure that define metadata node.
struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement {
std::string Type;///< Type of "Value".
std::string Value;///< Value.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Metadata, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Root
/// Structure that define root node.
struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement {
std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
std::string Version;///< Version of format.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Root, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Color
/// Structure that define object node.
struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement {
bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA.
aiColor4D Color; ///< Constant color.
std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b..
/// @brief Constructor.
/// @param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Color, pParent)
, Composed( false )
, Color()
, Profile() {
// empty
}
};
/// \struct CAMFImporter_NodeElement_Material
/// Structure that define material node.
struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Material, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Object
/// Structure that define object node.
struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Object, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Mesh
/// Structure that define mesh node.
struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Mesh, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Vertex
/// Structure that define vertex node.
struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Vertex, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Edge
/// Structure that define edge node.
struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Edge, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Vertices
/// Structure that define vertices node.
struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Vertices, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Volume
/// Structure that define volume node.
struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement {
std::string MaterialID;///< Which material to use.
std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Volume, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_Coordinates
/// Structure that define coordinates node.
struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement
{
aiVector3D Coordinate;///< Coordinate.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Coordinates, pParent)
{}
};
/// \struct CAMFImporter_NodeElement_TexMap
/// Structure that define texture coordinates node.
struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement {
aiVector3D TextureCoordinate[3];///< Texture coordinates.
std::string TextureID_R;///< Texture ID for red color component.
std::string TextureID_G;///< Texture ID for green color component.
std::string TextureID_B;///< Texture ID for blue color component.
std::string TextureID_A;///< Texture ID for alpha color component.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_TexMap, pParent)
, TextureCoordinate{}
, TextureID_R()
, TextureID_G()
, TextureID_B()
, TextureID_A() {
// empty
}
};
/// \struct CAMFImporter_NodeElement_Triangle
/// Structure that define triangle node.
struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement {
size_t V[3];///< Triangle vertices.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Triangle, pParent) {
// empty
}
};
/// Structure that define texture node.
struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement {
size_t Width, Height, Depth;///< Size of the texture.
std::vector<uint8_t> Data;///< Data of the texture.
bool Tiled;
/// Constructor.
/// \param [in] pParent - pointer to parent node.
CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent)
: CAMFImporter_NodeElement(ENET_Texture, pParent)
, Width( 0 )
, Height( 0 )
, Depth( 0 )
, Data()
, Tiled( false ){
// empty
}
};
#endif // INCLUDED_AI_AMF_IMPORTER_NODE_H

View File

@ -1,978 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
// Header files, Assimp.
#include <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 CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const
{
CAMFImporter_NodeElement_Vertices* vn = nullptr;
size_t col_idx;
// All data stored in "vertices", search for it.
for(CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices*)ne_child;
}
// If "vertices" not found then no work for us.
if(vn == nullptr) return;
pVertexCoordinateArray.reserve(vn->Child.size());// all coordinates stored as child and we need to reserve space for future push_back's.
pVertexColorArray.resize(vn->Child.size());// colors count equal vertices count.
col_idx = 0;
// Inside vertices collect all data and place to arrays
for(CAMFImporter_NodeElement* vn_child: vn->Child)
{
// vertices, colors
if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
{
// by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr;
for(CAMFImporter_NodeElement* vtx: vn_child->Child)
{
if(vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates)
{
pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates*)vtx)->Coordinate);
continue;
}
if(vtx->Type == CAMFImporter_NodeElement::ENET_Color)
{
pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color*)vtx;
continue;
}
}// for(CAMFImporter_NodeElement* vtx: vn_child->Child)
col_idx++;
}// if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
}// for(CAMFImporter_NodeElement* vn_child: vn->Child)
}
size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B,
const std::string& pID_A)
{
size_t TextureConverted_Index;
std::string TextureConverted_ID;
// check input data
if(pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty())
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
// Create ID
TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A;
// Check if texture specified by set of IDs is converted already.
TextureConverted_Index = 0;
for(const SPP_Texture& tex_convd: mTexture_Converted)
{
if ( tex_convd.ID == TextureConverted_ID ) {
return TextureConverted_Index;
} else {
++TextureConverted_Index;
}
}
//
// Converted texture not found, create it.
//
CAMFImporter_NodeElement_Texture* src_texture[4]{nullptr};
std::vector<CAMFImporter_NodeElement_Texture*> src_texture_4check;
SPP_Texture converted_texture;
{// find all specified source textures
CAMFImporter_NodeElement* t_tex;
// R
if(!pID_R.empty())
{
if(!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
src_texture[0] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[0] = nullptr;
}
// G
if(!pID_G.empty())
{
if(!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
src_texture[1] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[1] = nullptr;
}
// B
if(!pID_B.empty())
{
if(!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
src_texture[2] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[2] = nullptr;
}
// A
if(!pID_A.empty())
{
if(!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
src_texture[3] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[3] = nullptr;
}
}// END: find all specified source textures
// check that all textures has same size
if(src_texture_4check.size() > 1)
{
for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
{
if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth))
{
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
}
}
}// if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture.Width = src_texture_4check[0]->Width;
converted_texture.Height = src_texture_4check[0]->Height;
converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false;
for(uint8_t i = 0; i < src_texture_4check.size(); i++) converted_texture.Tiled |= src_texture_4check[i]->Tiled;
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000");// copy initial string.
if(!pID_R.empty()) converted_texture.FormatHint[4] = '8';
if(!pID_G.empty()) converted_texture.FormatHint[5] = '8';
if(!pID_B.empty()) converted_texture.FormatHint[6] = '8';
if(!pID_A.empty()) converted_texture.FormatHint[7] = '8';
//
// Сopy data of textures.
//
size_t tex_size = 0;
size_t step = 0;
size_t off_g = 0;
size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied.
if(!pID_R.empty() && nullptr != src_texture[ 0 ] ) {
tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++;
}
if(!pID_G.empty() && nullptr != src_texture[ 1 ] ) {
tex_size += src_texture[1]->Data.size(); step++, off_b++;
}
if(!pID_B.empty() && nullptr != src_texture[ 2 ] ) {
tex_size += src_texture[2]->Data.size(); step++;
}
if(!pID_A.empty() && nullptr != src_texture[ 3 ] ) {
tex_size += src_texture[3]->Data.size(); step++;
}
// Create target array.
converted_texture.Data = new uint8_t[tex_size];
// And copy data
auto CopyTextureData = [&](const std::string& pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
{
if(!pID.empty())
{
for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
CAMFImporter_NodeElement_Texture* tex = src_texture[pSrcTexNum];
ai_assert(tex);
converted_texture.Data[idx_target] = tex->Data.at(idx_src);
}
}
};// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(pID_R, 0, step, 0);
CopyTextureData(pID_G, off_g, step, 1);
CopyTextureData(pID_B, off_b, step, 2);
CopyTextureData(pID_A, step - 1, step, 3);
// Store new converted texture ID
converted_texture.ID = TextureConverted_ID;
// Store new converted texture
mTexture_Converted.push_back(converted_texture);
return TextureConverted_Index;
}
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated)
{
auto texmap_is_equal = [](const CAMFImporter_NodeElement_TexMap* pTexMap1, const CAMFImporter_NodeElement_TexMap* pTexMap2) -> bool
{
if((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
if(pTexMap1 == nullptr) return false;
if(pTexMap2 == nullptr) return false;
if(pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
if(pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
if(pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
if(pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
return true;
};
pOutputList_Separated.clear();
if(pInputList.empty()) return;
do
{
SComplexFace face_start = pInputList.front();
std::list<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<CAMFImporter_NodeElement_Metadata*>& 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 CAMFImporter_NodeElement_Metadata& metadata: metadataList)
{
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)
{
CAMFImporter_NodeElement_Color* 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 CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
std::vector<aiVector3D> vertex_arr;
std::vector<CAMFImporter_NodeElement_Color*> color_arr;
// color for object
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color*)ne_child;
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh)
{
// Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh
Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
}
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
}
void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray,
const CAMFImporter_NodeElement_Color* pObjectColor, std::list<aiMesh*>& pMeshList, aiNode& pSceneNode)
{
std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it.
for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
const CAMFImporter_NodeElement_Color* ne_volume_color = nullptr;
const SPP_Material* cur_mat = nullptr;
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
{
/******************* Get faces *******************/
const CAMFImporter_NodeElement_Volume* ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume*>(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 CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
{
// color for volume
if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color)
{
ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color*>(ne_volume_child);
}
else if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle)// triangles, triangles colors
{
const CAMFImporter_NodeElement_Triangle& tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle*>(ne_volume_child);
SComplexFace complex_face;
// initialize pointers
complex_face.Color = nullptr;
complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates.
if(tri_al.Child.size())
{
for(const CAMFImporter_NodeElement* ne_triangle_child: tri_al.Child)
{
if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color)
complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color*>(ne_triangle_child);
else if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap*>(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=0;
if(pBiggerThan != nullptr)
{
bool found = false;
for(const SComplexFace& face: pFaceList)
{
for(size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++)
{
if(face.Face.mIndices[idx_vert] > *pBiggerThan)
{
rv = face.Face.mIndices[idx_vert];
found = true;
break;
}
}
if(found) break;
}
if(!found) return *pBiggerThan;
}
else
{
rv = pFaceList.front().Face.mIndices[0];
}// if(pBiggerThan != nullptr) else
for(const SComplexFace& face: pFaceList)
{
for(size_t vi = 0; vi < face.Face.mNumIndices; vi++)
{
if(face.Face.mIndices[vi] < rv)
{
if(pBiggerThan != nullptr)
{
if(face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
}
else
{
rv = face.Face.mIndices[vi];
}
}
}
}// for(const SComplexFace& face: pFaceList)
return rv;
};// auto VertexIndex_GetMinimal = [](const std::list<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 CAMFImporter_NodeElement_Material& pMaterial)
{
SPP_Material new_mat;
new_mat.ID = pMaterial.ID;
for(const CAMFImporter_NodeElement* mat_child: pMaterial.Child)
{
if(mat_child->Type == CAMFImporter_NodeElement::ENET_Color)
{
new_mat.Color = (CAMFImporter_NodeElement_Color*)mat_child;
}
else if(mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata)
{
new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata*)mat_child);
}
}// for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
// place converted material to special list
mMaterial_Converted.push_back(new_mat);
}
void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<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 CAMFImporter_NodeElement* ne: pConstellation.Child)
{
aiMatrix4x4 tmat;
aiNode* t_node;
aiNode* found_node;
if(ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue;
if(ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for conveniance
CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);
// find referenced object
if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation
t_node = new aiNode;
t_node->mParent = con_node;
// apply transformation
aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
// create array for one child node
t_node->mNumChildren = 1;
t_node->mChildren = new aiNode*[t_node->mNumChildren];
SceneCombiner::Copy(&t_node->mChildren[0], found_node);
t_node->mChildren[0]->mParent = t_node;
ch_node.push_back(t_node);
}// for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
// copy found aiNode's as children
if(ch_node.empty()) throw DeadlyImportError("<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<CAMFImporter_NodeElement_Metadata*> 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
CAMFImporter_NodeElement* root_el = nullptr;
for(CAMFImporter_NodeElement* ne: mNodeElement_List)
{
if(ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
root_el = ne;
break;
}// for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found.
if(root_el == nullptr) throw DeadlyImportError("Root(<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 CAMFImporter_NodeElement* root_child: root_el->Child)
{
if(root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material*)root_child));
}
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
//
// 3. <object>
for(const CAMFImporter_NodeElement* root_child: root_el->Child)
{
if(root_child->Type == CAMFImporter_NodeElement::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(*((CAMFImporter_NodeElement_Object*)root_child), mesh_list, &tnode);
if(tnode != nullptr) node_list.push_back(tnode);
}
}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes.
//
for(const CAMFImporter_NodeElement* root_child: root_el->Child)
{
// 4. <constellation>
if(root_child->Type == CAMFImporter_NodeElement::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(*((CAMFImporter_NodeElement_Constellation*)root_child), node_list);
}
// 5, <metadata>
if(root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata*)root_child);
}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// at now we can add collected metadata to root node
Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
//
// Check constellation children
//
// As said in specification:
// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
// And at this step we are checking that relations.
nl_clean_loop:
if(node_list.size() > 1)
{
// walk through all nodes
for(std::list<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

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -43,17 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file Implementation of the 3ds importer class */
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers
#include "3DSLoader.h"
#include "Common/TargetAnimation.h"
#include <assimp/StringComparison.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/StringComparison.h>
#include <memory>
#include <cctype>
#include <memory>
using namespace Assimp;
@ -61,8 +58,7 @@ static const unsigned int NotSet = 0xcdcdcdcd;
// ------------------------------------------------------------------------------------------------
// Setup final material indices, generae a default material if necessary
void Discreet3DSImporter::ReplaceDefaultMaterial()
{
void Discreet3DSImporter::ReplaceDefaultMaterial() {
// Try to find an existing material that matches the
// typical default material setting:
// - no textures
@ -70,8 +66,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
// NOTE: This is here to workaround the fact that some
// exporters are writing a default material, too.
unsigned int idx(NotSet);
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
{
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
std::string s = mScene->mMaterials[i].mName;
for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
*it = static_cast<char>(::tolower(*it));
@ -89,8 +84,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
{
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
continue;
}
idx = i;
@ -104,29 +98,23 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
unsigned int cnt = 0;
for (std::vector<D3DS::Mesh>::iterator
i = mScene->mMeshes.begin();
i != mScene->mMeshes.end();++i)
{
i != mScene->mMeshes.end(); ++i) {
for (std::vector<unsigned int>::iterator
a = (*i).mFaceMaterials.begin();
a != (*i).mFaceMaterials.end();++a)
{
a != (*i).mFaceMaterials.end(); ++a) {
// NOTE: The additional check seems to be necessary,
// some exporters seem to generate invalid data here
if (0xcdcdcdcd == (*a))
{
if (0xcdcdcdcd == (*a)) {
(*a) = idx;
++cnt;
}
else if ( (*a) >= mScene->mMaterials.size())
{
} else if ((*a) >= mScene->mMaterials.size()) {
(*a) = idx;
ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
++cnt;
}
}
}
if (cnt && idx == mScene->mMaterials.size())
{
if (cnt && idx == mScene->mMaterials.size()) {
// We need to create our own default material
D3DS::Material sMat("%%%DEFAULT");
sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f);
@ -138,20 +126,15 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
// ------------------------------------------------------------------------------------------------
// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
{
for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
{
void Discreet3DSImporter::CheckIndices(D3DS::Mesh &sMesh) {
for (std::vector<D3DS::Face>::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) {
// check whether all indices are in range
for (unsigned int a = 0; a < 3;++a)
{
if ((*i).mIndices[a] >= sMesh.mPositions.size())
{
for (unsigned int a = 0; a < 3; ++a) {
if ((*i).mIndices[a] >= sMesh.mPositions.size()) {
ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size() - 1;
}
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
{
if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) {
ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size() - 1;
}
@ -161,8 +144,7 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
// ------------------------------------------------------------------------------------------------
// Generate out unique verbose format representation
void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
{
void Discreet3DSImporter::MakeUnique(D3DS::Mesh &sMesh) {
// TODO: really necessary? I don't think. Just a waste of memory and time
// to do it now in a separate buffer.
@ -172,13 +154,11 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
if (sMesh.mTexCoords.size())
vNew2.resize(sMesh.mFaces.size() * 3);
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
{
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) {
D3DS::Face &face = sMesh.mFaces[i];
// Positions
for (unsigned int a = 0; a < 3;++a,++base)
{
for (unsigned int a = 0; a < 3; ++a, ++base) {
vNew[base] = sMesh.mPositions[face.mIndices[a]];
if (sMesh.mTexCoords.size())
vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
@ -192,8 +172,7 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
// ------------------------------------------------------------------------------------------------
// Convert a 3DS texture to texture keys in an aiMaterial
void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
{
void CopyTexture(aiMaterial &mat, D3DS::Texture &texture, aiTextureType type) {
// Setup the texture name
aiString tex;
tex.Set(texture.mMapName);
@ -210,8 +189,7 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
// Mirroring - double the scaling values
// FIXME: this is not really correct ...
if (texture.mMapMode == aiTextureMapMode_Mirror)
{
if (texture.mMapMode == aiTextureMapMode_Mirror) {
texture.mScaleU *= 2.0;
texture.mScaleV *= 2.0;
texture.mOffsetU /= 2.0;
@ -225,12 +203,10 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
// ------------------------------------------------------------------------------------------------
// Convert a 3DS material to an aiMaterial
void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
aiMaterial& mat)
{
aiMaterial &mat) {
// NOTE: Pass the background image to the viewer by bypassing the
// material system. This is an evil hack, never do it again!
if (0 != mBackgroundImage.length() && bHasBG)
{
if (0 != mBackgroundImage.length() && bHasBG) {
aiString tex;
tex.Set(mBackgroundImage);
mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
@ -256,14 +232,10 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
// Phong shininess and shininess strength
if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
D3DS::Discreet3DS::Metal == oldMat.mShading)
{
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
{
D3DS::Discreet3DS::Metal == oldMat.mShading) {
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) {
oldMat.mShading = D3DS::Discreet3DS::Gouraud;
}
else
{
} else {
mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
}
@ -276,43 +248,45 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
mat.AddProperty<ai_real>(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING);
// Two sided rendering?
if (oldMat.mTwoSided)
{
if (oldMat.mTwoSided) {
int i = 1;
mat.AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
}
// Shading mode
aiShadingMode eShading = aiShadingMode_NoShading;
switch (oldMat.mShading)
{
switch (oldMat.mShading) {
case D3DS::Discreet3DS::Flat:
eShading = aiShadingMode_Flat; break;
eShading = aiShadingMode_Flat;
break;
// I don't know what "Wire" shading should be,
// assume it is simple lambertian diffuse shading
case D3DS::Discreet3DS::Wire:
{
case D3DS::Discreet3DS::Wire: {
// Set the wireframe flag
unsigned int iWire = 1;
mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; break;
eShading = aiShadingMode_Gouraud;
break;
// assume cook-torrance shading for metals.
case D3DS::Discreet3DS::Phong:
eShading = aiShadingMode_Phong; break;
eShading = aiShadingMode_Phong;
break;
case D3DS::Discreet3DS::Metal:
eShading = aiShadingMode_CookTorrance; break;
eShading = aiShadingMode_CookTorrance;
break;
// FIX to workaround a warning with GCC 4 who complained
// about a missing case Blinn: here - Blinn isn't a valid
// value in the 3DS Loader, it is just needed for ASE
case D3DS::Discreet3DS::Blinn:
eShading = aiShadingMode_Blinn; break;
eShading = aiShadingMode_Blinn;
break;
}
int eShading_ = static_cast<int>(eShading);
mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
@ -355,8 +329,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
// ------------------------------------------------------------------------------------------------
// Split meshes by their materials and generate output aiMesh'es
void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
{
void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
std::vector<aiMesh *> avOutMeshes;
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
@ -371,13 +344,11 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
unsigned int iNum = 0;
for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
a != (*i).mFaceMaterials.end();++a,++iNum)
{
a != (*i).mFaceMaterials.end(); ++a, ++iNum) {
aiSplit[*a].push_back(iNum);
}
// now generate submeshes
for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
{
for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) {
if (aiSplit[p].empty()) {
continue;
}
@ -402,20 +373,17 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
if ((*i).mTexCoords.size())
{
if ((*i).mTexCoords.size()) {
meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
}
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
{
for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) {
unsigned int index = aiSplit[p][q];
aiFace &face = meshOut->mFaces[q];
face.mIndices = new unsigned int[3];
face.mNumIndices = 3;
for (unsigned int a = 0; a < 3;++a,++base)
{
for (unsigned int a = 0; a < 3; ++a, ++base) {
unsigned int idx = (*i).mFaces[index].mIndices[a];
meshOut->mVertices[base] = (*i).mPositions[idx];
meshOut->mNormals[base] = (*i).mNormals[idx];
@ -445,24 +413,21 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
// ------------------------------------------------------------------------------------------------
// Add a node to the scenegraph and setup its final transformation
void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
{
D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) {
std::vector<unsigned int> iArray;
iArray.reserve(3);
aiMatrix4x4 abs;
// Find all meshes with the same name as the node
for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
{
for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) {
const D3DS::Mesh *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0];
ai_assert(NULL != pcMesh);
ai_assert(nullptr != pcMesh);
if (pcIn->mName == pcMesh->mName)
iArray.push_back(a);
}
if (!iArray.empty())
{
if (!iArray.empty()) {
// The matrix should be identical for all meshes with the
// same name. It HAS to be identical for all meshes .....
D3DS::Mesh *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]);
@ -470,7 +435,8 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
// Compute the inverse of the transformation matrix to move the
// vertices back to their relative and local space
aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
mInv.Inverse();mInvTransposed.Transpose();
mInv.Inverse();
mInvTransposed.Transpose();
aiVector3D pivot = pcIn->vPivot;
pcOut->mNumMeshes = (unsigned int)iArray.size();
@ -479,8 +445,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
const unsigned int iIndex = iArray[i];
aiMesh *const mesh = pcSOut->mMeshes[iIndex];
if (mesh->mColors[1] == NULL)
{
if (mesh->mColors[1] == nullptr) {
// Transform the vertices back into their local space
// fixme: consider computing normals after this, so we don't need to transform them
const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices;
@ -492,8 +457,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
}
// Handle negative transformation matrix determinant -> invert vertex x
if (imesh->mMat.Determinant() < 0.0f)
{
if (imesh->mMat.Determinant() < 0.0f) {
/* we *must* have normals */
for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
pvCurrent->x *= -1.f;
@ -503,16 +467,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
}
// Handle pivot point
if (pivot.x || pivot.y || pivot.z)
{
if (pivot.x || pivot.y || pivot.z) {
for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
*pvCurrent -= pivot;
}
}
mesh->mColors[1] = (aiColor4D *)1;
}
else
} else
mesh->mColors[1] = (aiColor4D *)1;
// Setup the mesh index
@ -522,15 +484,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
// Setup the name of the node
// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
if (pcIn->mInstanceNumber > 1)
{
if (pcIn->mInstanceNumber > 1) {
char tmp[12];
ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
std::string tempStr = pcIn->mName + "_inst_";
tempStr += tmp;
pcOut->mName.Set(tempStr);
}
else
} else
pcOut->mName.Set(pcIn->mName);
// Now build the transformation matrix of the node
@ -543,26 +503,28 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
}
pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix());
}
else if (pcIn->aCameraRollKeys.size())
{
} else if (pcIn->aCameraRollKeys.size()) {
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue),
pcOut->mTransformation);
}
// SCALING
aiMatrix4x4 &m = pcOut->mTransformation;
if (pcIn->aScalingKeys.size())
{
if (pcIn->aScalingKeys.size()) {
const aiVector3D &v = pcIn->aScalingKeys[0].mValue;
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
m.a1 *= v.x;
m.b1 *= v.x;
m.c1 *= v.x;
m.a2 *= v.y;
m.b2 *= v.y;
m.c2 *= v.y;
m.a3 *= v.z;
m.b3 *= v.z;
m.c3 *= v.z;
}
// TRANSLATION
if (pcIn->aPositionKeys.size())
{
if (pcIn->aPositionKeys.size()) {
const aiVector3D &v = pcIn->aPositionKeys[0].mValue;
m.a4 += v.x;
m.b4 += v.y;
@ -572,21 +534,18 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
// Generate animation channels for the node
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
pcIn->aTargetPositionKeys.size() > 1)
{
pcIn->aTargetPositionKeys.size() > 1) {
aiAnimation *anim = pcSOut->mAnimations[0];
ai_assert(nullptr != anim);
if (pcIn->aCameraRollKeys.size() > 1)
{
ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
if (pcIn->aCameraRollKeys.size() > 1) {
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ...");
// Camera roll keys - in fact they're just rotations
// around the camera's z axis. The angles are given
// in degrees (and they're clockwise).
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
{
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) {
aiQuatKey &q = pcIn->aRotationKeys[i];
aiFloatKey &f = pcIn->aCameraRollKeys[i];
@ -599,7 +558,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
#if 0
if (pcIn->aTargetPositionKeys.size() > 1)
{
ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ...");
// Camera or spot light - need to convert the separate
// target position channel to our representation
@ -655,8 +614,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
nda->mNodeName.Set(pcIn->mName);
// POSITION keys
if (pcIn->aPositionKeys.size() > 0)
{
if (pcIn->aPositionKeys.size() > 0) {
nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0],
@ -664,15 +622,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
}
// ROTATION keys
if (pcIn->aRotationKeys.size() > 0)
{
if (pcIn->aRotationKeys.size() > 0) {
nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
// Rotations are quaternion offsets
aiQuaternion abs1;
for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
{
for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) {
const aiQuatKey &q = pcIn->aRotationKeys[n];
abs1 = (n ? abs1 * q.mValue : q.mValue);
@ -682,8 +638,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
}
// SCALING keys
if (pcIn->aScalingKeys.size() > 0)
{
if (pcIn->aScalingKeys.size() > 0) {
nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0],
@ -697,8 +652,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
// Recursively process all children
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
for (unsigned int i = 0; i < size;++i)
{
for (unsigned int i = 0; i < size; ++i) {
pcOut->mChildren[i] = new aiNode();
pcOut->mChildren[i]->mParent = pcOut;
AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs);
@ -707,16 +661,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
// ------------------------------------------------------------------------------------------------
// Find out how many node animation channels we'll have finally
void CountTracks(D3DS::Node* node, unsigned int& cnt)
{
void CountTracks(D3DS::Node *node, unsigned int &cnt) {
//////////////////////////////////////////////////////////////////////////////
// We will never generate more than one channel for a node, so
// this is rather easy here.
if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
node->aTargetPositionKeys.size() > 1)
{
node->aTargetPositionKeys.size() > 1) {
++cnt;
// account for the additional channel for the camera/spotlight target position
@ -730,11 +682,9 @@ void CountTracks(D3DS::Node* node, unsigned int& cnt)
// ------------------------------------------------------------------------------------------------
// Generate the output node graph
void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
{
void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
pcOut->mRootNode = new aiNode();
if (0 == mRootNode->mChildren.size())
{
if (0 == mRootNode->mChildren.size()) {
//////////////////////////////////////////////////////////////////////////////
// It seems the file is so messed up that it has not even a hierarchy.
// generate a flat hiearachy which looks like this:
@ -755,8 +705,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
// Build dummy nodes for all meshes
unsigned int a = 0;
for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
{
for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) {
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
pcNode->mMeshes = new unsigned int[1];
@ -768,8 +717,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
}
// Build dummy nodes for all cameras
for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
{
for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) {
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
@ -778,24 +726,20 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
}
// Build dummy nodes for all lights
for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
{
for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) {
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
// Build a name for the node
pcNode->mName = mScene->mLights[i]->mName;
}
}
else
{
} else {
// First of all: find out how many scaling, rotation and translation
// animation tracks we'll have afterwards
unsigned int numChannel = 0;
CountTracks(mRootNode, numChannel);
if (numChannel)
{
if (numChannel) {
// Allocate a primary animation channel
pcOut->mNumAnimations = 1;
pcOut->mAnimations = new aiAnimation *[1];
@ -814,37 +758,34 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
}
// We used the first and second vertex color set to store some temporary values so we need to cleanup here
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
{
pcOut->mMeshes[a]->mColors[0] = NULL;
pcOut->mMeshes[a]->mColors[1] = NULL;
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
pcOut->mMeshes[a]->mColors[0] = nullptr;
pcOut->mMeshes[a]->mColors[1] = nullptr;
}
pcOut->mRootNode->mTransformation = aiMatrix4x4(
1.f, 0.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, -1.f, 0.f, 0.f,
0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
0.f, 0.f, 0.f, 1.f) *
pcOut->mRootNode->mTransformation;
// If the root node is unnamed name it "<3DSRoot>"
if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") ||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
{
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) {
pcOut->mRootNode->mName.Set("<3DSRoot>");
}
}
// ------------------------------------------------------------------------------------------------
// Convert all meshes in the scene and generate the final output scene.
void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
{
void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
// Allocate enough storage for all output materials
pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials];
// ... and convert the 3DS materials to aiMaterial's
for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
{
for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) {
aiMaterial *pcNew = new aiMaterial();
ConvertMaterial(mScene->mMaterials[i], *pcNew);
pcOut->mMaterials[i] = pcNew;
@ -855,16 +796,14 @@ void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
// Now copy all light sources to the output scene
pcOut->mNumLights = (unsigned int)mScene->mLights.size();
if (pcOut->mNumLights)
{
if (pcOut->mNumLights) {
pcOut->mLights = new aiLight *[pcOut->mNumLights];
::memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights);
}
// Now copy all cameras to the output scene
pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
if (pcOut->mNumCameras)
{
if (pcOut->mNumCameras) {
pcOut->mCameras = new aiCamera *[pcOut->mNumCameras];
::memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras);
}

View File

@ -43,16 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
#include "3DS/3DSExporter.h"
#include "3DS/3DSLoader.h"
#include "3DS/3DSHelper.h"
#include "AssetLib/3DS/3DSExporter.h"
#include "AssetLib/3DS/3DSHelper.h"
#include "AssetLib/3DS/3DSLoader.h"
#include "PostProcessing/SplitLargeMeshes.h"
#include <assimp/SceneCombiner.h>
#include <assimp/StringComparison.h>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
@ -70,14 +70,13 @@ namespace {
// size based on the then-position of the output stream cursor is filled in.
class ChunkWriter {
enum {
CHUNK_SIZE_NOT_SET = 0xdeadbeef
, SIZE_OFFSET = 2
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
SIZE_OFFSET = 2
};
public:
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
: writer(writer)
{
public:
ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
writer(writer) {
chunk_start_pos = writer.GetCurrentPos();
writer.PutU2(chunk_type);
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
@ -99,7 +98,6 @@ namespace {
std::size_t chunk_start_pos;
};
// Return an unique name for a given |mesh| attached to |node| that
// preserves the mesh's given name if it has one. |index| is the index
// of the mesh in |aiScene::mMeshes|.
@ -149,12 +147,11 @@ namespace {
CollectMeshes(node->mChildren[i], meshes);
}
}
}
} // namespace
// ------------------------------------------------------------------------------------------------
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
{
void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
std::shared_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
if (!outfile) {
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
@ -186,10 +183,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
: scene(scene)
, writer(outfile)
{
Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene *scene) :
scene(scene), writer(outfile) {
CollectTrafos(scene->mRootNode, trafos);
CollectMeshes(scene->mRootNode, meshes);
@ -217,10 +212,8 @@ Discreet3DSExporter::~Discreet3DSExporter() {
// empty
}
// ------------------------------------------------------------------------------------------------
int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
{
int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) {
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
{
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
@ -276,8 +269,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMaterials()
{
void Discreet3DSExporter::WriteMaterials() {
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
const aiMaterial &mat = *scene->mMaterials[i];
@ -304,6 +296,12 @@ void Discreet3DSExporter::WriteMaterials()
WriteColor(color);
}
float f;
if (mat.Get(AI_MATKEY_OPACITY, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TRANSPARENCY);
WritePercentChunk(1.0f - f);
}
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
WriteColor(color);
@ -341,8 +339,6 @@ void Discreet3DSExporter::WriteMaterials()
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
}
float f;
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
WritePercentChunk(f);
@ -370,14 +366,13 @@ void Discreet3DSExporter::WriteMaterials()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
{
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
aiString path;
aiTextureMapMode map_mode[2] = {
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
};
ai_real blend = 1.0;
if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
return;
}
@ -400,8 +395,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
uint16_t val = 0; // WRAP
if (map_mode[0] == aiTextureMapMode_Mirror) {
val = 0x2;
}
else if (map_mode[0] == aiTextureMapMode_Decal) {
} else if (map_mode[0] == aiTextureMapMode_Decal) {
val = 0x10;
}
writer.PutU2(val);
@ -410,8 +404,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMeshes()
{
void Discreet3DSExporter::WriteMeshes() {
// NOTE: 3DS allows for instances. However:
// i) not all importers support reading them
// ii) instances are not as flexible as they are in assimp, in particular,
@ -441,7 +434,6 @@ void Discreet3DSExporter::WriteMeshes()
const std::string &name = GetMeshName(mesh, mesh_idx, node);
WriteString(name);
// TRIMESH chunk
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
@ -524,8 +516,7 @@ void Discreet3DSExporter::WriteMeshes()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
{
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT);
const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
WriteString(name);
@ -577,6 +568,5 @@ void Discreet3DSExporter::WritePercentChunk(double f) {
writer.PutF8(f);
}
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -321,9 +321,10 @@ public:
struct Face : public FaceWithSmoothingGroup {
};
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4315)
#endif
#endif // _MSC_VER
// ---------------------------------------------------------------------------
/** Helper structure representing a texture */
@ -412,6 +413,10 @@ struct Texture {
#include <assimp/Compiler/poppack1.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
// ---------------------------------------------------------------------------
/** Helper structure representing a 3ds material */
struct Material {
@ -441,12 +446,31 @@ struct Material {
// empty
}
Material(const Material &other) = default;
Material &operator=(const Material &other) = default;
Material(const Material &other) :
mName(other.mName),
mDiffuse(other.mDiffuse),
mSpecularExponent(other.mSpecularExponent),
mShininessStrength(other.mShininessStrength),
mSpecular(other.mSpecular),
mAmbient(other.mAmbient),
mShading(other.mShading),
mTransparency(other.mTransparency),
sTexDiffuse(other.sTexDiffuse),
sTexOpacity(other.sTexOpacity),
sTexSpecular(other.sTexSpecular),
sTexReflective(other.sTexReflective),
sTexBump(other.sTexBump),
sTexEmissive(other.sTexEmissive),
sTexShininess(other.sTexShininess),
mBumpHeight(other.mBumpHeight),
mEmissive(other.mEmissive),
sTexAmbient(other.sTexAmbient),
mTwoSided(other.mTwoSided) {
// empty
}
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
Material(Material &&other) AI_NO_EXCEPT
: mName(std::move(other.mName)),
Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)),
mDiffuse(std::move(other.mDiffuse)),
mSpecularExponent(std::move(other.mSpecularExponent)),
mShininessStrength(std::move(other.mShininessStrength)),
@ -465,6 +489,7 @@ struct Material {
mEmissive(std::move(other.mEmissive)),
sTexAmbient(std::move(other.sTexAmbient)),
mTwoSided(std::move(other.mTwoSided)) {
// empty
}
Material &operator=(Material &&other) AI_NO_EXCEPT {
@ -593,7 +618,12 @@ struct Node {
Node() = delete;
explicit Node(const std::string &name) :
mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) {
mParent(nullptr),
mName(name),
mInstanceNumber(0),
mHierarchyPos(0),
mHierarchyIndex(0),
mInstanceCount(1) {
aRotationKeys.reserve(20);
aPositionKeys.reserve(20);
aScalingKeys.reserve(20);

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -47,15 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* http://www.the-labs.com/Blender/3DS-details.html
*/
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
#include "3DSLoader.h"
#include <assimp/IOSystem.hpp>
#include <assimp/StringComparison.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <assimp/StringComparison.h>
#include <assimp/IOSystem.hpp>
using namespace Assimp;
@ -72,7 +69,6 @@ static const aiImporterDesc desc = {
"3ds prj"
};
// ------------------------------------------------------------------------------------------------
// Begins a new parsing block
// - Reads the current chunk and validates it
@ -88,8 +84,7 @@ static const aiImporterDesc desc = {
if (chunkSize <= 0) \
continue; \
const unsigned int oldReadLimit = stream->SetReadLimit( \
stream->GetCurrentPos() + chunkSize); \
stream->GetCurrentPos() + chunkSize);
// ------------------------------------------------------------------------------------------------
// End a parsing block
@ -103,15 +98,8 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
Discreet3DSImporter::Discreet3DSImporter()
: stream()
, mLastNodeIndex()
, mCurrentNode()
, mRootNode()
, mScene()
, mMasterScale()
, bHasBG()
, bIsPrj() {
Discreet3DSImporter::Discreet3DSImporter() :
stream(), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() {
// empty
}
@ -141,28 +129,25 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle
// ------------------------------------------------------------------------------------------------
// Loader registry entry
const aiImporterDesc* Discreet3DSImporter::GetInfo () const
{
const aiImporterDesc *Discreet3DSImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/)
{
void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
// nothing to be done for the moment
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void Discreet3DSImporter::InternReadFile(const std::string &pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
aiScene *pScene, IOSystem *pIOHandler) {
StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
// We should have at least one chunk
if (theStream.GetRemainingSize() < 16) {
throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile);
}
this->stream = &theStream;
@ -177,7 +162,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
mRootNode = mCurrentNode;
mRootNode->mHierarchyPos = -1;
mRootNode->mHierarchyIndex = -1;
mRootNode->mParent = NULL;
mRootNode->mParent = nullptr;
mMasterScale = 1.0f;
mBackgroundImage = "";
bHasBG = false;
@ -193,14 +178,14 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
// file.
for (auto &mesh : mScene->mMeshes) {
if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) {
throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile);
}
CheckIndices(mesh);
MakeUnique(mesh);
ComputeNormalsWithSmoothingsGroups<D3DS::Face>(mesh);
}
// Replace all occurences of the default material with a
// Replace all occurrences of the default material with a
// valid material. Generate it if no material containing
// DEFAULT in its name has been found in the file
ReplaceDefaultMaterial();
@ -227,11 +212,12 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
// ------------------------------------------------------------------------------------------------
// Applies a master-scaling factor to the imported scene
void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
{
void Discreet3DSImporter::ApplyMasterScale(aiScene *pScene) {
// There are some 3DS files with a zero scaling factor
if (!mMasterScale)mMasterScale = 1.0f;
else mMasterScale = 1.0f / mMasterScale;
if (!mMasterScale)
mMasterScale = 1.0f;
else
mMasterScale = 1.0f / mMasterScale;
// Construct an uniform scaling matrix and multiply with it
pScene->mRootNode->mTransformation *= aiMatrix4x4(
@ -245,8 +231,7 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
// ------------------------------------------------------------------------------------------------
// Reads a new chunk from the file
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
{
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk *pcOut) {
ai_assert(pcOut != nullptr);
pcOut->Flag = stream->GetI2();
@ -263,8 +248,7 @@ void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
// ------------------------------------------------------------------------------------------------
// Skip a chunk
void Discreet3DSImporter::SkipChunk()
{
void Discreet3DSImporter::SkipChunk() {
Discreet3DS::Chunk psChunk;
ReadChunk(&psChunk);
@ -274,13 +258,11 @@ void Discreet3DSImporter::SkipChunk()
// ------------------------------------------------------------------------------------------------
// Process the primary chunk of the file
void Discreet3DSImporter::ParseMainChunk()
{
void Discreet3DSImporter::ParseMainChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_PRJ:
bIsPrj = true;
@ -295,13 +277,11 @@ void Discreet3DSImporter::ParseMainChunk()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseEditorChunk()
{
void Discreet3DSImporter::ParseEditorChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_OBJMESH:
ParseObjectChunk();
@ -314,36 +294,31 @@ void Discreet3DSImporter::ParseEditorChunk()
ParseKeyframeChunk();
break;
case Discreet3DS::CHUNK_VERSION:
{
case Discreet3DS::CHUNK_VERSION: {
// print the version number
char buff[10];
ASSIMP_itoa10(buff, stream->GetI2());
ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
}
break;
} break;
};
ASSIMP_3DS_END_CHUNK();
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseObjectChunk()
{
void Discreet3DSImporter::ParseObjectChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
case Discreet3DS::CHUNK_OBJBLOCK:
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_OBJBLOCK: {
unsigned int cnt = 0;
const char *sz = (const char *)stream->GetPtr();
// Get the name of the geometry object
while (stream->GetI1())++cnt;
while (stream->GetI1())
++cnt;
ParseChunk(sz, cnt);
}
break;
} break;
case Discreet3DS::CHUNK_MAT_MATERIAL:
@ -357,24 +332,22 @@ void Discreet3DSImporter::ParseObjectChunk()
// This is the ambient base color of the scene.
// We add it to the ambient color of all materials
ParseColorChunk(&mClrAmbient, true);
if (is_qnan(mClrAmbient.r))
{
if (is_qnan(mClrAmbient.r)) {
// We failed to read the ambient base color.
ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
}
break;
case Discreet3DS::CHUNK_BIT_MAP:
{
case Discreet3DS::CHUNK_BIT_MAP: {
// Specifies the background image. The string should already be
// properly 0 terminated but we need to be sure
unsigned int cnt = 0;
const char *sz = (const char *)stream->GetPtr();
while (stream->GetI1())++cnt;
while (stream->GetI1())
++cnt;
mBackgroundImage = std::string(sz, cnt);
}
break;
} break;
case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
bHasBG = true;
@ -389,8 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
{
void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
ASSIMP_3DS_BEGIN_CHUNK();
// IMPLEMENTATION NOTE;
@ -399,20 +371,16 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
// to to be able to return valid cameras/lights even if no scenegraph is given.
// get chunk type
switch (chunk.Flag)
{
case Discreet3DS::CHUNK_TRIMESH:
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_TRIMESH: {
// this starts a new triangle mesh
mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num)));
// Read mesh chunks
ParseMeshChunk();
}
break;
} break;
case Discreet3DS::CHUNK_LIGHT:
{
case Discreet3DS::CHUNK_LIGHT: {
// This starts a new light
aiLight *light = new aiLight();
mScene->mLights.push_back(light);
@ -435,15 +403,13 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
light->mColorSpecular = light->mColorDiffuse;
light->mColorAmbient = mClrAmbient;
if (light->mType == aiLightSource_UNDEFINED)
{
if (light->mType == aiLightSource_UNDEFINED) {
// It must be a point light
light->mType = aiLightSource_POINT;
}}
break;
}
} break;
case Discreet3DS::CHUNK_CAMERA:
{
case Discreet3DS::CHUNK_CAMERA: {
// This starts a new camera
aiCamera *camera = new aiCamera();
mScene->mCameras.push_back(camera);
@ -465,8 +431,8 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
camera->mLookAt = aiVector3D(0.0, 1.0, 0.0);
}
else camera->mLookAt /= len;
} else
camera->mLookAt /= len;
// And finally - the camera rotation angle, in counter clockwise direction
const ai_real angle = AI_DEG_TO_RAD(stream->GetF4());
@ -482,21 +448,19 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
// Now check for further subchunks
if (!bIsPrj) /* fixme */ {
ParseCameraChunk();
}}
break;
}
} break;
};
ASSIMP_3DS_END_CHUNK();
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseLightChunk()
{
void Discreet3DSImporter::ParseLightChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
aiLight *light = mScene->mLights.back();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_DL_SPOTLIGHT:
// Now we can be sure that the light is a spot light
light->mType = aiLightSource_SPOT;
@ -537,14 +501,12 @@ void Discreet3DSImporter::ParseLightChunk()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseCameraChunk()
{
void Discreet3DSImporter::ParseCameraChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
aiCamera *camera = mScene->mCameras.back();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
// near and far clip plane
case Discreet3DS::CHUNK_CAM_RANGES:
camera->mClipPlaneNear = stream->GetF4();
@ -556,13 +518,11 @@ void Discreet3DSImporter::ParseCameraChunk()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseKeyframeChunk()
{
void Discreet3DSImporter::ParseKeyframeChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_TRACKCAMTGT:
case Discreet3DS::CHUNK_TRACKSPOTL:
case Discreet3DS::CHUNK_TRACKCAMERA:
@ -580,8 +540,7 @@ void Discreet3DSImporter::ParseKeyframeChunk()
// ------------------------------------------------------------------------------------------------
// Little helper function for ParseHierarchyChunk
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
{
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node *pcNode, D3DS::Node *pcCurrent) {
if (!pcCurrent) {
mRootNode->push_back(pcNode);
return;
@ -590,8 +549,8 @@ void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCur
if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) {
if (pcCurrent->mParent) {
pcCurrent->mParent->push_back(pcNode);
}
else pcCurrent->push_back(pcNode);
} else
pcCurrent->push_back(pcNode);
return;
}
return InverseNodeSearch(pcNode, pcCurrent->mParent);
@ -617,15 +576,13 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) {
// ------------------------------------------------------------------------------------------------
// Binary predicate for std::unique()
template <class T>
bool KeyUniqueCompare(const T& first, const T& second)
{
bool KeyUniqueCompare(const T &first, const T &second) {
return first.mTime == second.mTime;
}
// ------------------------------------------------------------------------------------------------
// Skip some additional import data.
void Discreet3DSImporter::SkipTCBInfo()
{
void Discreet3DSImporter::SkipTCBInfo() {
unsigned int flags = stream->GetI2();
if (!flags) {
@ -655,13 +612,11 @@ void Discreet3DSImporter::SkipTCBInfo()
// ------------------------------------------------------------------------------------------------
// Read hierarchy and keyframe info
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
{
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_TRACKOBJNAME:
// This is the name of the object to which the track applies. The chunk also
@ -672,7 +627,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
unsigned int cnt = 0;
const char *sz = (const char *)stream->GetPtr();
while (stream->GetI1())++cnt;
while (stream->GetI1())
++cnt;
std::string name = std::string(sz, cnt);
// Now find out whether we have this node already (target animation channels
@ -680,11 +636,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
D3DS::Node *pcNode = FindNode(mRootNode, name);
int instanceNumber = 1;
if ( pcNode)
{
if (pcNode) {
// if the source is not a CHUNK_TRACKINFO block it won't be an object instance
if (parent != Discreet3DS::CHUNK_TRACKINFO)
{
if (parent != Discreet3DS::CHUNK_TRACKINFO) {
mCurrentNode = pcNode;
break;
}
@ -708,14 +662,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// add to the parent of the last touched node
mCurrentNode->mParent->push_back(pcNode);
mLastNodeIndex++;
}
else if(hierarchy >= mLastNodeIndex) {
} else if (hierarchy >= mLastNodeIndex) {
// place it at the current position in the hierarchy
mCurrentNode->push_back(pcNode);
mLastNodeIndex = hierarchy;
}
else {
} else {
// need to go back to the specified position in the hierarchy.
InverseNodeSearch(pcNode, mCurrentNode);
mLastNodeIndex++;
@ -730,7 +682,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// This is the "real" name of a $$$DUMMY object
{
const char *sz = (const char *)stream->GetPtr();
while (stream->GetI1());
while (stream->GetI1())
;
// If object name is DUMMY, take this one instead
if (mCurrentNode->mName == "$$$DUMMY") {
@ -742,8 +695,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
case Discreet3DS::CHUNK_TRACKPIVOT:
if ( Discreet3DS::CHUNK_TRACKINFO != parent)
{
if (Discreet3DS::CHUNK_TRACKINFO != parent) {
ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
break;
}
@ -754,11 +706,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
mCurrentNode->vPivot.z = stream->GetF4();
break;
// ////////////////////////////////////////////////////////////////////
// POSITION KEYFRAME
case Discreet3DS::CHUNK_TRACKPOS:
{
case Discreet3DS::CHUNK_TRACKPOS: {
stream->IncPtr(10);
const unsigned int numFrames = stream->GetI4();
bool sortKeys = false;
@ -768,8 +718,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
std::vector<aiVectorKey> *l;
if (Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) {
l = &mCurrentNode->aTargetPositionKeys;
}
else l = & mCurrentNode->aPositionKeys;
} else
l = &mCurrentNode->aPositionKeys;
l->reserve(numFrames);
for (unsigned int i = 0; i < numFrames; ++i) {
@ -796,14 +746,14 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
if (sortKeys) {
std::stable_sort(l->begin(), l->end());
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
}}
}
}
break;
// ////////////////////////////////////////////////////////////////////
// CAMERA ROLL KEYFRAME
case Discreet3DS::CHUNK_TRACKROLL:
{
case Discreet3DS::CHUNK_TRACKROLL: {
// roll keys are accepted for cameras only
if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
@ -838,24 +788,19 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
if (sortKeys) {
std::stable_sort(l->begin(), l->end());
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiFloatKey>), l->end());
}}
break;
}
} break;
// ////////////////////////////////////////////////////////////////////
// CAMERA FOV KEYFRAME
case Discreet3DS::CHUNK_TRACKFOV:
{
case Discreet3DS::CHUNK_TRACKFOV: {
ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
"This is not supported");
}
break;
} break;
// ////////////////////////////////////////////////////////////////////
// ROTATION KEYFRAME
case Discreet3DS::CHUNK_TRACKROTATE:
{
case Discreet3DS::CHUNK_TRACKROTATE: {
stream->IncPtr(10);
const unsigned int numFrames = stream->GetI4();
@ -894,13 +839,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
if (sortKeys) {
std::stable_sort(l->begin(), l->end());
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiQuatKey>), l->end());
}}
break;
}
} break;
// ////////////////////////////////////////////////////////////////////
// SCALING KEYFRAME
case Discreet3DS::CHUNK_TRACKSCALE:
{
case Discreet3DS::CHUNK_TRACKSCALE: {
stream->IncPtr(10);
const unsigned int numFrames = stream->GetI2();
stream->IncPtr(2);
@ -937,8 +881,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
if (sortKeys) {
std::stable_sort(l->begin(), l->end());
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
}}
break;
}
} break;
};
ASSIMP_3DS_END_CHUNK();
@ -946,18 +890,15 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// ------------------------------------------------------------------------------------------------
// Read a face chunk - it contains smoothing groups and material assignments
void Discreet3DSImporter::ParseFaceChunk()
{
void Discreet3DSImporter::ParseFaceChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// Get the mesh we're currently working on
D3DS::Mesh &mMesh = mScene->mMeshes.back();
// Get chunk type
switch (chunk.Flag)
{
case Discreet3DS::CHUNK_SMOOLIST:
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_SMOOLIST: {
// This is the list of smoothing groups - a bitfield for every face.
// Up to 32 smoothing groups assigned to a single face.
unsigned int num = chunkSize / 4, m = 0;
@ -967,14 +908,14 @@ void Discreet3DSImporter::ParseFaceChunk()
for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num; ++i, ++m) {
// nth bit is set for nth smoothing group
(*i).iSmoothGroup = stream->GetI4();
}}
break;
}
} break;
case Discreet3DS::CHUNK_FACEMAT:
{
case Discreet3DS::CHUNK_FACEMAT: {
// at fist an asciiz with the material name
const char *sz = (const char *)stream->GetPtr();
while (stream->GetI1());
while (stream->GetI1())
;
// find the index of the material
unsigned int idx = 0xcdcdcdcd, cnt = 0;
@ -997,28 +938,25 @@ void Discreet3DSImporter::ParseFaceChunk()
// check range
if (fidx >= mMesh.mFaceMaterials.size()) {
ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
} else
mMesh.mFaceMaterials[fidx] = idx;
}
else mMesh.mFaceMaterials[fidx] = idx;
}}
break;
} break;
};
ASSIMP_3DS_END_CHUNK();
}
// ------------------------------------------------------------------------------------------------
// Read a mesh chunk. Here's the actual mesh data
void Discreet3DSImporter::ParseMeshChunk()
{
void Discreet3DSImporter::ParseMeshChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
// Get the mesh we're currently working on
D3DS::Mesh &mMesh = mScene->mMeshes.back();
// get chunk type
switch (chunk.Flag)
{
case Discreet3DS::CHUNK_VERTLIST:
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_VERTLIST: {
// This is the list of all vertices in the current mesh
int num = (int)(uint16_t)stream->GetI2();
mMesh.mPositions.reserve(num);
@ -1028,10 +966,9 @@ void Discreet3DSImporter::ParseMeshChunk()
v.y = stream->GetF4();
v.z = stream->GetF4();
mMesh.mPositions.push_back(v);
}}
break;
case Discreet3DS::CHUNK_TRMATRIX:
{
}
} break;
case Discreet3DS::CHUNK_TRMATRIX: {
// This is the RLEATIVE transformation matrix of the current mesh. Vertices are
// pretransformed by this matrix wonder.
mMesh.mMat.a1 = stream->GetF4();
@ -1046,11 +983,9 @@ void Discreet3DSImporter::ParseMeshChunk()
mMesh.mMat.a4 = stream->GetF4();
mMesh.mMat.b4 = stream->GetF4();
mMesh.mMat.c4 = stream->GetF4();
}
break;
} break;
case Discreet3DS::CHUNK_MAPLIST:
{
case Discreet3DS::CHUNK_MAPLIST: {
// This is the list of all UV coords in the current mesh
int num = (int)(uint16_t)stream->GetI2();
mMesh.mTexCoords.reserve(num);
@ -1059,11 +994,10 @@ void Discreet3DSImporter::ParseMeshChunk()
v.x = stream->GetF4();
v.y = stream->GetF4();
mMesh.mTexCoords.push_back(v);
}}
break;
}
} break;
case Discreet3DS::CHUNK_FACELIST:
{
case Discreet3DS::CHUNK_FACELIST: {
// This is the list of all faces in the current mesh
int num = (int)(uint16_t)stream->GetI2();
mMesh.mFaces.reserve(num);
@ -1084,22 +1018,19 @@ void Discreet3DSImporter::ParseMeshChunk()
mMesh.mFaceMaterials.resize(mMesh.mFaces.size(), 0xcdcdcdcd);
// Larger 3DS files could have multiple FACE chunks here
chunkSize = stream->GetRemainingSizeToLimit();
chunkSize = (int)stream->GetRemainingSizeToLimit();
if (chunkSize > (int)sizeof(Discreet3DS::Chunk))
ParseFaceChunk();
}
break;
} break;
};
ASSIMP_3DS_END_CHUNK();
}
// ------------------------------------------------------------------------------------------------
// Read a 3DS material chunk
void Discreet3DSImporter::ParseMaterialChunk()
{
void Discreet3DSImporter::ParseMaterialChunk() {
ASSIMP_3DS_BEGIN_CHUNK();
switch (chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_MAT_MATNAME:
{
@ -1112,13 +1043,11 @@ void Discreet3DSImporter::ParseMaterialChunk()
if (!cnt) {
// This may not be, we use the default name instead
ASSIMP_LOG_ERROR("3DS: Empty material name");
}
else mScene->mMaterials.back().mName = std::string(sz,cnt);
}
break;
} else
mScene->mMaterials.back().mName = std::string(sz, cnt);
} break;
case Discreet3DS::CHUNK_MAT_DIFFUSE:
{
case Discreet3DS::CHUNK_MAT_DIFFUSE: {
// This is the diffuse material color
aiColor3D *pc = &mScene->mMaterials.back().mDiffuse;
ParseColorChunk(pc);
@ -1126,11 +1055,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
// color chunk is invalid. Simply ignore it
ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
pc->r = pc->g = pc->b = 1.0f;
}}
break;
}
} break;
case Discreet3DS::CHUNK_MAT_SPECULAR:
{
case Discreet3DS::CHUNK_MAT_SPECULAR: {
// This is the specular material color
aiColor3D *pc = &mScene->mMaterials.back().mSpecular;
ParseColorChunk(pc);
@ -1138,11 +1066,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
// color chunk is invalid. Simply ignore it
ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
pc->r = pc->g = pc->b = 1.0f;
}}
break;
}
} break;
case Discreet3DS::CHUNK_MAT_AMBIENT:
{
case Discreet3DS::CHUNK_MAT_AMBIENT: {
// This is the ambient material color
aiColor3D *pc = &mScene->mMaterials.back().mAmbient;
ParseColorChunk(pc);
@ -1150,11 +1077,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
// color chunk is invalid. Simply ignore it
ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
pc->r = pc->g = pc->b = 0.0f;
}}
break;
}
} break;
case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
{
case Discreet3DS::CHUNK_MAT_SELF_ILLUM: {
// This is the emissive material color
aiColor3D *pc = &mScene->mMaterials.back().mEmissive;
ParseColorChunk(pc);
@ -1162,11 +1088,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
// color chunk is invalid. Simply ignore it
ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
pc->r = pc->g = pc->b = 0.0f;
}}
break;
}
} break;
case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
{
case Discreet3DS::CHUNK_MAT_TRANSPARENCY: {
// This is the material's transparency
ai_real *pcf = &mScene->mMaterials.back().mTransparency;
*pcf = ParsePercentageChunk();
@ -1176,8 +1101,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
*pcf = ai_real(1.0);
else
*pcf = ai_real(1.0) - *pcf * (ai_real)0xFFFF / ai_real(100.0);
}
break;
} break;
case Discreet3DS::CHUNK_MAT_SHADING:
// This is the material shading mode
@ -1189,37 +1113,32 @@ void Discreet3DSImporter::ParseMaterialChunk()
mScene->mMaterials.back().mTwoSided = true;
break;
case Discreet3DS::CHUNK_MAT_SHININESS:
{ // This is the shininess of the material
case Discreet3DS::CHUNK_MAT_SHININESS: { // This is the shininess of the material
ai_real *pcf = &mScene->mMaterials.back().mSpecularExponent;
*pcf = ParsePercentageChunk();
if (is_qnan(*pcf))
*pcf = 0.0;
else *pcf *= (ai_real)0xFFFF;
}
break;
else
*pcf *= (ai_real)0xFFFF;
} break;
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
{ // This is the shininess strength of the material
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: { // This is the shininess strength of the material
ai_real *pcf = &mScene->mMaterials.back().mShininessStrength;
*pcf = ParsePercentageChunk();
if (is_qnan(*pcf))
*pcf = ai_real(0.0);
else
*pcf *= (ai_real)0xffff / ai_real(100.0);
}
break;
} break;
case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
{ // This is the self illumination strength of the material
case Discreet3DS::CHUNK_MAT_SELF_ILPCT: { // This is the self illumination strength of the material
ai_real f = ParsePercentageChunk();
if (is_qnan(f))
f = ai_real(0.0);
else
f *= (ai_real)0xFFFF / ai_real(100.0);
mScene->mMaterials.back().mEmissive = aiColor3D(f, f, f);
}
break;
} break;
// Parse texture chunks
case Discreet3DS::CHUNK_MAT_TEXTURE:
@ -1255,24 +1174,19 @@ void Discreet3DSImporter::ParseMaterialChunk()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
{
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture *pcOut) {
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
switch (chunk.Flag)
{
case Discreet3DS::CHUNK_MAPFILE:
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_MAPFILE: {
// The material name string is already zero-terminated, but we need to be sure ...
const char *sz = (const char *)stream->GetPtr();
unsigned int cnt = 0;
while (stream->GetI1())
++cnt;
pcOut->mMapName = std::string(sz, cnt);
}
break;
} break;
case Discreet3DS::CHUNK_PERCENTD:
// Manually parse the blend factor
@ -1292,8 +1206,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
case Discreet3DS::CHUNK_MAT_MAP_USCALE:
// Texture coordinate scaling in the U direction
pcOut->mScaleU = stream->GetF4();
if (0.0f == pcOut->mScaleU)
{
if (0.0f == pcOut->mScaleU) {
ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1.");
pcOut->mScaleU = 1.0f;
}
@ -1301,8 +1214,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
// Texture coordinate scaling in the V direction
pcOut->mScaleV = stream->GetF4();
if (0.0f == pcOut->mScaleV)
{
if (0.0f == pcOut->mScaleV) {
ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1.");
pcOut->mScaleV = 1.0f;
}
@ -1323,8 +1235,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
pcOut->mRotation = -AI_DEG_TO_RAD(stream->GetF4());
break;
case Discreet3DS::CHUNK_MAT_MAP_TILING:
{
case Discreet3DS::CHUNK_MAT_MAP_TILING: {
const uint16_t iFlags = stream->GetI2();
// Get the mapping mode (for both axes)
@ -1335,9 +1246,9 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
pcOut->mMapMode = aiTextureMapMode_Decal;
// wrapping in all remaining cases
else pcOut->mMapMode = aiTextureMapMode_Wrap;
}
break;
else
pcOut->mMapMode = aiTextureMapMode_Wrap;
} break;
};
ASSIMP_3DS_END_CHUNK();
@ -1360,9 +1271,8 @@ ai_real Discreet3DSImporter::ParsePercentageChunk() {
// ------------------------------------------------------------------------------------------------
// Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
{
ai_assert(out != NULL);
void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
ai_assert(out != nullptr);
// error return value
const ai_real qnan = get_qnan();
@ -1375,8 +1285,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
bool bGamma = false;
// Get the type of the chunk
switch(chunk.Flag)
{
switch (chunk.Flag) {
case Discreet3DS::CHUNK_LINRGBF:
bGamma = true;
@ -1392,8 +1301,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
case Discreet3DS::CHUNK_LINRGBB:
bGamma = true;
case Discreet3DS::CHUNK_RGBB:
{
case Discreet3DS::CHUNK_RGBB: {
if (sizeof(char) * 3 > diff) {
*out = clrError;
return;
@ -1402,8 +1310,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
out->r = (ai_real)(uint8_t)stream->GetI1() * invVal;
out->g = (ai_real)(uint8_t)stream->GetI1() * invVal;
out->b = (ai_real)(uint8_t)stream->GetI1() * invVal;
}
break;
} break;
// Percentage chunks are accepted, too.
case Discreet3DS::CHUNK_PERCENTF:

View File

@ -65,15 +65,11 @@ using namespace D3DS;
// ---------------------------------------------------------------------------------
/** Importer class for 3D Studio r3 and r4 3DS files
*/
class Discreet3DSImporter : public BaseImporter
{
class Discreet3DSImporter : public BaseImporter {
public:
Discreet3DSImporter();
~Discreet3DSImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -56,6 +55,8 @@ namespace XmlTag {
static const std::string resources = "resources";
static const std::string object = "object";
static const std::string mesh = "mesh";
static const std::string components = "components";
static const std::string component = "component";
static const std::string vertices = "vertices";
static const std::string vertex = "vertex";
static const std::string triangles = "triangles";
@ -68,6 +69,7 @@ namespace XmlTag {
static const std::string v3 = "v3";
static const std::string id = "id";
static const std::string pid = "pid";
static const std::string pindex = "pindex";
static const std::string p1 = "p1";
static const std::string name = "name";
static const std::string type = "type";

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -44,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFExporter.h"
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/StringUtils.h>
#include <assimp/Exceptional.h>
#include <assimp/StringUtils.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
@ -83,15 +82,8 @@ void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pSce
namespace D3MF {
D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
: mArchiveName( pFile )
, m_zipArchive( nullptr )
, mScene( pScene )
, mModelOutput()
, mRelOutput()
, mContentOutput()
, mBuildItems()
, mRelations() {
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
// empty
}
@ -145,7 +137,7 @@ bool D3MFExporter::exportContentTypes() {
mContentOutput << std::endl;
mContentOutput << "</Types>";
mContentOutput << std::endl;
exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE);
return true;
}
@ -170,7 +162,7 @@ bool D3MFExporter::exportRelations() {
mRelOutput << "</Relationships>";
mRelOutput << std::endl;
writeRelInfoToFile( "_rels", ".rels" );
zipRelInfo("_rels", ".rels");
mRelOutput.flush();
return true;
@ -192,7 +184,6 @@ bool D3MFExporter::export3DModel() {
writeObjects();
mModelOutput << "</" << XmlTag::resources << ">";
mModelOutput << std::endl;
writeBuild();
@ -205,7 +196,7 @@ bool D3MFExporter::export3DModel() {
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
mRelations.push_back(info);
writeModelToArchive( "3D", "3DModel.model" );
zipModel("3D", "3DModel.model");
mModelOutput.flush();
return true;
@ -254,8 +245,18 @@ void D3MFExporter::writeBaseMaterials() {
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
hexDiffuseColor.clear();
tmp.clear();
hexDiffuseColor = "#";
// rgbs %
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
hexDiffuseColor = Rgba2Hex(
(int)((ai_real)color.r) * 255,
(int)((ai_real)color.g) * 255,
(int)((ai_real)color.b) * 255,
(int)((ai_real)color.a) * 255,
true);
} else {
hexDiffuseColor = "#";
tmp = DecimalToHexa((ai_real)color.r);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.g);
@ -264,6 +265,7 @@ void D3MFExporter::writeBaseMaterials() {
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.a);
hexDiffuseColor += tmp;
}
} else {
hexDiffuseColor = "#FFFFFFFF";
}
@ -284,7 +286,7 @@ void D3MFExporter::writeObjects() {
if (nullptr == currentNode) {
continue;
}
mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
mModelOutput << std::endl;
for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
@ -348,53 +350,37 @@ void D3MFExporter::writeBuild() {
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
for (size_t i = 0; i < mBuildItems.size(); ++i) {
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
mModelOutput << std::endl;
}
mModelOutput << "</" << XmlTag::build << ">";
mModelOutput << std::endl;
}
void D3MFExporter::exportContentTyp( const std::string &filename ) {
if ( nullptr == m_zipArchive ) {
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
}
const std::string entry = filename;
zip_entry_open( m_zipArchive, entry.c_str() );
const std::string &exportTxt( mContentOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
zip_entry_close( m_zipArchive );
void D3MFExporter::zipContentType(const std::string &filename) {
addFileInZip(filename, mContentOutput.str());
}
void D3MFExporter::writeModelToArchive( const std::string &folder, const std::string &modelName ) {
if ( nullptr == m_zipArchive ) {
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
}
void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) {
const std::string entry = folder + "/" + modelName;
zip_entry_open( m_zipArchive, entry.c_str() );
const std::string &exportTxt( mModelOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
zip_entry_close( m_zipArchive );
addFileInZip(entry, mModelOutput.str());
}
void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) {
void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) {
const std::string entry = folder + "/" + relName;
addFileInZip(entry, mRelOutput.str());
}
void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) {
if (nullptr == m_zipArchive) {
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
}
const std::string entry = folder + "/" + relName;
zip_entry_open(m_zipArchive, entry.c_str());
const std::string &exportTxt( mRelOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
zip_entry_write(m_zipArchive, content.c_str(), content.size());
zip_entry_close(m_zipArchive);
}
} // Namespace D3MF
} // Namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -83,9 +82,12 @@ protected:
void writeVertex( const aiVector3D &pos );
void writeFaces( aiMesh *mesh, unsigned int matIdx );
void writeBuild();
void exportContentTyp( const std::string &filename );
void writeModelToArchive( const std::string &folder, const std::string &modelName );
void writeRelInfoToFile( const std::string &folder, const std::string &relName );
// Zip the data
void zipContentType( const std::string &filename );
void zipModel( const std::string &folder, const std::string &modelName );
void zipRelInfo( const std::string &folder, const std::string &relName );
void addFileInZip( const std::string &entry, const std::string &content );
private:
std::string mArchiveName;

View File

@ -0,0 +1,626 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#include "D3MFImporter.h"
#include <assimp/StringComparison.h>
#include <assimp/StringUtils.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h>
#include <iomanip>
namespace Assimp {
namespace D3MF {
enum class ResourceType {
RT_Object,
RT_BaseMaterials,
RT_Unknown
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
class Resource
{
public:
Resource(int id) :
mId(id) {}
virtual ~Resource() {}
int mId;
virtual ResourceType getType() {
return ResourceType::RT_Unknown;
}
};
class BaseMaterials : public Resource {
public:
BaseMaterials(int id) :
Resource(id),
mMaterials(),
mMaterialIndex() {}
std::vector<aiMaterial *> mMaterials;
std::vector<unsigned int> mMaterialIndex;
virtual ResourceType getType() {
return ResourceType::RT_BaseMaterials;
}
};
struct Component {
int mObjectId;
aiMatrix4x4 mTransformation;
};
class Object : public Resource {
public:
std::vector<aiMesh*> mMeshes;
std::vector<unsigned int> mMeshIndex;
std::vector<Component> mComponents;
std::string mName;
Object(int id) :
Resource(id),
mName (std::string("Object_") + to_string(id)){}
virtual ResourceType getType() {
return ResourceType::RT_Object;
}
};
class XmlSerializer {
public:
XmlSerializer(XmlParser *xmlParser) :
mResourcesDictionnary(),
mMaterialCount(0),
mMeshCount(0),
mXmlParser(xmlParser) {
// empty
}
~XmlSerializer() {
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
delete it->second;
}
}
void ImportXml(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mRootNode = new aiNode("3MF");
XmlNode node = mXmlParser->getRootNode().child("model");
if (node.empty()) {
return;
}
XmlNode resNode = node.child("resources");
for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentNodeName = currentNode.name();
if (currentNodeName == D3MF::XmlTag::object) {
ReadObject(currentNode);;
} else if (currentNodeName == D3MF::XmlTag::basematerials) {
ReadBaseMaterials(currentNode);
} else if (currentNodeName == D3MF::XmlTag::meta) {
ReadMetadata(currentNode);
}
}
XmlNode buildNode = node.child("build");
for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentNodeName = currentNode.name();
if (currentNodeName == D3MF::XmlTag::item) {
int objectId = -1;
std::string transformationMatrixStr;
aiMatrix4x4 transformationMatrix;
getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId);
bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr);
auto it = mResourcesDictionnary.find(objectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it->second);
if (hasTransform) {
transformationMatrix = parseTransformMatrix(transformationMatrixStr);
}
addObjectToNode(scene->mRootNode, obj, transformationMatrix);
}
}
}
// import the metadata
if (!mMetaData.empty()) {
const size_t numMeta(mMetaData.size());
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
for (size_t i = 0; i < numMeta; ++i) {
aiString val(mMetaData[i].value);
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>(mMeshCount);
if (scene->mNumMeshes != 0) {
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
if (it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object*>(it->second);
for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
}
}
}
}
// import the materials
scene->mNumMaterials = static_cast<unsigned int>(mMaterialCount);
if (scene->mNumMaterials != 0) {
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) {
scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i];
}
}
}
}
}
private:
void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) {
aiNode *sceneNode = new aiNode(obj->mName);
sceneNode->mNumMeshes = static_cast<unsigned int>(obj->mMeshes.size());
sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes);
sceneNode->mTransformation = nodeTransform;
parent->addChildren(1, &sceneNode);
for (size_t i = 0; i < obj->mComponents.size(); ++i) {
Component c = obj->mComponents[i];
auto it = mResourcesDictionnary.find(c.mObjectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
addObjectToNode(sceneNode, static_cast<Object*>(it->second), c.mTransformation);
}
}
}
bool getNodeAttribute(const XmlNode& node, const std::string& attribute, std::string& value) {
pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str());
if (!objectAttribute.empty()) {
value = objectAttribute.as_string();
return true;
} else {
return false;
}
}
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
std::string strValue;
bool ret = getNodeAttribute(node, attribute, strValue);
if (ret) {
value = std::atoi(strValue.c_str());
return true;
} else {
return false;
}
}
aiMatrix4x4 parseTransformMatrix(std::string matrixStr) {
// split the string
std::vector<float> numbers;
std::string currentNumber;
for (size_t i = 0; i < matrixStr.size(); ++i) {
const char c = matrixStr[i];
if (c == ' ') {
if (currentNumber.size() > 0) {
float f = std::stof(currentNumber);
numbers.push_back(f);
currentNumber.clear();
}
} else {
currentNumber.push_back(c);
}
}
if (currentNumber.size() > 0) {
float f = std::stof(currentNumber);
numbers.push_back(f);
}
aiMatrix4x4 transformMatrix;
transformMatrix.a1 = numbers[0];
transformMatrix.b1 = numbers[1];
transformMatrix.c1 = numbers[2];
transformMatrix.d1 = 0;
transformMatrix.a2 = numbers[3];
transformMatrix.b2 = numbers[4];
transformMatrix.c2 = numbers[5];
transformMatrix.d2 = 0;
transformMatrix.a3 = numbers[6];
transformMatrix.b3 = numbers[7];
transformMatrix.c3 = numbers[8];
transformMatrix.d3 = 0;
transformMatrix.a4 = numbers[9];
transformMatrix.b4 = numbers[10];
transformMatrix.c4 = numbers[11];
transformMatrix.d4 = 1;
return transformMatrix;
}
void ReadObject(XmlNode &node) {
int id = -1, pid = -1, pindex = -1;
bool hasId = getNodeAttribute(node, D3MF::XmlTag::id, id);
//bool hasType = getNodeAttribute(node, D3MF::XmlTag::type, type); not used currently
bool hasPid = getNodeAttribute(node, D3MF::XmlTag::pid, pid);
bool hasPindex = getNodeAttribute(node, D3MF::XmlTag::pindex, pindex);
std::string idStr = to_string(id);
if (!hasId) {
return;
}
Object *obj = new Object(id);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh(currentNode);
mesh->mName.Set(idStr);
if (hasPid) {
auto it = mResourcesDictionnary.find(pid);
if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
}
}
obj->mMeshes.push_back(mesh);
obj->mMeshIndex.push_back(mMeshCount);
mMeshCount++;
} else if (currentName == D3MF::XmlTag::components) {
for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) {
if (currentSubNode.name() == D3MF::XmlTag::component) {
int objectId = -1;
std::string componentTransformStr;
aiMatrix4x4 componentTransform;
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) {
componentTransform = parseTransformMatrix(componentTransformStr);
}
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId))
obj->mComponents.push_back({ objectId, componentTransform });
}
}
}
}
mResourcesDictionnary.insert(std::make_pair(id, obj));
}
aiMesh *ReadMesh(XmlNode &node) {
aiMesh *mesh = new aiMesh();
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == D3MF::XmlTag::vertices) {
ImportVertices(currentNode, mesh);
} else if (currentName == D3MF::XmlTag::triangles) {
ImportTriangles(currentNode, mesh);
}
}
return mesh;
}
void ReadMetadata(XmlNode &node) {
pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str());
const std::string name = attribute.as_string();
const std::string value = node.value();
if (name.empty()) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back(entry);
}
void ImportVertices(XmlNode &node, aiMesh *mesh) {
std::vector<aiVector3D> vertices;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode));
}
}
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr);
vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr);
vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr);
return vertex;
}
void ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == D3MF::XmlTag::triangle) {
aiFace face = ReadTriangle(currentNode);
faces.push_back(face);
int pid, p1;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
if (hasPid && hasP1) {
auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end())
{
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
}
// TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material
}
}
}
}
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
aiFace ReadTriangle(XmlNode &node) {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string()));
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(node.attribute(D3MF::XmlTag::v3.c_str()).as_string()));
return face;
}
void ReadBaseMaterials(XmlNode &node) {
int id = -1;
if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) {
BaseMaterials* baseMaterials = new BaseMaterials(id);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling())
{
if (currentNode.name() == D3MF::XmlTag::basematerials_base) {
baseMaterials->mMaterialIndex.push_back(mMaterialCount);
baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
mMaterialCount++;
}
}
mResourcesDictionnary.insert(std::make_pair(id, baseMaterials));
}
}
bool parseColor(const char *color, aiColor4D &diffuse) {
if (nullptr == color) {
return false;
}
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
const size_t len(strlen(color));
if (9 != len && 7 != len) {
return false;
}
const char *buf(color);
if ('#' != buf[0]) {
return false;
}
char r[3] = { buf[1], buf[2], '\0' };
diffuse.r = static_cast<ai_real>(strtol(r, nullptr, 16)) / ai_real(255.0);
char g[3] = { buf[3], buf[4], '\0' };
diffuse.g = static_cast<ai_real>(strtol(g, nullptr, 16)) / ai_real(255.0);
char b[3] = { buf[5], buf[6], '\0' };
diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
if (7 == len)
return true;
char a[3] = { buf[7], buf[8], '\0' };
diffuse.a = static_cast<ai_real>(strtol(a, nullptr, 16)) / ai_real(255.0);
return true;
}
void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string();
aiColor4D diffuse;
if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
}
}
aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) {
aiMaterial *material = new aiMaterial();
material->mNumProperties = 0;
std::string name;
bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
std::string stdMaterialName;
std::string strId(to_string(basematerialsId));
stdMaterialName += "id";
stdMaterialName += strId;
stdMaterialName += "_";
if (hasName) {
stdMaterialName += std::string(name);
} else {
stdMaterialName += "basemat_";
stdMaterialName += to_string(mMaterialCount - basematerialsId);
}
aiString assimpMaterialName(stdMaterialName);
material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME);
assignDiffuseColor(node, material);
return material;
}
private:
struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::map<unsigned int, Resource*> mResourcesDictionnary;
unsigned int mMaterialCount, mMeshCount;
XmlParser *mXmlParser;
};
} //namespace D3MF
static const aiImporterDesc desc = {
"3mf Importer",
"",
"",
"http://3mf.io/",
aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
0,
0,
0,
0,
"3mf"
};
D3MFImporter::D3MFImporter() :
BaseImporter() {
// empty
}
D3MFImporter::~D3MFImporter() {
// empty
}
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension(GetExtension(filename));
if (extension == desc.mFileExtensions) {
return true;
} else if (!extension.length() || checkSig) {
if (nullptr == pIOHandler) {
return false;
}
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false;
}
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
return opcPackage.validate();
}
return false;
}
void D3MFImporter::SetupProperties(const Importer * /*pImp*/) {
// empty
}
const aiImporterDesc *D3MFImporter::GetInfo() const {
return &desc;
}
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
XmlParser xmlParser;
if (xmlParser.parse(opcPackage.RootStream())) {
D3MF::XmlSerializer xmlSerializer(&xmlParser);
xmlSerializer.ImportXml(pScene);
}
}
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_3MF_IMPORTER

View File

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

View File

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

View File

@ -192,7 +192,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
objects.push_back(Object());
Object &obj = objects.back();
aiLight *light = NULL;
aiLight *light = nullptr;
if (!ASSIMP_strincmp(buffer, "light", 5)) {
// This is a light source. Add it to the list
mLights->push_back(light = new aiLight());
@ -207,7 +207,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
obj.name = std::string(light->mName.data);
ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
obj.type = Object::Light;
} else if (!ASSIMP_strincmp(buffer, "group", 5)) {
obj.type = Object::Group;
@ -294,7 +294,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
// example writes no surf chunks
if (!Q3DWorkAround) {
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
}
--buffer; // make sure the line is processed a second time
// break; --- see fix notes above
@ -471,26 +471,33 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++node->mNumMeshes;
}
switch ((*it).flags & 0xf) {
switch ((*it).GetType()) {
// closed line
case 0x1:
case Surface::ClosedLine:
needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
break;
// unclosed line
case 0x2:
case Surface::OpenLine:
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
break;
// 0 == polygon, else unknown
default:
if ((*it).flags & 0xf) {
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(0xf);
}
// triangle strip
case Surface::TriangleStrip:
needMat[idx].first += (unsigned int)(*it).entries.size() - 2;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3;
break;
default:
// Coerce unknowns to a polygon and warn
ASSIMP_LOG_WARN_F("AC3D: The type flag of a surface is unknown: ", (*it).flags);
(*it).flags &= ~(Surface::Mask);
// fallthrough
// polygon
case Surface::Polygon:
// the number of faces increments by one, the number
// of vertices by surface.numref.
needMat[idx].first++;
@ -535,7 +542,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// allocate UV coordinates, but only if the texture name for the
// surface is not empty
aiVector3D *uv = NULL;
aiVector3D *uv = nullptr;
if (object.texture.length()) {
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2;
@ -546,8 +553,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
const Surface &src = *it;
// closed polygon
unsigned int type = (*it).flags & 0xf;
if (!type) {
uint8_t type = (*it).GetType();
if (type == Surface::Polygon) {
aiFace &face = *faces++;
face.mNumIndices = (unsigned int)src.entries.size();
if (0 != face.mNumIndices) {
@ -570,13 +577,71 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
}
}
}
} else if (type == Surface::TriangleStrip) {
for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
const Surface::SurfaceEntry &entry1 = src.entries[i];
const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
// skip degenerate triangles
if (object.vertices[entry1.first] == object.vertices[entry2.first] ||
object.vertices[entry1.first] == object.vertices[entry3.first] ||
object.vertices[entry2.first] == object.vertices[entry3.first]) {
mesh->mNumFaces--;
mesh->mNumVertices -= 3;
continue;
}
aiFace &face = *faces++;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = cur++;
face.mIndices[1] = cur++;
face.mIndices[2] = cur++;
if (!(i & 1)) {
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
} else {
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
}
if (static_cast<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 {
it2 = (*it).entries.begin();
// either a closed or an unclosed line
unsigned int tmp = (unsigned int)(*it).entries.size();
if (0x2 == type) --tmp;
if (Surface::OpenLine == type) --tmp;
for (unsigned int m = 0; m < tmp; ++m) {
aiFace &face = *faces++;
@ -599,7 +664,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++uv;
}
if (0x1 == type && tmp - 1 == m) {
if (Surface::ClosedLine == type && tmp - 1 == m) {
// if this is a closed line repeat its beginning now
it2 = (*it).entries.begin();
} else
@ -627,7 +692,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name);
std::vector<aiMesh *> cpy(meshes.size() - oldm, NULL);
std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
@ -697,7 +762,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
// Check whether we can read from the file
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

View File

@ -56,27 +56,23 @@ struct aiMesh;
struct aiMaterial;
struct aiLight;
namespace Assimp {
// ---------------------------------------------------------------------------
/** AC3D (*.ac) importer class
*/
class AC3DImporter : public BaseImporter
{
class AC3DImporter : public BaseImporter {
public:
AC3DImporter();
~AC3DImporter();
// Represents an AC3D material
struct Material
{
Material()
: rgb (0.6f,0.6f,0.6f)
, spec (1.f,1.f,1.f)
, shin (0.f)
, trans (0.f)
{}
struct Material {
Material() :
rgb(0.6f, 0.6f, 0.6f),
spec(1.f, 1.f, 1.f),
shin(0.f),
trans(0.f) {}
// base color of the material
aiColor3D rgb;
@ -101,41 +97,48 @@ public:
};
// Represents an AC3D surface
struct Surface
{
Surface()
: mat (0)
, flags (0)
{}
struct Surface {
Surface() :
mat(0),
flags(0) {}
unsigned int mat, flags;
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
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
struct Object
{
Object()
: type (World)
, name( "" )
, children()
, texture( "" )
, texRepeat( 1.f, 1.f )
, texOffset( 0.0f, 0.0f )
, rotation()
, translation()
, vertices()
, surfaces()
, numRefs (0)
, subDiv (0)
, crease()
{}
struct Object {
Object() :
type(World),
name(""),
children(),
texture(""),
texRepeat(1.f, 1.f),
texOffset(0.0f, 0.0f),
rotation(),
translation(),
vertices(),
surfaces(),
numRefs(0),
subDiv(0),
crease() {}
// Type description
enum Type
{
enum Type {
World = 0x0,
Poly = 0x1,
Group = 0x2,
@ -177,9 +180,7 @@ public:
float crease;
};
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
@ -188,7 +189,6 @@ public:
bool checkSig) const;
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details */
@ -207,7 +207,6 @@ protected:
void SetupProperties(const Importer *pImp);
private:
// -------------------------------------------------------------------
/** Get the next line from the file.
* @return false if the end of the file was reached*/
@ -231,7 +230,7 @@ private:
std::vector<aiMesh *> &meshes,
std::vector<aiMaterial *> &outMaterials,
const std::vector<Material> &materials,
aiNode* parent = NULL);
aiNode *parent = nullptr);
// -------------------------------------------------------------------
/** Convert a material

View File

@ -0,0 +1,541 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter.cpp
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
// Header files, Assimp.
#include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
#include <assimp/DefaultIOSystem.h>
#include <assimp/fast_atof.h>
// Header files, stdlib.
#include <memory>
namespace Assimp {
const aiImporterDesc AMFImporter::Description = {
"Additive manufacturing file format(AMF) Importer",
"smalcom",
"",
"See documentation in source code. Chapter: Limitations.",
aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
0,
0,
0,
0,
"amf"
};
void AMFImporter::Clear() {
mNodeElement_Cur = nullptr;
mUnit.clear();
mMaterial_Converted.clear();
mTexture_Converted.clear();
// Delete all elements
if (!mNodeElement_List.empty()) {
for (AMFNodeElementBase *ne : mNodeElement_List) {
delete ne;
}
mNodeElement_List.clear();
}
}
AMFImporter::AMFImporter() AI_NO_EXCEPT :
mNodeElement_Cur(nullptr),
mXmlParser(nullptr),
mUnit(),
mVersion(),
mMaterial_Converted(),
mTexture_Converted() {
// empty
}
AMFImporter::~AMFImporter() {
delete mXmlParser;
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
Clear();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const {
for (AMFNodeElementBase *ne : mNodeElement_List) {
if ((ne->ID == pID) && (ne->Type == pType)) {
if (pNodeElement != nullptr) {
*pNodeElement = ne;
}
return true;
}
} // for(CAMFImporter_NodeElement* ne: mNodeElement_List)
return false;
}
bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const {
aiString node_name(pID.c_str());
for (aiNode *node : nodeArray) {
if (node->mName == node_name) {
if (pNode != nullptr) {
*pNode = node;
}
return true;
}
} // for(aiNode* node: pNodeList)
return false;
}
bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const {
for (const SPP_Material &mat : mMaterial_Converted) {
if (mat.ID == pID) {
if (pConvertedMaterial != nullptr) {
*pConvertedMaterial = &mat;
}
return true;
}
} // for(const SPP_Material& mat: mMaterial_Converted)
return false;
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: throw set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::Throw_CloseNotFound(const std::string &nodeName) {
throw DeadlyImportError("Close tag for node <" + nodeName + "> not found. Seems file is corrupt.");
}
void AMFImporter::Throw_IncorrectAttr(const std::string &nodeName, const std::string &attrName) {
throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + attrName + "\".");
}
void AMFImporter::Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &attrName) {
throw DeadlyImportError("Attribute \"" + attrName + "\" in node <" + nodeName + "> has incorrect value.");
}
void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) {
throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription);
}
void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
throw DeadlyImportError("Not found node with name \"", pID, "\".");
}
/*********************************************************************************************************************************************/
/************************************************************* Functions: XML set ************************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) {
if (node.children().begin() == node.children().end()) {
throw DeadlyImportError(std::string("Node <") + node.name() + "> must have children.");
}
}
bool AMFImporter::XML_SearchNode(const std::string &nodeName) {
return nullptr != mXmlParser->findNode(nodeName);
}
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
size_t instr_len;
pOutString.clear();
instr_len = strlen(pInStr);
if (!instr_len) return;
pOutString.reserve(instr_len * 3 / 2);
// check and correct floats in format ".x". Must be "x.y".
if (pInStr[0] == '.') pOutString.push_back('0');
pOutString.push_back(pInStr[0]);
for (size_t ci = 1; ci < instr_len; ci++) {
if ((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) {
pOutString.push_back('0');
pOutString.push_back('.');
} else {
pOutString.push_back(pInStr[ci]);
}
}
}
static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) {
return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
}
void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const {
// With help from
// René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html
const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uint8_t tidx = 0;
uint8_t arr4[4], arr3[3];
// check input data
if (pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
// prepare output place
pOutputData.clear();
pOutputData.reserve(pInputBase64.size() / 4 * 3);
for (size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--) {
if (ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) {
arr4[tidx++] = pInputBase64[in_idx++];
if (tidx == 4) {
for (tidx = 0; tidx < 4; tidx++)
arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]);
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for (tidx = 0; tidx < 3; tidx++)
pOutputData.push_back(arr3[tidx]);
tidx = 0;
} // if(tidx == 4)
} // if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
else {
in_idx++;
} // if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else
}
if (tidx) {
for (uint8_t i = tidx; i < 4; i++)
arr4[i] = 0;
for (uint8_t i = 0; i < 4; i++)
arr4[i] = (uint8_t)(base64_chars.find(arr4[i]));
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for (uint8_t i = 0; i < (tidx - 1); i++)
pOutputData.push_back(arr3[i]);
}
}
void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AMF file ", pFile, ".");
}
mXmlParser = new XmlParser();
if (!mXmlParser->parse(file.get())) {
delete mXmlParser;
throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
}
// Start reading, search for root tag <amf>
if (!mXmlParser->hasNode("amf")) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
ParseNode_Root();
} // namespace Assimp
void AMFImporter::ParseHelper_Node_Enter(AMFNodeElementBase *node) {
mNodeElement_Cur->Child.push_back(node); // add new element to current element child list.
mNodeElement_Cur = node;
}
void AMFImporter::ParseHelper_Node_Exit() {
if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
}
// <amf
// unit="" - The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
// version="" - Version of file format.
// >
// </amf>
// Root XML element.
// Multi elements - No.
void AMFImporter::ParseNode_Root() {
AMFNodeElementBase *ne = nullptr;
XmlNode *root = mXmlParser->findNode("amf");
if (nullptr == root) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
XmlNode node = *root;
mUnit = node.attribute("unit").as_string();
mVersion = node.attribute("version").as_string();
// Read attributes for node <amf>.
// Check attributes
if (!mUnit.empty()) {
if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) {
Throw_IncorrectAttrValue("unit", mUnit);
}
}
// create root node element.
ne = new AMFRoot(nullptr);
mNodeElement_Cur = ne; // set first "current" element
// and assign attribute's values
((AMFRoot *)ne)->Unit = mUnit;
((AMFRoot *)ne)->Version = mVersion;
// Check for child nodes
for (XmlNode &currentNode : node.children() ) {
const std::string currentName = currentNode.name();
if (currentName == "object") {
ParseNode_Object(currentNode);
} else if (currentName == "material") {
ParseNode_Material(currentNode);
} else if (currentName == "texture") {
ParseNode_Texture(currentNode);
} else if (currentName == "constellation") {
ParseNode_Constellation(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
}
mNodeElement_Cur = ne;
}
mNodeElement_Cur = ne; // force restore "current" element
mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
}
// <constellation
// id="" - The Object ID of the new constellation being defined.
// >
// </constellation>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Constellation(XmlNode &node) {
std::string id;
id = node.attribute("id").as_string();
// create and if needed - define new grouping object.
AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
// Check for child nodes
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
std::string name = currentNode.name();
if (name == "instance") {
ParseNode_Instance(currentNode);
} else if (name == "metadata") {
ParseNode_Metadata(currentNode);
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne);
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <instance
// objectid="" - The Object ID of the new constellation being defined.
// >
// </instance>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Instance(XmlNode &node) {
AMFNodeElementBase *ne(nullptr);
// Read attributes for node <constellation>.
std::string objectid = node.attribute("objectid").as_string();
// used object id must be defined, check that.
if (objectid.empty()) {
throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
}
// create and define new grouping object.
ne = new AMFInstance(mNodeElement_Cur);
AMFInstance &als = *((AMFInstance *)ne);
als.ObjectID = objectid;
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == "deltax") {
als.Delta.x = (ai_real)std::atof(currentNode.value());
} else if (currentName == "deltay") {
als.Delta.y = (ai_real)std::atof(currentNode.value());
} else if (currentName == "deltaz") {
als.Delta.z = (ai_real)std::atof(currentNode.value());
} else if (currentName == "rx") {
als.Delta.x = (ai_real)std::atof(currentNode.value());
} else if (currentName == "ry") {
als.Delta.y = (ai_real)std::atof(currentNode.value());
} else if (currentName == "rz") {
als.Delta.z = (ai_real)std::atof(currentNode.value());
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne);
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <object
// id="" - A unique ObjectID for the new object being defined.
// >
// </object>
// An object definition.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Object(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
// Read attributes for node <object>.
std::string id = node.attribute("id").as_string();
// create and if needed - define new geometry object.
ne = new AMFObject(mNodeElement_Cur);
AMFObject &als = *((AMFObject *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
// Check for child nodes
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentName = currentNode.name();
if (currentName == "color") {
ParseNode_Color(currentNode);
} else if (currentName == "mesh") {
ParseNode_Mesh(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <metadata
// type="" - The type of the attribute.
// >
// </metadata>
// Specify additional information about an entity.
// Multi elements - Yes.
// Parent element - <amf>, <object>, <volume>, <material>, <vertex>.
//
// Reserved types are:
// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user.
// "Description" - A description of the content of the entity
// "URL" - A link to an external resource relating to the entity
// "Author" - Specifies the name(s) of the author(s) of the entity
// "Company" - Specifying the company generating the entity
// "CAD" - specifies the name of the originating CAD software and version
// "Revision" - specifies the revision of the entity
// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
void AMFImporter::ParseNode_Metadata(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
std::string type = node.attribute("type").as_string(), value;
XmlParser::getValueAsString(node, value);
// read attribute
ne = new AMFMetadata(mNodeElement_Cur);
((AMFMetadata *)ne)->Type = type;
((AMFMetadata *)ne)->Value = value;
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
const std::string extension = GetExtension(pFile);
if (extension == "amf") {
return true;
}
if (extension.empty() || pCheckSig) {
const char *tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
}
void AMFImporter::GetExtensionList(std::set<std::string> &pExtensionList) {
pExtensionList.insert("amf");
}
const aiImporterDesc *AMFImporter::GetInfo() const {
return &Description;
}
void AMFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
Clear(); // delete old graph.
ParseFile(pFile, pIOHandler);
Postprocess_BuildScene(pScene);
// scene graph is ready, exit.
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -0,0 +1,311 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter.hpp
/// \brief AMF-format files importer for Assimp.
/// \date 2016
/// \author smal.root@gmail.com
// Thanks to acorn89 for support.
#pragma once
#ifndef INCLUDED_AI_AMF_IMPORTER_H
#define INCLUDED_AI_AMF_IMPORTER_H
#include "AMFImporter_Node.hpp"
// Header files, Assimp.
#include "assimp/types.h"
#include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h>
#include <assimp/importerdesc.h>
#include <assimp/DefaultLogger.hpp>
// Header files, stdlib.
#include <set>
namespace Assimp {
/// \class AMFImporter
/// Class that holding scene graph which include: geometry, metadata, materials etc.
///
/// Implementing features.
///
/// Limitations.
///
/// 1. When for texture mapping used set of source textures (r, g, b, a) not only one then attribute "tiled" for all set will be true if it true in any of
/// source textures.
/// Example. Triangle use for texture mapping three textures. Two of them has "tiled" set to false and one - set to true. In scene all three textures
/// will be tiled.
///
/// Unsupported features:
/// 1. Node <composite>, formulas in <composite> and <color>. For implementing this feature can be used expression parser "muParser" like in project
/// "amf_tools".
/// 2. Attribute "profile" in node <color>.
/// 3. Curved geometry: <edge>, <normal> and children nodes of them.
/// 4. Attributes: "unit" and "version" in <amf> read but do nothing.
/// 5. <metadata> stored only for root node <amf>.
/// 6. Color averaging of vertices for which <triangle>'s set different colors.
///
/// Supported nodes:
/// General:
/// <amf>; <constellation>; <instance> and children <deltax>, <deltay>, <deltaz>, <rx>, <ry>, <rz>; <metadata>;
///
/// Geometry:
/// <object>; <mesh>; <vertices>; <vertex>; <coordinates> and children <x>, <y>, <z>; <volume>; <triangle> and children <v1>, <v2>, <v3>;
///
/// Material:
/// <color> and children <r>, <g>, <b>, <a>; <texture>; <material>;
/// two variants of texture coordinates:
/// new - <texmap> and children <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>
/// old - <map> and children <u1>, <u2>, <u3>, <v1>, <v2>, <v3>
///
class AMFImporter : public BaseImporter {
private:
struct SPP_Material; // forward declaration
/// Data type for post-processing step. More suitable container for part of material's composition.
struct SPP_Composite {
SPP_Material *Material; ///< Pointer to material - part of composition.
std::string Formula; ///< Formula for calculating ratio of \ref Material.
};
/// \struct SPP_Material
/// Data type for post-processing step. More suitable container for material.
struct SPP_Material {
std::string ID; ///< Material ID.
std::list<AMFMetadata *> Metadata; ///< Metadata of material.
AMFColor *Color; ///< Color of material.
std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate.
/// \param [in] pX - "x" coordinate.
/// \param [in] pY - "y" coordinate.
/// \param [in] pZ - "z" coordinate.
/// \return calculated color.
aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
};
/// Data type for post-processing step. More suitable container for texture.
struct SPP_Texture {
std::string ID;
size_t Width, Height, Depth;
bool Tiled;
char FormatHint[9]; // 8 for string + 1 for terminator.
uint8_t *Data;
};
/// Data type for post-processing step. Contain face data.
struct SComplexFace {
aiFace Face; ///< Face vertices.
const AMFColor *Color; ///< Face color. Equal to nullptr if color is not set for the face.
const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
};
using AMFMetaDataArray = std::vector<AMFMetadata*>;
using MeshArray = std::vector<aiMesh*>;
using NodeArray = std::vector<aiNode*>;
/// Clear all temporary data.
void Clear();
/// Get data stored in <vertices> and place it to arrays.
/// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \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
/// contain nullptr.
void PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
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
/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
/// to converted textures list.
/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
/// \param [in] pID_R - ID of source "red" texture.
/// \param [in] pID_G - ID of source "green" texture.
/// \param [in] pID_B - ID of source "blue" texture.
/// \param [in] pID_A - ID of source "alpha" texture.
/// \return index of the texture in array of the converted textures.
size_t PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B, const std::string &pID_A);
/// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
/// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
/// processing.
/// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated);
/// Check if child elements of node element is metadata and add it to scene node.
/// \param [in] pMetadataList - reference to list with collected metadata.
/// \param [out] pSceneNode - scene node in which metadata will be added.
void Postprocess_AddMetadata(const AMFMetaDataArray &pMetadataList, aiNode &pSceneNode) const;
/// To create aiMesh and aiNode for it from <object>.
/// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \param [out] meshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - pointer to place where new aiNode will be created.
void Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode);
/// Create mesh for every <volume> in <mesh>.
/// \param [in] pNodeElement - reference to node element which kept <mesh> data.
/// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all <volume>'s.
/// \param [in] pVertexColorArray - reference to vertices colors for all <volume>'s. If color for vertex is not set then corresponding member of array
/// contain nullptr.
/// \param [in] pObjectColor - pointer to colors for <object>. If color is not set then argument contain nullptr.
/// \param [in] pMaterialList - reference to a list with defined materials.
/// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
void Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor,
MeshArray &pMeshList, aiNode &pSceneNode);
/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
void Postprocess_BuildMaterial(const AMFMaterial &pMaterial);
/// Create and add to aiNode's list new part of scene graph defined by <constellation>.
/// \param [in] pConstellation - reference to <constellation> node.
/// \param [out] nodeArray - reference to aiNode's list.
void Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const;
/// Build Assimp scene graph in aiScene from collected data.
/// \param [out] pScene - pointer to aiScene where tree will be built.
void Postprocess_BuildScene(aiScene *pScene);
/// Decode Base64-encoded data.
/// \param [in] pInputBase64 - reference to input Base64-encoded string.
/// \param [out] pOutputData - reference to output array for decoded data.
void ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const;
/// Parse <AMF> node of the file.
void ParseNode_Root();
/// Parse <constellation> node of the file.
void ParseNode_Constellation(XmlNode &node);
/// Parse <instance> node of the file.
void ParseNode_Instance(XmlNode &node);
/// Parse <material> node of the file.
void ParseNode_Material(XmlNode &node);
/// Parse <metadata> node.
void ParseNode_Metadata(XmlNode &node);
/// Parse <object> node of the file.
void ParseNode_Object(XmlNode &node);
/// Parse <texture> node of the file.
void ParseNode_Texture(XmlNode &node);
/// Parse <coordinates> node of the file.
void ParseNode_Coordinates(XmlNode &node);
/// Parse <edge> node of the file.
void ParseNode_Edge(XmlNode &node);
/// Parse <mesh> node of the file.
void ParseNode_Mesh(XmlNode &node);
/// Parse <triangle> node of the file.
void ParseNode_Triangle(XmlNode &node);
/// Parse <vertex> node of the file.
void ParseNode_Vertex(XmlNode &node);
/// Parse <vertices> node of the file.
void ParseNode_Vertices(XmlNode &node);
/// Parse <volume> node of the file.
void ParseNode_Volume(XmlNode &node);
/// Parse <color> node of the file.
void ParseNode_Color(XmlNode &node);
/// 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>.
void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false);
public:
/// Default constructor.
AMFImporter() AI_NO_EXCEPT;
/// Default destructor.
~AMFImporter();
/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
/// Also exception can be thrown if trouble will found.
/// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
void ParseHelper_Node_Enter(AMFNodeElementBase *child);
void ParseHelper_Node_Exit();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
void GetExtensionList(std::set<std::string> &pExtensionList);
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
const aiImporterDesc *GetInfo() const;
bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
void Throw_CloseNotFound(const std::string &nodeName);
void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName);
void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName);
void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription);
void Throw_ID_NotFound(const std::string &pID) const;
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
bool XML_SearchNode(const std::string &nodeName);
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
AMFImporter(const AMFImporter &pScene) = delete;
AMFImporter &operator=(const AMFImporter &pScene) = delete;
private:
static const aiImporterDesc Description;
AMFNodeElementBase *mNodeElement_Cur; ///< Current element.
std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph.
XmlParser *mXmlParser;
std::string mUnit;
std::string mVersion;
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.
};
} // namespace Assimp
#endif // INCLUDED_AI_AMF_IMPORTER_H

View File

@ -0,0 +1,289 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Geometry.cpp
/// \brief Parsing data from geometry nodes.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
#include <assimp/ParsingUtils.h>
namespace Assimp {
// <mesh>
// </mesh>
// A 3D mesh hull.
// Multi elements - Yes.
// Parent element - <object>.
void AMFImporter::ParseNode_Mesh(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
// create new mesh object.
ne = new AMFMesh(mNodeElement_Cur);
// Check for child nodes
if (0 != ASSIMP_stricmp(node.name(), "mesh")) {
return;
}
bool found_verts = false, found_volumes = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
pugi::xml_node vertNode = node.child("vertices");
if (!vertNode.empty()) {
ParseNode_Vertices(vertNode);
found_verts = true;
}
pugi::xml_node volumeNode = node.child("volume");
if (!volumeNode.empty()) {
ParseNode_Volume(volumeNode);
found_volumes = true;
}
ParseHelper_Node_Exit();
}
if (!found_verts && !found_volumes) {
mNodeElement_Cur->Child.push_back(ne);
} // if(!mReader->isEmptyElement()) else
// and to node element list because its a new object in graph.
mNodeElement_List.push_back(ne);
}
// <vertices>
// </vertices>
// The list of vertices to be used in defining triangles.
// Multi elements - No.
// Parent element - <mesh>.
void AMFImporter::ParseNode_Vertices(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
// create new mesh object.
ne = new AMFVertices(mNodeElement_Cur);
// Check for child nodes
pugi::xml_node vertexNode = node.child("vertex");
if (!vertexNode.empty()) {
ParseHelper_Node_Enter(ne);
ParseNode_Vertex(vertexNode);
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <vertex>
// </vertex>
// A vertex to be referenced in triangles.
// Multi elements - Yes.
// Parent element - <vertices>.
void AMFImporter::ParseNode_Vertex(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
// create new mesh object.
ne = new AMFVertex(mNodeElement_Cur);
// Check for child nodes
pugi::xml_node colorNode = node.child("color");
bool col_read = false;
bool coord_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
if (!colorNode.empty()) {
ParseNode_Color(colorNode);
col_read = true;
}
pugi::xml_node coordNode = node.child("coordinates");
if (!coordNode.empty()) {
ParseNode_Coordinates(coordNode);
coord_read = true;
}
ParseHelper_Node_Exit();
}
if (!coord_read && !col_read) {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <coordinates>
// </coordinates>
// Specifies the 3D location of this vertex.
// Multi elements - No.
// Parent element - <vertex>.
//
// Children elements:
// <x>, <y>, <z>
// Multi elements - No.
// X, Y, or Z coordinate, respectively, of a vertex position in space.
void AMFImporter::ParseNode_Coordinates(XmlNode &node) {
AMFNodeElementBase *ne = nullptr;
// create new color object.
ne = new AMFCoordinates(mNodeElement_Cur);
AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "X") {
XmlParser::getValueAsFloat(currentNode, als.Coordinate.x);
} else if (currentName == "Y") {
XmlParser::getValueAsFloat(currentNode, als.Coordinate.y);
} else if (currentName == "Z") {
XmlParser::getValueAsFloat(currentNode, als.Coordinate.z);
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne);
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <volume
// materialid="" - Which material to use.
// type="" - What this volume describes can be “region” or “support”. If none specified, “object” is assumed. If support, then the geometric
// requirements 1-8 listed in section 5 do not need to be maintained.
// >
// </volume>
// Defines a volume from the established vertex list.
// Multi elements - Yes.
// Parent element - <mesh>.
void AMFImporter::ParseNode_Volume(XmlNode &node) {
std::string materialid;
std::string type;
AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur);
// Read attributes for node <color>.
// and assign read data
((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string();
((AMFVolume *)ne)->Type = type;
// Check for child nodes
bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "color") {
if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <volume>.");
ParseNode_Color(currentNode);
col_read = true;
} else if (currentName == "triangle") {
ParseNode_Triangle(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
} else if (currentName == "volume") {
ParseNode_Metadata(currentNode);
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
// <triangle>
// </triangle>
// Defines a 3D triangle from three vertices, according to the right-hand rule (counter-clockwise when looking from the outside).
// Multi elements - Yes.
// Parent element - <volume>.
//
// Children elements:
// <v1>, <v2>, <v3>
// Multi elements - No.
// Index of the desired vertices in a triangle or edge.
void AMFImporter::ParseNode_Triangle(XmlNode &node) {
AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur);
// create new triangle object.
AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience
bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "color") {
if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <triangle>.");
ParseNode_Color(currentNode);
col_read = true;
} else if (currentName == "texmap") {
ParseNode_TexMap(currentNode);
} else if (currentName == "map") {
ParseNode_TexMap(currentNode, true);
} else if (currentName == "v1") {
als.V[0] = std::atoi(currentNode.value());
} else if (currentName == "v2") {
als.V[1] = std::atoi(currentNode.value());
} else if (currentName == "v3") {
als.V[2] = std::atoi(currentNode.value());
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -1,12 +1,10 @@
/*
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,

View File

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

View File

@ -0,0 +1,306 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Node.hpp
/// \brief Elements of scene graph.
/// \date 2016
/// \author smal.root@gmail.com
#pragma once
#ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H
#define INCLUDED_AI_AMF_IMPORTER_NODE_H
// Header files, stdlib.
#include <list>
#include <string>
#include <vector>
// Header files, Assimp.
#include "assimp/scene.h"
#include "assimp/types.h"
/// \class CAMFImporter_NodeElement
/// Base class for elements of nodes.
class AMFNodeElementBase {
public:
/// Define what data type contain node element.
enum EType {
ENET_Color, ///< Color element: <color>.
ENET_Constellation, ///< Grouping element: <constellation>.
ENET_Coordinates, ///< Coordinates element: <coordinates>.
ENET_Edge, ///< Edge element: <edge>.
ENET_Instance, ///< Grouping element: <constellation>.
ENET_Material, ///< Material element: <material>.
ENET_Metadata, ///< Metadata element: <metadata>.
ENET_Mesh, ///< Metadata element: <mesh>.
ENET_Object, ///< Element which hold object: <object>.
ENET_Root, ///< Root element: <amf>.
ENET_Triangle, ///< Triangle element: <triangle>.
ENET_TexMap, ///< Texture coordinates element: <texmap> or <map>.
ENET_Texture, ///< Texture element: <texture>.
ENET_Vertex, ///< Vertex element: <vertex>.
ENET_Vertices, ///< Vertex element: <vertices>.
ENET_Volume, ///< Volume element: <volume>.
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
const EType Type; ///< Type of element.
std::string ID; ///< ID of element.
AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
std::list<AMFNodeElementBase *> Child; ///< Child elements.
public: /// Destructor, virtual..
virtual ~AMFNodeElementBase() {
// empty
}
/// Disabled copy constructor and co.
AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete;
AMFNodeElementBase(AMFNodeElementBase &&) = delete;
AMFNodeElementBase &operator=(const AMFNodeElementBase &pNodeElement) = delete;
AMFNodeElementBase() = delete;
protected:
/// In constructor inheritor must set element type.
/// \param [in] pType - element type.
/// \param [in] pParent - parent element.
AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
Type(pType), ID(), Parent(pParent), Child() {
// empty
}
}; // class IAMFImporter_NodeElement
/// \struct CAMFImporter_NodeElement_Constellation
/// A collection of objects or constellations with specific relative locations.
struct AMFConstellation : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFConstellation(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Constellation, pParent) {}
}; // struct CAMFImporter_NodeElement_Constellation
/// \struct CAMFImporter_NodeElement_Instance
/// Part of constellation.
struct AMFInstance : public AMFNodeElementBase {
std::string ObjectID; ///< ID of object for instantiation.
/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
/// create an instance of the object in the current constellation.
aiVector3D Delta;
/// \var Rotation - The rotation, in degrees, to rotate the referenced object about its x, y, and z axes, respectively, to create an
/// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z.
aiVector3D Rotation;
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFInstance(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Instance, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Metadata
/// Structure that define metadata node.
struct AMFMetadata : public AMFNodeElementBase {
std::string Type; ///< Type of "Value".
std::string Value; ///< Value.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFMetadata(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Metadata, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Root
/// Structure that define root node.
struct AMFRoot : public AMFNodeElementBase {
std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
std::string Version; ///< Version of format.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFRoot(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Root, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Color
/// Structure that define object node.
struct AMFColor : public AMFNodeElementBase {
bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA.
aiColor4D Color; ///< Constant color.
std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b..
/// @brief Constructor.
/// @param [in] pParent - pointer to parent node.
AMFColor(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() {
// empty
}
};
/// \struct CAMFImporter_NodeElement_Material
/// Structure that define material node.
struct AMFMaterial : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFMaterial(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Material, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Object
/// Structure that define object node.
struct AMFObject : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFObject(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Object, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Mesh
/// Structure that define mesh node.
struct AMFMesh : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFMesh(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Mesh, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Vertex
/// Structure that define vertex node.
struct AMFVertex : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFVertex(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Vertex, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Edge
/// Structure that define edge node.
struct AMFEdge : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFEdge(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Edge, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Vertices
/// Structure that define vertices node.
struct AMFVertices : public AMFNodeElementBase {
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFVertices(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Vertices, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Volume
/// Structure that define volume node.
struct AMFVolume : public AMFNodeElementBase {
std::string MaterialID; ///< Which material to use.
std::string Type; ///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFVolume(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Volume, pParent) {}
};
/// \struct CAMFImporter_NodeElement_Coordinates
/// Structure that define coordinates node.
struct AMFCoordinates : public AMFNodeElementBase {
aiVector3D Coordinate; ///< Coordinate.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFCoordinates(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Coordinates, pParent) {}
};
/// \struct CAMFImporter_NodeElement_TexMap
/// Structure that define texture coordinates node.
struct AMFTexMap : public AMFNodeElementBase {
aiVector3D TextureCoordinate[3]; ///< Texture coordinates.
std::string TextureID_R; ///< Texture ID for red color component.
std::string TextureID_G; ///< Texture ID for green color component.
std::string TextureID_B; ///< Texture ID for blue color component.
std::string TextureID_A; ///< Texture ID for alpha color component.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFTexMap(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() {
// empty
}
};
/// \struct CAMFImporter_NodeElement_Triangle
/// Structure that define triangle node.
struct AMFTriangle : public AMFNodeElementBase {
size_t V[3]; ///< Triangle vertices.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFTriangle(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Triangle, pParent) {
// empty
}
};
/// Structure that define texture node.
struct AMFTexture : public AMFNodeElementBase {
size_t Width, Height, Depth; ///< Size of the texture.
std::vector<uint8_t> Data; ///< Data of the texture.
bool Tiled;
/// Constructor.
/// \param [in] pParent - pointer to parent node.
AMFTexture(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Texture, pParent), Width(0), Height(0), Depth(0), Data(), Tiled(false) {
// empty
}
};
#endif // INCLUDED_AI_AMF_IMPORTER_NODE_H

View File

@ -0,0 +1,892 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
#include <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
#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;
}
// all coordinates stored as child and we need to reserve space for future push_back's.
pVertexCoordinateArray.reserve(vn->Child.size());
// colors count equal vertices count.
pVertexColorArray.resize(vn->Child.size());
col_idx = 0;
// Inside vertices collect all data and place to arrays
for (AMFNodeElementBase *vn_child : vn->Child) {
// vertices, colors
if (vn_child->Type == AMFNodeElementBase::ENET_Vertex) {
// by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr;
for (AMFNodeElementBase *vtx : vn_child->Child) {
if (vtx->Type == AMFNodeElementBase::ENET_Coordinates) {
pVertexCoordinateArray.push_back(((AMFCoordinates *)vtx)->Coordinate);
continue;
}
if (vtx->Type == AMFNodeElementBase::ENET_Color) {
pVertexColorArray[col_idx] = (AMFColor *)vtx;
continue;
}
}
++col_idx;
}
}
}
size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) {
if (r.empty() && g.empty() && b.empty() && a.empty()) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
}
std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a;
size_t TextureConverted_Index = 0;
for (const SPP_Texture &tex_convd : mTexture_Converted) {
if (tex_convd.ID == TextureConverted_ID) {
return TextureConverted_Index;
} else {
++TextureConverted_Index;
}
}
// Converted texture not found, create it.
AMFTexture *src_texture[4] {
nullptr
};
std::vector<AMFTexture *> src_texture_4check;
SPP_Texture converted_texture;
{ // find all specified source textures
AMFNodeElementBase *t_tex = nullptr;
// R
if (!r.empty()) {
if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(r);
}
src_texture[0] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
} else {
src_texture[0] = nullptr;
}
// G
if (!g.empty()) {
if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(g);
}
src_texture[1] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
} else {
src_texture[1] = nullptr;
}
// B
if (!b.empty()) {
if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(b);
}
src_texture[2] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
} else {
src_texture[2] = nullptr;
}
// A
if (!a.empty()) {
if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) {
Throw_ID_NotFound(a);
}
src_texture[3] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
} else {
src_texture[3] = nullptr;
}
} // END: find all specified source textures
// check that all textures has same size
if (src_texture_4check.size() > 1) {
for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++) {
if ((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth)) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
}
}
} // if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture.Width = src_texture_4check[0]->Width;
converted_texture.Height = src_texture_4check[0]->Height;
converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false;
for (uint8_t i = 0; i < src_texture_4check.size(); ++i) {
converted_texture.Tiled |= src_texture_4check[i]->Tiled;
}
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
if (!r.empty()) converted_texture.FormatHint[4] = '8';
if (!g.empty()) converted_texture.FormatHint[5] = '8';
if (!b.empty()) converted_texture.FormatHint[6] = '8';
if (!a.empty()) converted_texture.FormatHint[7] = '8';
// Сopy data of textures.
size_t tex_size = 0;
size_t step = 0;
size_t off_g = 0;
size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied.
if (!r.empty() && nullptr != src_texture[0]) {
tex_size += src_texture[0]->Data.size();
step++, off_g++, off_b++;
}
if (!g.empty() && nullptr != src_texture[1]) {
tex_size += src_texture[1]->Data.size();
step++, off_b++;
}
if (!b.empty() && nullptr != src_texture[2]) {
tex_size += src_texture[2]->Data.size();
step++;
}
if (!a.empty() && nullptr != src_texture[3]) {
tex_size += src_texture[3]->Data.size();
step++;
}
// Create target array.
converted_texture.Data = new uint8_t[tex_size];
// And copy data
auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
if (!pID.empty()) {
for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
AMFTexture *tex = src_texture[pSrcTexNum];
ai_assert(tex);
converted_texture.Data[idx_target] = tex->Data.at(idx_src);
}
}
}; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(r, 0, step, 0);
CopyTextureData(g, off_g, step, 1);
CopyTextureData(b, off_b, step, 2);
CopyTextureData(a, step - 1, step, 3);
// Store new converted texture ID
converted_texture.ID = TextureConverted_ID;
// Store new converted texture
mTexture_Converted.push_back(converted_texture);
return TextureConverted_Index;
}
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<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 AMFMetaDataArray &metadataList, aiNode &sceneNode) const {
if (metadataList.empty()) {
return;
}
if (sceneNode.mMetaData != nullptr) {
throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
}
// copy collected metadata to output node.
sceneNode.mMetaData = aiMetadata::Alloc(static_cast<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));
}
}
void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, 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, meshList, **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, MeshArray &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 = 0;
if (pBiggerThan != nullptr) {
bool found = false;
for (const SComplexFace &face : pFaceList) {
for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) {
if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
rv = face.Face.mIndices[idx_vert];
found = true;
break;
}
}
if (found) {
break;
}
}
if (!found) {
return *pBiggerThan;
}
} else {
rv = pFaceList.front().Face.mIndices[0];
} // if(pBiggerThan != nullptr) else
for (const SComplexFace &face : pFaceList) {
for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) {
if (face.Face.mIndices[vi] < rv) {
if (pBiggerThan != nullptr) {
if (face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
} else {
rv = face.Face.mIndices[vi];
}
}
}
} // for(const SComplexFace& face: pFaceList)
return rv;
}; // auto VertexIndex_GetMinimal = [](const std::list<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. Optimization mean following.In AMF all volumes use one big list of vertices. And one volume
// can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10.
// Do you need all this thousands of garbage? Of course no. So, optimization step transform sparse indices set to continuous.
size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
std::vector<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
/// optimization.
bool *idx_vert_used;
idx_vert_used = new bool[VertexCount_Max * 2];
for (size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++)
idx_vert_used[i] = false;
// This ID's will be used when set materials ID in scene.
tmesh->mMaterialIndex = static_cast<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, NodeArray &nodeArray) 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, nodeArray, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation
t_node = new aiNode;
t_node->mParent = con_node;
// apply transformation
aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
// create array for one child node
t_node->mNumChildren = 1;
t_node->mChildren = new aiNode *[t_node->mNumChildren];
SceneCombiner::Copy(&t_node->mChildren[0], found_node);
t_node->mChildren[0]->mParent = t_node;
ch_node.push_back(t_node);
} // for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
// copy found aiNode's as children
if (ch_node.empty()) throw DeadlyImportError("<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
nodeArray.push_back(con_node);
}
void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
NodeArray nodeArray;
MeshArray mesh_list;
AMFMetaDataArray meta_list;
//
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
// For building aiScene we are must to do few steps:
// at first creating root node for aiScene.
pScene->mRootNode = new aiNode;
pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
// search for root(<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) {
nodeArray.push_back(tnode);
}
}
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes.
//
for (const AMFNodeElementBase *root_child : root_el->Child) {
// 4. <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), nodeArray);
}
// 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 (nodeArray.size() > 1) {
// walk through all nodes
for (NodeArray::iterator nl_it = nodeArray.begin(); nl_it != nodeArray.end(); ++nl_it) {
// and try to find them in another top nodes.
NodeArray::const_iterator next_it = nl_it;
++next_it;
for (; next_it != nodeArray.end(); ++next_it) {
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
nodeArray.erase(nl_it);
goto nl_clean_loop;
}
} // for(; next_it != node_list.end(); next_it++)
} // for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
}
//
// move created objects to aiScene
//
//
// Nodes
if (!nodeArray.empty()) {
NodeArray::const_iterator nl_it = nodeArray.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(nodeArray.size());
pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) {
// Objects and constellation that must be showed placed at top of hierarchy in <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()) {
MeshArray::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

@ -51,15 +51,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers
#include "ASELoader.h"
#include <assimp/StringComparison.h>
#include <assimp/SkeletonMeshBuilder.h>
#include "Common/TargetAnimation.h"
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/StringComparison.h>
#include <assimp/Importer.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/Importer.hpp>
#include <memory>
@ -84,12 +84,8 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
ASEImporter::ASEImporter()
: mParser()
, mBuffer()
, pcScene()
, configRecomputeNormals()
, noSkeletonMesh() {
ASEImporter::ASEImporter() :
mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() {
// empty
}
@ -126,7 +122,9 @@ const aiImporterDesc* ASEImporter::GetInfo () const {
// Setup configuration options
void ASEImporter::SetupProperties(const Importer *pImp) {
configRecomputeNormals = (pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS, 1) ?
true :
false);
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
}
@ -139,7 +137,7 @@ void ASEImporter::InternReadFile( const std::string& pFile,
// Check whether we can read from the file
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
@ -226,17 +224,20 @@ void ASEImporter::InternReadFile( const std::string& pFile,
// into one huge list.
//------------------------------------------------------------------
std::vector<BaseNode *> nodes;
nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
+ mParser->m_vCameras.size() + mParser->m_vDummies.size());
nodes.reserve(mParser->m_vMeshes.size() + mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size());
// Lights
for (auto &light : mParser->m_vLights)nodes.push_back(&light);
for (auto &light : mParser->m_vLights)
nodes.push_back(&light);
// Cameras
for (auto &camera : mParser->m_vCameras)nodes.push_back(&camera);
for (auto &camera : mParser->m_vCameras)
nodes.push_back(&camera);
// Meshes
for (auto &mesh : mParser->m_vMeshes)nodes.push_back(&mesh);
for (auto &mesh : mParser->m_vMeshes)
nodes.push_back(&mesh);
// Dummies
for (auto &dummy : mParser->m_vDummies)nodes.push_back(&dummy);
for (auto &dummy : mParser->m_vDummies)
nodes.push_back(&dummy);
// build the final node graph
BuildNodes(nodes);
@ -263,9 +264,8 @@ void ASEImporter::InternReadFile( const std::string& pFile,
}
}
// ------------------------------------------------------------------------------------------------
void ASEImporter::GenerateDefaultMaterial()
{
ai_assert(NULL != mParser);
void ASEImporter::GenerateDefaultMaterial() {
ai_assert(nullptr != mParser);
bool bHas = false;
for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
@ -288,8 +288,7 @@ void ASEImporter::GenerateDefaultMaterial()
}
// ------------------------------------------------------------------------------------------------
void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
{
void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
// check whether we have at least one mesh which has animations
std::vector<ASE::BaseNode *>::const_iterator i = nodes.begin();
unsigned int iNum = 0;
@ -370,8 +369,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
nd->mNodeName.Set(me->mName);
// copy position keys
if (me->mAnim.akeyPositions.size() > 1 )
{
if (me->mAnim.akeyPositions.size() > 1) {
// Allocate the key array and fill it
nd->mNumPositionKeys = (unsigned int)me->mAnim.akeyPositions.size();
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
@ -424,8 +422,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
// ------------------------------------------------------------------------------------------------
// Build output cameras
void ASEImporter::BuildCameras()
{
void ASEImporter::BuildCameras() {
if (!mParser->m_vCameras.empty()) {
pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
pcScene->mCameras = new aiCamera *[pcScene->mNumCameras];
@ -446,8 +443,7 @@ void ASEImporter::BuildCameras()
// ------------------------------------------------------------------------------------------------
// Build output lights
void ASEImporter::BuildLights()
{
void ASEImporter::BuildLights() {
if (!mParser->m_vLights.empty()) {
pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
pcScene->mLights = new aiLight *[pcScene->mNumLights];
@ -462,8 +458,7 @@ void ASEImporter::BuildLights()
out->mDirection = aiVector3D(0.f, 0.f, -1.f);
out->mName.Set(in.mName);
switch (in.mLightType)
{
switch (in.mLightType) {
case ASE::Light::TARGET:
out->mType = aiLightSource_SPOT;
out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
@ -486,16 +481,14 @@ void ASEImporter::BuildLights()
// ------------------------------------------------------------------------------------------------
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
aiNode* pcParent,const char* szName)
{
aiNode *pcParent, const char *szName) {
aiMatrix4x4 m;
AddNodes(nodes, pcParent, szName, m);
}
// ------------------------------------------------------------------------------------------------
// Add meshes to a given node
void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
{
void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
// Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
const aiMesh *pcMesh = pcScene->mMeshes[i];
@ -549,8 +542,7 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
// Add child nodes to a given parent node
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
aiNode *pcParent, const char *szName,
const aiMatrix4x4& mat)
{
const aiMatrix4x4 &mat) {
const size_t len = szName ? ::strlen(szName) : 0;
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
@ -564,8 +556,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
if (szName) {
if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str()))
continue;
}
else if (snode->mParent.length())
} else if (snode->mParent.length())
continue;
(*it)->mProcessed = true;
@ -595,8 +586,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
// slightly inconvinient here and a better solution should
// be used when this code is refactored next.
AddMeshes(snode, node);
}
else if (is_not_qnan( snode->mTargetPosition.x )) {
} else if (is_not_qnan(snode->mTargetPosition.x)) {
// If this is a target camera or light we generate a small
// child node which marks the position of the camera
// target (the direction information is contained in *this*
@ -624,7 +614,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
node->mNumChildren++;
// What we did is so great, it is at least worth a debug message
ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")");
ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (" + snode->mName + ")");
}
}
@ -644,7 +634,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
// ------------------------------------------------------------------------------------------------
// Build the output node graph
void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
ai_assert(NULL != pcScene);
ai_assert(nullptr != pcScene);
// allocate the one and only root node
aiNode *root = pcScene->mRootNode = new aiNode();
@ -663,7 +653,7 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
}
// add all nodes
AddNodes(nodes,ch,NULL);
AddNodes(nodes, ch, nullptr);
// now iterate through al nodes and find those that have not yet
// been added to the nodegraph (= their parent could not be recognized)
@ -723,9 +713,9 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
}
// Reset the third color set to NULL - we used this field to store a temporary pointer
// Reset the third color set to nullptr - we used this field to store a temporary pointer
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i)
pcScene->mMeshes[i]->mColors[2] = NULL;
pcScene->mMeshes[i]->mColors[2] = nullptr;
// The root node should not have at least one child or the file is valid
if (!pcScene->mRootNode->mNumChildren) {
@ -773,8 +763,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
// iterate through all faces in the mesh
unsigned int iCurrent = 0, fi = 0;
for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin(); i != mesh.mFaces.end(); ++i, ++fi) {
for (unsigned int n = 0; n < 3;++n,++iCurrent)
{
for (unsigned int n = 0; n < 3; ++n, ++iCurrent) {
mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
// add texture coordinates
@ -814,8 +803,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
// ------------------------------------------------------------------------------------------------
// Copy a texture from the ASE structs to the output material
void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
{
void CopyASETexture(aiMaterial &mat, ASE::Texture &texture, aiTextureType type) {
// Setup the texture name
aiString tex;
tex.Set(texture.mMapName);
@ -831,8 +819,7 @@ void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
// ------------------------------------------------------------------------------------------------
// Convert from ASE material to output material
void ASEImporter::ConvertMaterial(ASE::Material& mat)
{
void ASEImporter::ConvertMaterial(ASE::Material &mat) {
// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
// Allocate the output material
@ -855,16 +842,14 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
mat.pcInstance->AddProperty(&mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
// shininess
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
{
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) {
mat.pcInstance->AddProperty(&mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
mat.pcInstance->AddProperty(&mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
}
// If there is no shininess, we can disable phong lighting
else if (D3DS::Discreet3DS::Metal == mat.mShading ||
D3DS::Discreet3DS::Phong == mat.mShading ||
D3DS::Discreet3DS::Blinn == mat.mShading)
{
D3DS::Discreet3DS::Blinn == mat.mShading) {
mat.mShading = D3DS::Discreet3DS::Gouraud;
}
@ -872,35 +857,37 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
mat.pcInstance->AddProperty<ai_real>(&mat.mTransparency, 1, AI_MATKEY_OPACITY);
// Two sided rendering?
if (mat.mTwoSided)
{
if (mat.mTwoSided) {
int i = 1;
mat.pcInstance->AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
}
// shading mode
aiShadingMode eShading = aiShadingMode_NoShading;
switch (mat.mShading)
{
switch (mat.mShading) {
case D3DS::Discreet3DS::Flat:
eShading = aiShadingMode_Flat; break;
eShading = aiShadingMode_Flat;
break;
case D3DS::Discreet3DS::Phong:
eShading = aiShadingMode_Phong; break;
eShading = aiShadingMode_Phong;
break;
case D3DS::Discreet3DS::Blinn:
eShading = aiShadingMode_Blinn; break;
eShading = aiShadingMode_Blinn;
break;
// I don't know what "Wire" shading should be,
// assume it is simple lambertian diffuse (L dot N) shading
case D3DS::Discreet3DS::Wire:
{
case D3DS::Discreet3DS::Wire: {
// set the wireframe flag
unsigned int iWire = 1;
mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; break;
eShading = aiShadingMode_Gouraud;
break;
case D3DS::Discreet3DS::Metal:
eShading = aiShadingMode_CookTorrance; break;
eShading = aiShadingMode_CookTorrance;
break;
}
mat.pcInstance->AddProperty<int>((int *)&eShading, 1, AI_MATKEY_SHADING_MODEL);
@ -934,7 +921,8 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
// store the name of the material itself, too
if (mat.mName.length() > 0) {
aiString tex;tex.Set( mat.mName);
aiString tex;
tex.Set(mat.mName);
mat.pcInstance->AddProperty(&tex, AI_MATKEY_NAME);
}
return;
@ -942,8 +930,7 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
// ------------------------------------------------------------------------------------------------
// Build output meshes
void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
{
void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMeshes) {
// validate the material index of the mesh
if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1;
@ -952,8 +939,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
// If the material the mesh is assigned to is consisting of submeshes, split it
if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
std::vector<ASE::Material> vSubMaterials = mParser->
m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
std::vector<unsigned int> *aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
@ -965,8 +951,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
// use the last material instead
aiSplit[vSubMaterials.size() - 1].push_back(i);
}
else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
} else
aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
}
// now generate submeshes
@ -994,7 +980,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
// receive output vertex weights
std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
std::vector<std::pair<unsigned int, float>> *avOutputBones = nullptr;
if (!mesh.mBones.empty()) {
avOutputBones = new std::vector<std::pair<unsigned int, float>>[mesh.mBones.size()];
}
@ -1041,8 +1027,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
}
// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
if (!mesh.amTexCoords[c].empty())
{
if (!mesh.amTexCoords[c].empty()) {
p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
iBase = 0;
for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
@ -1075,8 +1060,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones];
aiBone **pcBone = p_pcOut->mBones;
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
{
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) {
if (!avOutputBones[mrspock].empty()) {
// we will need this bone. add it to the output mesh and
// add all per-vertex weights
@ -1086,8 +1070,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
pc->mWeights = new aiVertexWeight[pc->mNumWeights];
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
{
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights; ++captainkirk) {
const std::pair<unsigned int, float> &ref = avOutputBones[mrspock][captainkirk];
pc->mWeights[captainkirk].mVertexId = ref.first;
pc->mWeights[captainkirk].mWeight = ref.second;
@ -1102,9 +1085,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
}
// delete storage
delete[] aiSplit;
}
else
{
} else {
// Otherwise we can simply copy the data to one output mesh
// This codepath needs less memory and uses fast memcpy()s
// to do the actual copying. So I think it is worth the
@ -1189,8 +1170,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
for (std::vector<std::pair<int, float>>::const_iterator
ronaldweasley = (*harrypotter).mBoneWeights.begin();
ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
{
ronaldweasley != (*harrypotter).mBoneWeights.end(); ++ronaldweasley) {
aiVertexWeight weight;
weight.mVertexId = quak;
weight.mWeight = (*ronaldweasley).second;
@ -1222,21 +1202,18 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
// ------------------------------------------------------------------------------------------------
// Setup proper material indices and build output materials
void ASEImporter::BuildMaterialIndices()
{
ai_assert(NULL != pcScene);
void ASEImporter::BuildMaterialIndices() {
ai_assert(nullptr != pcScene);
// iterate through all materials and check whether we need them
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
{
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
ASE::Material &mat = mParser->m_vMaterials[iMat];
if (mat.bNeed) {
// Convert it to the aiMaterial layout
ConvertMaterial(mat);
++pcScene->mNumMaterials;
}
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
{
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
ASE::Material &submat = mat.avSubMaterials[iSubMat];
if (submat.bNeed) {
// Convert it to the aiMaterial layout
@ -1253,9 +1230,8 @@ void ASEImporter::BuildMaterialIndices()
unsigned int iNum = 0;
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
ASE::Material &mat = mParser->m_vMaterials[iMat];
if (mat.bNeed)
{
ai_assert(NULL != mat.pcInstance);
if (mat.bNeed) {
ai_assert(nullptr != mat.pcInstance);
pcScene->mMaterials[iNum] = mat.pcInstance;
// Store the internal material, too
@ -1263,14 +1239,12 @@ void ASEImporter::BuildMaterialIndices()
// Iterate through all meshes and search for one which is using
// this top-level material index
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
{
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) {
aiMesh *mesh = pcScene->mMeshes[iMesh];
if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
iMat == (uintptr_t)mesh->mColors[3])
{
iMat == (uintptr_t)mesh->mColors[3]) {
mesh->mMaterialIndex = iNum;
mesh->mColors[3] = NULL;
mesh->mColors[3] = nullptr;
}
}
iNum++;
@ -1278,7 +1252,7 @@ void ASEImporter::BuildMaterialIndices()
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
ASE::Material &submat = mat.avSubMaterials[iSubMat];
if (submat.bNeed) {
ai_assert(NULL != submat.pcInstance);
ai_assert(nullptr != submat.pcInstance);
pcScene->mMaterials[iNum] = submat.pcInstance;
// Store the internal material, too
@ -1291,7 +1265,7 @@ void ASEImporter::BuildMaterialIndices()
if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
mesh->mMaterialIndex = iNum;
mesh->mColors[3] = NULL;
mesh->mColors[3] = nullptr;
}
}
iNum++;
@ -1307,13 +1281,11 @@ void ASEImporter::BuildMaterialIndices()
// Generate normal vectors basing on smoothing groups
bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) {
if (!mesh.mNormals.empty() && !configRecomputeNormals)
{
if (!mesh.mNormals.empty() && !configRecomputeNormals) {
// Check whether there are only uninitialized normals. If there are
// some, skip all normals from the file and compute them on our own
for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin(); qq != mesh.mNormals.end(); ++qq) {
if ((*qq).x || (*qq).y || (*qq).z)
{
if ((*qq).x || (*qq).y || (*qq).z) {
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -40,15 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Defines the helper data structures for importing ASE files */
#ifndef AI_ASEFILEHELPER_H_INC
#define AI_ASEFILEHELPER_H_INC
// public ASSIMP headers
#include <assimp/types.h>
#include <assimp/mesh.h>
#include <assimp/anim.h>
#include <assimp/mesh.h>
#include <assimp/types.h>
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
@ -57,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/qnan.h>
// ASE is quite similar to 3ds. We can reuse some structures
#include "3DS/3DSLoader.h"
#include "AssetLib/3DS/3DSLoader.h"
namespace Assimp {
namespace ASE {
@ -66,16 +65,15 @@ using namespace D3DS;
// ---------------------------------------------------------------------------
/** Helper structure representing an ASE material */
struct Material : public D3DS::Material
{
struct Material : public D3DS::Material {
//! Default constructor has been deleted
Material() = delete;
//! Constructor with explicit name
explicit Material(const std::string &name)
: D3DS::Material(name)
, pcInstance(NULL)
, bNeed (false) {
explicit Material(const std::string &name) :
D3DS::Material(name),
pcInstance(nullptr),
bNeed(false) {
// empty
}
@ -93,18 +91,15 @@ struct Material : public D3DS::Material
return *this;
}
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
Material(Material &&other) AI_NO_EXCEPT
: D3DS::Material(std::move(other))
, avSubMaterials(std::move(other.avSubMaterials))
, pcInstance(std::move(other.pcInstance))
, bNeed(std::move(other.bNeed))
{
: D3DS::Material(std::move(other)),
avSubMaterials(std::move(other.avSubMaterials)),
pcInstance(std::move(other.pcInstance)),
bNeed(std::move(other.bNeed)) {
other.pcInstance = nullptr;
}
Material &operator=(Material &&other) AI_NO_EXCEPT {
if (this == &other) {
return *this;
@ -121,10 +116,8 @@ struct Material : public D3DS::Material
return *this;
}
~Material() {}
//! Contains all sub materials of this material
std::vector<Material> avSubMaterials;
@ -140,8 +133,8 @@ struct Material : public D3DS::Material
struct Face : public FaceWithSmoothingGroup {
//! Default constructor. Initializes everything with 0
Face() AI_NO_EXCEPT
: iMaterial(DEFAULT_MATINDEX)
, iFace(0) {
: iMaterial(DEFAULT_MATINDEX),
iFace(0) {
// empty
}
@ -172,8 +165,8 @@ struct Bone {
Bone() = delete;
//! Construction from an existing name
explicit Bone( const std::string& name)
: mName(name) {
explicit Bone(const std::string &name) :
mName(name) {
// empty
}
@ -196,12 +189,13 @@ struct Animation {
TRACK = 0x0,
BEZIER = 0x1,
TCB = 0x2
} mRotationType, mScalingType, mPositionType;
} mRotationType,
mScalingType, mPositionType;
Animation() AI_NO_EXCEPT
: mRotationType (TRACK)
, mScalingType (TRACK)
, mPositionType (TRACK) {
: mRotationType(TRACK),
mScalingType(TRACK),
mPositionType(TRACK) {
// empty
}
@ -246,10 +240,8 @@ struct BaseNode {
} mType;
//! Construction from an existing name
BaseNode(Type _mType, const std::string &name)
: mType (_mType)
, mName (name)
, mProcessed (false) {
BaseNode(Type _mType, const std::string &name) :
mType(_mType), mName(name), mProcessed(false) {
// Set mTargetPosition to qnan
const ai_real qnan = get_qnan();
mTargetPosition.x = qnan;
@ -289,13 +281,8 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
Mesh() = delete;
//! Construction from an existing name
explicit Mesh(const std::string &name)
: BaseNode( BaseNode::Mesh, name )
, mVertexColors()
, mBoneVertices()
, mBones()
, iMaterialIndex(Face::DEFAULT_MATINDEX)
, bSkip (false) {
explicit Mesh(const std::string &name) :
BaseNode(BaseNode::Mesh, name), mVertexColors(), mBoneVertices(), mBones(), iMaterialIndex(Face::DEFAULT_MATINDEX), bSkip(false) {
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
this->mNumUVComponents[c] = 2;
}
@ -325,10 +312,8 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE light source */
struct Light : public BaseNode
{
enum LightType
{
struct Light : public BaseNode {
enum LightType {
OMNI,
TARGET,
FREE,
@ -339,17 +324,13 @@ struct Light : public BaseNode
Light() = delete;
//! Construction from an existing name
explicit Light(const std::string &name)
: BaseNode (BaseNode::Light, name)
, mLightType (OMNI)
, mColor (1.f,1.f,1.f)
, mIntensity (1.f) // light is white by default
, mAngle (45.f)
, mFalloff (0.f)
{
explicit Light(const std::string &name) :
BaseNode(BaseNode::Light, name), mLightType(OMNI), mColor(1.f, 1.f, 1.f), mIntensity(1.f) // light is white by default
,
mAngle(45.f),
mFalloff(0.f) {
}
LightType mLightType;
aiColor3D mColor;
ai_real mIntensity;
@ -359,10 +340,8 @@ struct Light : public BaseNode
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE camera */
struct Camera : public BaseNode
{
enum CameraType
{
struct Camera : public BaseNode {
enum CameraType {
FREE,
TARGET
};
@ -370,18 +349,16 @@ struct Camera : public BaseNode
//! Default constructor has been deleted
Camera() = delete;
//! Construction from an existing name
explicit Camera(const std::string &name)
: BaseNode (BaseNode::Camera, name)
, mFOV (0.75f) // in radians
, mNear (0.1f)
, mFar (1000.f) // could be zero
, mCameraType (FREE)
{
explicit Camera(const std::string &name) :
BaseNode(BaseNode::Camera, name), mFOV(0.75f) // in radians
,
mNear(0.1f),
mFar(1000.f) // could be zero
,
mCameraType(FREE) {
}
ai_real mFOV, mNear, mFar;
CameraType mCameraType;
};
@ -414,7 +391,6 @@ private:
}
public:
// -------------------------------------------------------------------
//! Construct a parser from a given input file which is
//! guaranteed to be terminated with zero.
@ -428,9 +404,7 @@ public:
//! Parses the file into the parsers internal representation
void Parse();
private:
// -------------------------------------------------------------------
//! Parse the *SCENE block in a file
void ParseLV1SceneBlock();
@ -646,7 +620,6 @@ private:
bool ParseString(std::string &out, const char *szName);
public:
//! Pointer to current data
const char *filePtr;
@ -695,9 +668,8 @@ public:
unsigned int iFileFormat;
};
} // Namespace ASE
} // Namespace ASSIMP
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_3DS_IMPORTER

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -61,10 +60,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <time.h>
#ifdef _WIN32
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4706)
#endif // _WIN32
#endif // _MSC_VER
namespace Assimp {
@ -269,7 +268,7 @@ private:
public:
AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) :
buffer(NULL),
buffer(nullptr),
magic(magic),
container(container),
cur_size(0),
@ -337,7 +336,7 @@ protected:
void WriteBinaryNode(IOStream *container, const aiNode *node) {
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE);
unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
unsigned int nb_metadata = (node->mMetaData != nullptr ? node->mMetaData->mNumProperties : 0);
Write<aiString>(&chunk, node->mName);
Write<aiMatrix4x4>(&chunk, node->mTransformation);
@ -745,7 +744,7 @@ public:
};
try {
time_t tt = time(NULL);
time_t tt = time(nullptr);
#if _WIN32
tm *p = gmtime(&tt);
#else
@ -791,7 +790,7 @@ public:
// Up to here the data is uncompressed. For compressed files, the rest
// is compressed using standard DEFLATE from zlib.
if (compressed) {
AssbinChunkWriter uncompressedStream(NULL, 0);
AssbinChunkWriter uncompressedStream(nullptr, 0);
WriteBinaryScene(&uncompressedStream, pScene);
uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
@ -826,8 +825,8 @@ void DumpSceneToAssbin(
AssbinFileWriter fileWriter(shortened, compressed);
fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
}
#ifdef _WIN32
#if _MSC_VER
#pragma warning(pop)
#endif // _WIN32
#endif // _MSC_VER
} // end of namespace Assimp

View File

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

View File

@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
// internal headers
#include "Assbin/AssbinLoader.h"
#include "AssetLib/Assbin/AssbinLoader.h"
#include "Common/assbin_chunks.h"
#include <assimp/MemoryIOWrapper.h>
#include <assimp/anim.h>
@ -604,7 +604,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
// Read node graph
//scene->mRootNode = new aiNode[1];
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL);
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr);
// Read all meshes
if (scene->mNumMeshes) {

View File

@ -9,6 +9,11 @@ For details, see http://sourceforge.net/projects/libb64
const int CHARS_PER_LINE = 72;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244)
#endif // _MSC_VER
void base64_init_encodestate(base64_encodestate* state_in)
{
state_in->step = step_A;
@ -107,3 +112,6 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
return (int)(codechar - code_out);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER

View File

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

View File

@ -9,16 +9,17 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/Exceptional.h>
#include <sstream>
#include <limits>
#include <cassert>
#include <limits>
#include <memory>
#include <sstream>
#define CURRENT_FORMAT_VERSION 100
@ -42,10 +43,8 @@ public:
Flag_WriteSpecialFloats = 0x2,
};
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
: out(out)
, first()
, flags(flags) {
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
out(out), first(), flags(flags) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale
buff.imbue(std::locale("C"));
}
@ -156,8 +155,7 @@ public:
void Delimit() {
if (!first) {
buff << ',';
}
else {
} else {
buff << ' ';
first = false;
}
@ -468,8 +466,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
}
out.EndArray();
}
else {
} else {
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
}
break;
@ -486,19 +483,15 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
}
break;
case aiPTI_String:
{
case aiPTI_String: {
aiString s;
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
out.SimpleValue(s);
}
break;
case aiPTI_Buffer:
{
} break;
case aiPTI_Buffer: {
// binary data is written as series of hex-encoded octets
out.SimpleValue(prop->mData, prop->mDataLength);
}
break;
} break;
default:
assert(false);
}
@ -525,8 +518,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
out.Key("data");
if (!ai.mHeight) {
out.SimpleValue(ai.pcData, ai.mWidth);
}
else {
} else {
out.StartArray();
for (unsigned int y = 0; y < ai.mHeight; ++y) {
out.StartArray(true);
@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
if (ai.mType != aiLightSource_POINT) {
out.Key("direction");
Write(out, ai.mDirection, false);
}
if (ai.mType != aiLightSource_DIRECTIONAL) {
@ -774,11 +765,10 @@ void Write(JSONWriter& out, const aiScene& ai) {
out.EndObj();
}
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
if (!str) {
//throw Assimp::DeadlyExportError("could not open output file");
throw DeadlyExportError("could not open output file");
}
// get a copy of the scene so we can modify it
@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
Write(s, *scenecopy_tmp);
}
catch (...) {
} catch (...) {
aiFreeScene(scenecopy_tmp);
throw;
}
aiFreeScene(scenecopy_tmp);
}
}
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -0,0 +1,659 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file AssxmlFileWriter.cpp
* @brief Implementation of Assxml file writer.
*/
#include "AssxmlFileWriter.h"
#include "PostProcessing/ProcessHelper.h"
#include <assimp/version.h>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <stdarg.h>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include <contrib/zlib/zlib.h>
#endif
#include <stdio.h>
#include <time.h>
#include <memory>
using namespace Assimp;
namespace Assimp {
namespace AssxmlFileWriter {
// -----------------------------------------------------------------------------------
static int ioprintf(IOStream *io, const char *format, ...) {
using namespace std;
if (nullptr == io) {
return -1;
}
static const int Size = 4096;
char sz[Size];
::memset(sz, '\0', Size);
va_list va;
va_start(va, format);
const unsigned int nSize = vsnprintf(sz, Size - 1, format, va);
ai_assert(nSize < Size);
va_end(va);
io->Write(sz, sizeof(char), nSize);
return nSize;
}
// -----------------------------------------------------------------------------------
// Convert a name to standard XML format
static void ConvertName(aiString &out, const aiString &in) {
out.length = 0;
for (unsigned int i = 0; i < in.length; ++i) {
switch (in.data[i]) {
case '<':
out.Append("&lt;");
break;
case '>':
out.Append("&gt;");
break;
case '&':
out.Append("&amp;");
break;
case '\"':
out.Append("&quot;");
break;
case '\'':
out.Append("&apos;");
break;
default:
out.data[out.length++] = in.data[i];
}
}
out.data[out.length] = 0;
}
// -----------------------------------------------------------------------------------
// Write a single node as text dump
static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
char prefix[512];
for (unsigned int i = 0; i < depth; ++i)
prefix[i] = '\t';
prefix[depth] = '\0';
const aiMatrix4x4 &m = node->mTransformation;
aiString name;
ConvertName(name, node->mName);
ioprintf(io, "%s<Node name=\"%s\"> \n"
"%s\t<Matrix4> \n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t</Matrix4> \n",
prefix, name.data, prefix,
prefix, m.a1, m.a2, m.a3, m.a4,
prefix, m.b1, m.b2, m.b3, m.b4,
prefix, m.c1, m.c2, m.c3, m.c4,
prefix, m.d1, m.d2, m.d3, m.d4, prefix);
if (node->mNumMeshes) {
ioprintf(io, "%s\t<MeshRefs num=\"%u\">\n%s\t",
prefix, node->mNumMeshes, prefix);
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
ioprintf(io, "%u ", node->mMeshes[i]);
}
ioprintf(io, "\n%s\t</MeshRefs>\n", prefix);
}
if (node->mNumChildren) {
ioprintf(io, "%s\t<NodeList num=\"%u\">\n",
prefix, node->mNumChildren);
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
WriteNode(node->mChildren[i], io, depth + 2);
}
ioprintf(io, "%s\t</NodeList>\n", prefix);
}
ioprintf(io, "%s</Node>\n", prefix);
}
// -----------------------------------------------------------------------------------
// Some chuncks of text will need to be encoded for XML
// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
static std::string encodeXML(const std::string &data) {
std::string buffer;
buffer.reserve(data.size());
for (size_t pos = 0; pos != data.size(); ++pos) {
switch (data[pos]) {
case '&': buffer.append("&amp;"); break;
case '\"': buffer.append("&quot;"); break;
case '\'': buffer.append("&apos;"); break;
case '<': buffer.append("&lt;"); break;
case '>': buffer.append("&gt;"); break;
default: buffer.append(&data[pos], 1); break;
}
}
return buffer;
}
// -----------------------------------------------------------------------------------
// Write a text model dump
static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) {
time_t tt = ::time(nullptr);
#if _WIN32
tm *p = gmtime(&tt);
#else
struct tm now;
tm *p = gmtime_r(&tt, &now);
#endif
ai_assert(nullptr != p);
std::string c = cmd;
std::string::size_type s;
// https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632
// -- not allowed in XML comments
while ((s = c.find("--")) != std::string::npos) {
c[s] = '?';
}
// write header
std::string header(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<ASSIMP format_id=\"1\">\n\n"
"<!-- XML Model dump produced by assimp dump\n"
" Library version: %u.%u.%u\n"
" Source: %s\n"
" Command line: %s\n"
" %s\n"
"-->"
" \n\n"
"<Scene flags=\"%u\" postprocessing=\"%u\">\n");
const unsigned int majorVersion(aiGetVersionMajor());
const unsigned int minorVersion(aiGetVersionMinor());
const unsigned int rev(aiGetVersionRevision());
const char *curtime(asctime(p));
ioprintf(io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u);
// write the node graph
WriteNode(scene->mRootNode, io, 0);
#if 0
// write cameras
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
aiCamera* cam = scene->mCameras[i];
ConvertName(name,cam->mName);
// camera header
ioprintf(io,"\t<Camera parent=\"%s\">\n"
"\t\t<Vector3 name=\"up\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"fov\" > %f </Float>\n"
"\t\t<Float name=\"aspect\" > %f </Float>\n"
"\t\t<Float name=\"near_clip\" > %f </Float>\n"
"\t\t<Float name=\"far_clip\" > %f </Float>\n"
"\t</Camera>\n",
name.data,
cam->mUp.x,cam->mUp.y,cam->mUp.z,
cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
}
// write lights
for (unsigned int i = 0; i < scene->mNumLights;++i) {
aiLight* l = scene->mLights[i];
ConvertName(name,l->mName);
// light header
ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
"\t\t<Vector3 name=\"diffuse\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"specular\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"ambient\" > %0 8f %0 8f %0 8f </Vector3>\n",
name.data,
(l->mType == aiLightSource_DIRECTIONAL ? "directional" :
(l->mType == aiLightSource_POINT ? "point" : "spot" )),
l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
if (l->mType != aiLightSource_DIRECTIONAL) {
ioprintf(io,
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"atten_cst\" > %f </Float>\n"
"\t\t<Float name=\"atten_lin\" > %f </Float>\n"
"\t\t<Float name=\"atten_sqr\" > %f </Float>\n",
l->mPosition.x,l->mPosition.y,l->mPosition.z,
l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
}
if (l->mType != aiLightSource_POINT) {
ioprintf(io,
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n",
l->mDirection.x,l->mDirection.y,l->mDirection.z);
}
if (l->mType == aiLightSource_SPOT) {
ioprintf(io,
"\t\t<Float name=\"cone_out\" > %f </Float>\n"
"\t\t<Float name=\"cone_inn\" > %f </Float>\n",
l->mAngleOuterCone,l->mAngleInnerCone);
}
ioprintf(io,"\t</Light>\n");
}
#endif
aiString name;
// write textures
if (scene->mNumTextures) {
ioprintf(io, "<TextureList num=\"%u\">\n", scene->mNumTextures);
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
aiTexture *tex = scene->mTextures[i];
bool compressed = (tex->mHeight == 0);
// mesh header
ioprintf(io, "\t<Texture width=\"%u\" height=\"%u\" compressed=\"%s\"> \n",
(compressed ? -1 : tex->mWidth), (compressed ? -1 : tex->mHeight),
(compressed ? "true" : "false"));
if (compressed) {
ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth);
if (!shortened) {
for (unsigned int n = 0; n < tex->mWidth; ++n) {
ioprintf(io, "\t\t\t%2x", reinterpret_cast<uint8_t *>(tex->pcData)[n]);
if (n && !(n % 50)) {
ioprintf(io, "\n");
}
}
}
} else if (!shortened) {
ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth * tex->mHeight * 4);
// const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1;
for (unsigned int y = 0; y < tex->mHeight; ++y) {
for (unsigned int x = 0; x < tex->mWidth; ++x) {
aiTexel *tx = tex->pcData + y * tex->mWidth + x;
unsigned int r = tx->r, g = tx->g, b = tx->b, a = tx->a;
ioprintf(io, "\t\t\t%2x %2x %2x %2x", r, g, b, a);
// group by four for readability
if (0 == (x + y * tex->mWidth) % 4) {
ioprintf(io, "\n");
}
}
}
}
ioprintf(io, "\t\t</Data>\n\t</Texture>\n");
}
ioprintf(io, "</TextureList>\n");
}
// write materials
if (scene->mNumMaterials) {
ioprintf(io, "<MaterialList num=\"%u\">\n", scene->mNumMaterials);
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
const aiMaterial *mat = scene->mMaterials[i];
ioprintf(io, "\t<Material>\n");
ioprintf(io, "\t\t<MatPropertyList num=\"%u\">\n", mat->mNumProperties);
for (unsigned int n = 0; n < mat->mNumProperties; ++n) {
const aiMaterialProperty *prop = mat->mProperties[n];
const char *sz = "";
if (prop->mType == aiPTI_Float) {
sz = "float";
} else if (prop->mType == aiPTI_Integer) {
sz = "integer";
} else if (prop->mType == aiPTI_String) {
sz = "string";
} else if (prop->mType == aiPTI_Buffer) {
sz = "binary_buffer";
}
ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
prop->mKey.data, sz,
::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
if (prop->mType == aiPTI_Float) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength / sizeof(float)));
for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(float); ++pp) {
ioprintf(io, "%f ", *((float *)(prop->mData + pp * sizeof(float))));
}
} else if (prop->mType == aiPTI_Integer) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength / sizeof(int)));
for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(int); ++pp) {
ioprintf(io, "%i ", *((int *)(prop->mData + pp * sizeof(int))));
}
} else if (prop->mType == aiPTI_Buffer) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength));
for (unsigned int pp = 0; pp < prop->mDataLength; ++pp) {
ioprintf(io, "%2x ", prop->mData[pp]);
if (pp && 0 == pp % 30) {
ioprintf(io, "\n\t\t\t\t");
}
}
} else if (prop->mType == aiPTI_String) {
ioprintf(io, ">\n\t\t\t\t\"%s\"", encodeXML(prop->mData + 4).c_str() /* skip length */);
}
ioprintf(io, "\n\t\t\t</MatProperty>\n");
}
ioprintf(io, "\t\t</MatPropertyList>\n");
ioprintf(io, "\t</Material>\n");
}
ioprintf(io, "</MaterialList>\n");
}
// write animations
if (scene->mNumAnimations) {
ioprintf(io, "<AnimationList num=\"%u\">\n", scene->mNumAnimations);
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
aiAnimation *anim = scene->mAnimations[i];
// anim header
ConvertName(name, anim->mName);
ioprintf(io, "\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
name.data, anim->mDuration, anim->mTicksPerSecond);
// write bone animation channels
if (anim->mNumChannels) {
ioprintf(io, "\t\t<NodeAnimList num=\"%u\">\n", anim->mNumChannels);
for (unsigned int n = 0; n < anim->mNumChannels; ++n) {
aiNodeAnim *nd = anim->mChannels[n];
// node anim header
ConvertName(name, nd->mNodeName);
ioprintf(io, "\t\t\t<NodeAnim node=\"%s\">\n", name.data);
if (!shortened) {
// write position keys
if (nd->mNumPositionKeys) {
ioprintf(io, "\t\t\t\t<PositionKeyList num=\"%u\">\n", nd->mNumPositionKeys);
for (unsigned int a = 0; a < nd->mNumPositionKeys; ++a) {
aiVectorKey *vc = nd->mPositionKeys + a;
ioprintf(io, "\t\t\t\t\t<PositionKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
}
ioprintf(io, "\t\t\t\t</PositionKeyList>\n");
}
// write scaling keys
if (nd->mNumScalingKeys) {
ioprintf(io, "\t\t\t\t<ScalingKeyList num=\"%u\">\n", nd->mNumScalingKeys);
for (unsigned int a = 0; a < nd->mNumScalingKeys; ++a) {
aiVectorKey *vc = nd->mScalingKeys + a;
ioprintf(io, "\t\t\t\t\t<ScalingKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
}
ioprintf(io, "\t\t\t\t</ScalingKeyList>\n");
}
// write rotation keys
if (nd->mNumRotationKeys) {
ioprintf(io, "\t\t\t\t<RotationKeyList num=\"%u\">\n", nd->mNumRotationKeys);
for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) {
aiQuatKey *vc = nd->mRotationKeys + a;
ioprintf(io, "\t\t\t\t\t<RotationKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z, vc->mValue.w);
}
ioprintf(io, "\t\t\t\t</RotationKeyList>\n");
}
}
ioprintf(io, "\t\t\t</NodeAnim>\n");
}
ioprintf(io, "\t\t</NodeAnimList>\n");
}
ioprintf(io, "\t</Animation>\n");
}
ioprintf(io, "</AnimationList>\n");
}
// write meshes
if (scene->mNumMeshes) {
ioprintf(io, "<MeshList num=\"%u\">\n", scene->mNumMeshes);
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
aiMesh *mesh = scene->mMeshes[i];
// const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1;
// mesh header
ioprintf(io, "\t<Mesh types=\"%s %s %s %s\" material_index=\"%u\">\n",
(mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""),
mesh->mMaterialIndex);
// bones
if (mesh->mNumBones) {
ioprintf(io, "\t\t<BoneList num=\"%u\">\n", mesh->mNumBones);
for (unsigned int n = 0; n < mesh->mNumBones; ++n) {
aiBone *bone = mesh->mBones[n];
ConvertName(name, bone->mName);
// bone header
ioprintf(io, "\t\t\t<Bone name=\"%s\">\n"
"\t\t\t\t<Matrix4> \n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t</Matrix4> \n",
name.data,
bone->mOffsetMatrix.a1, bone->mOffsetMatrix.a2, bone->mOffsetMatrix.a3, bone->mOffsetMatrix.a4,
bone->mOffsetMatrix.b1, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.b4,
bone->mOffsetMatrix.c1, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.c4,
bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3, bone->mOffsetMatrix.d4);
if (!shortened && bone->mNumWeights) {
ioprintf(io, "\t\t\t\t<WeightList num=\"%u\">\n", bone->mNumWeights);
// bone weights
for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
aiVertexWeight *wght = bone->mWeights + a;
ioprintf(io, "\t\t\t\t\t<Weight index=\"%u\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
wght->mVertexId, wght->mWeight);
}
ioprintf(io, "\t\t\t\t</WeightList>\n");
}
ioprintf(io, "\t\t\t</Bone>\n");
}
ioprintf(io, "\t\t</BoneList>\n");
}
// faces
if (!shortened && mesh->mNumFaces) {
ioprintf(io, "\t\t<FaceList num=\"%u\">\n", mesh->mNumFaces);
for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
aiFace &f = mesh->mFaces[n];
ioprintf(io, "\t\t\t<Face num=\"%u\">\n"
"\t\t\t\t",
f.mNumIndices);
for (unsigned int j = 0; j < f.mNumIndices; ++j)
ioprintf(io, "%u ", f.mIndices[j]);
ioprintf(io, "\n\t\t\t</Face>\n");
}
ioprintf(io, "\t\t</FaceList>\n");
}
// vertex positions
if (mesh->HasPositions()) {
ioprintf(io, "\t\t<Positions num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mVertices[n].x,
mesh->mVertices[n].y,
mesh->mVertices[n].z);
}
}
ioprintf(io, "\t\t</Positions>\n");
}
// vertex normals
if (mesh->HasNormals()) {
ioprintf(io, "\t\t<Normals num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mNormals[n].x,
mesh->mNormals[n].y,
mesh->mNormals[n].z);
}
}
ioprintf(io, "\t\t</Normals>\n");
}
// vertex tangents and bitangents
if (mesh->HasTangentsAndBitangents()) {
ioprintf(io, "\t\t<Tangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mTangents[n].x,
mesh->mTangents[n].y,
mesh->mTangents[n].z);
}
}
ioprintf(io, "\t\t</Tangents>\n");
ioprintf(io, "\t\t<Bitangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mBitangents[n].x,
mesh->mBitangents[n].y,
mesh->mBitangents[n].z);
}
}
ioprintf(io, "\t\t</Bitangents>\n");
}
// texture coordinates
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (!mesh->mTextureCoords[a])
break;
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" num_components=\"%u\"> \n", mesh->mNumVertices,
a, mesh->mNumUVComponents[a]);
if (!shortened) {
if (mesh->mNumUVComponents[a] == 3) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y,
mesh->mTextureCoords[a][n].z);
}
} else {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y);
}
}
}
ioprintf(io, "\t\t</TextureCoords>\n");
}
// vertex colors
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
if (!mesh->mColors[a])
break;
ioprintf(io, "\t\t<Colors num=\"%u\" set=\"%u\" num_components=\"4\"> \n", mesh->mNumVertices, a);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f %0 8f\n",
mesh->mColors[a][n].r,
mesh->mColors[a][n].g,
mesh->mColors[a][n].b,
mesh->mColors[a][n].a);
}
}
ioprintf(io, "\t\t</Colors>\n");
}
ioprintf(io, "\t</Mesh>\n");
}
ioprintf(io, "</MeshList>\n");
}
ioprintf(io, "</Scene>\n</ASSIMP>");
}
} // end of namespace AssxmlFileWriter
void DumpSceneToAssxml(
const char *pFile, const char *cmd, IOSystem *pIOSystem,
const aiScene *pScene, bool shortened) {
std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt"));
if (!file.get()) {
throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
}
AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened);
}
} // end of namespace Assimp

View File

@ -0,0 +1,744 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file B3DImporter.cpp
* @brief Implementation of the b3d importer class
*/
#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
// internal headers
#include "AssetLib/B3D/B3DImporter.h"
#include "PostProcessing/ConvertToLHProcess.h"
#include "PostProcessing/TextureTransform.h"
#include <assimp/StringUtils.h>
#include <assimp/anim.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp;
using namespace std;
static const aiImporterDesc desc = {
"BlitzBasic 3D Importer",
"",
"",
"http://www.blitzbasic.com/",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"b3d"
};
#ifdef _MSC_VER
#pragma warning(disable : 4018)
#endif
//#define DEBUG_B3D
template <typename T>
void DeleteAllBarePointers(std::vector<T> &x) {
for (auto p : x) {
delete p;
}
}
B3DImporter::~B3DImporter() {
}
// ------------------------------------------------------------------------------------------------
bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
size_t pos = pFile.find_last_of('.');
if (pos == string::npos) {
return false;
}
string ext = pFile.substr(pos + 1);
if (ext.size() != 3) {
return false;
}
return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D');
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc *B3DImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open B3D file ", pFile, ".");
}
// check whether the .b3d file is large enough to contain
// at least one chunk.
size_t fileSize = file->FileSize();
if (fileSize < 8) {
throw DeadlyImportError("B3D File is too small.");
}
_pos = 0;
_buf.resize(fileSize);
file->Read(&_buf[0], 1, fileSize);
_stack.clear();
ReadBB3D(pScene);
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Oops() {
throw DeadlyImportError("B3D Importer - INTERNAL ERROR");
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail(string str) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
#endif
throw DeadlyImportError("B3D Importer - error in B3D file data: ", str);
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte() {
if (_pos > _buf.size()) {
Fail("EOF");
}
return _buf[_pos++];
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadInt() {
if (_pos + 4 > _buf.size()) {
Fail("EOF");
}
int n;
memcpy(&n, &_buf[_pos], 4);
_pos += 4;
return n;
}
// ------------------------------------------------------------------------------------------------
float B3DImporter::ReadFloat() {
if (_pos + 4 > _buf.size()) {
Fail("EOF");
}
float n;
memcpy(&n, &_buf[_pos], 4);
_pos += 4;
return n;
}
// ------------------------------------------------------------------------------------------------
aiVector2D B3DImporter::ReadVec2() {
float x = ReadFloat();
float y = ReadFloat();
return aiVector2D(x, y);
}
// ------------------------------------------------------------------------------------------------
aiVector3D B3DImporter::ReadVec3() {
float x = ReadFloat();
float y = ReadFloat();
float z = ReadFloat();
return aiVector3D(x, y, z);
}
// ------------------------------------------------------------------------------------------------
aiQuaternion B3DImporter::ReadQuat() {
// (aramis_acg) Fix to adapt the loader to changed quat orientation
float w = -ReadFloat();
float x = ReadFloat();
float y = ReadFloat();
float z = ReadFloat();
return aiQuaternion(w, x, y, z);
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadString() {
if (_pos > _buf.size()) {
Fail("EOF");
}
string str;
while (_pos < _buf.size()) {
char c = (char)ReadByte();
if (!c) {
return str;
}
str += c;
}
return string();
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadChunk() {
string tag;
for (int i = 0; i < 4; ++i) {
tag += char(ReadByte());
}
#ifdef DEBUG_B3D
ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
#endif
unsigned sz = (unsigned)ReadInt();
_stack.push_back(_pos + sz);
return tag;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ExitChunk() {
_pos = _stack.back();
_stack.pop_back();
}
// ------------------------------------------------------------------------------------------------
size_t B3DImporter::ChunkSize() {
return _stack.back() - _pos;
}
// ------------------------------------------------------------------------------------------------
template <class T>
T *B3DImporter::to_array(const vector<T> &v) {
if (v.empty()) {
return 0;
}
T *p = new T[v.size()];
for (size_t i = 0; i < v.size(); ++i) {
p[i] = v[i];
}
return p;
}
// ------------------------------------------------------------------------------------------------
template <class T>
T **unique_to_array(vector<std::unique_ptr<T>> &v) {
if (v.empty()) {
return 0;
}
T **p = new T *[v.size()];
for (size_t i = 0; i < v.size(); ++i) {
p[i] = v[i].release();
}
return p;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTEXS() {
while (ChunkSize()) {
string name = ReadString();
/*int flags=*/ReadInt();
/*int blend=*/ReadInt();
/*aiVector2D pos=*/ReadVec2();
/*aiVector2D scale=*/ReadVec2();
/*float rot=*/ReadFloat();
_textures.push_back(name);
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBRUS() {
int n_texs = ReadInt();
if (n_texs < 0 || n_texs > 8) {
Fail("Bad texture count");
}
while (ChunkSize()) {
string name = ReadString();
aiVector3D color = ReadVec3();
float alpha = ReadFloat();
float shiny = ReadFloat();
/*int blend=**/ ReadInt();
int fx = ReadInt();
std::unique_ptr<aiMaterial> mat(new aiMaterial);
// Name
aiString ainame(name);
mat->AddProperty(&ainame, AI_MATKEY_NAME);
// Diffuse color
mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
// Opacity
mat->AddProperty(&alpha, 1, AI_MATKEY_OPACITY);
// Specular color
aiColor3D speccolor(shiny, shiny, shiny);
mat->AddProperty(&speccolor, 1, AI_MATKEY_COLOR_SPECULAR);
// Specular power
float specpow = shiny * 128;
mat->AddProperty(&specpow, 1, AI_MATKEY_SHININESS);
// Double sided
if (fx & 0x10) {
int i = 1;
mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
}
//Textures
for (int i = 0; i < n_texs; ++i) {
int texid = ReadInt();
if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) {
Fail("Bad texture id");
}
if (i == 0 && texid >= 0) {
aiString texname(_textures[texid]);
mat->AddProperty(&texname, AI_MATKEY_TEXTURE_DIFFUSE(0));
}
}
_materials.emplace_back(std::move(mat));
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadVRTS() {
_vflags = ReadInt();
_tcsets = ReadInt();
_tcsize = ReadInt();
if (_tcsets < 0 || _tcsets > 4 || _tcsize < 0 || _tcsize > 4) {
Fail("Bad texcoord data");
}
int sz = 12 + (_vflags & 1 ? 12 : 0) + (_vflags & 2 ? 16 : 0) + (_tcsets * _tcsize * 4);
size_t n_verts = ChunkSize() / sz;
int v0 = static_cast<int>(_vertices.size());
_vertices.resize(v0 + n_verts);
for (unsigned int i = 0; i < n_verts; ++i) {
Vertex &v = _vertices[v0 + i];
memset(v.bones, 0, sizeof(v.bones));
memset(v.weights, 0, sizeof(v.weights));
v.vertex = ReadVec3();
if (_vflags & 1) {
v.normal = ReadVec3();
}
if (_vflags & 2) {
ReadQuat(); //skip v 4bytes...
}
for (int j = 0; j < _tcsets; ++j) {
float t[4] = { 0, 0, 0, 0 };
for (int k = 0; k < _tcsize; ++k) {
t[k] = ReadFloat();
}
t[1] = 1 - t[1];
if (!j) {
v.texcoords = aiVector3D(t[0], t[1], t[2]);
}
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTRIS(int v0) {
int matid = ReadInt();
if (matid == -1) {
matid = 0;
} else if (matid < 0 || matid >= (int)_materials.size()) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("material id=", matid);
#endif
Fail("Bad material id");
}
std::unique_ptr<aiMesh> mesh(new aiMesh);
mesh->mMaterialIndex = matid;
mesh->mNumFaces = 0;
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
size_t n_tris = ChunkSize() / 12;
aiFace *face = mesh->mFaces = new aiFace[n_tris];
for (unsigned int i = 0; i < n_tris; ++i) {
int i0 = ReadInt() + v0;
int i1 = ReadInt() + v0;
int i2 = ReadInt() + v0;
if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
#endif
Fail("Bad triangle index");
continue;
}
face->mNumIndices = 3;
face->mIndices = new unsigned[3];
face->mIndices[0] = i0;
face->mIndices[1] = i1;
face->mIndices[2] = i2;
++mesh->mNumFaces;
++face;
}
_meshes.emplace_back(std::move(mesh));
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadMESH() {
/*int matid=*/ReadInt();
int v0 = static_cast<int>(_vertices.size());
while (ChunkSize()) {
string t = ReadChunk();
if (t == "VRTS") {
ReadVRTS();
} else if (t == "TRIS") {
ReadTRIS(v0);
}
ExitChunk();
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBONE(int id) {
while (ChunkSize()) {
int vertex = ReadInt();
float weight = ReadFloat();
if (vertex < 0 || vertex >= (int)_vertices.size()) {
Fail("Bad vertex index");
}
Vertex &v = _vertices[vertex];
for (int i = 0; i < 4; ++i) {
if (!v.weights[i]) {
v.bones[i] = static_cast<unsigned char>(id);
v.weights[i] = weight;
break;
}
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
vector<aiVectorKey> trans, scale;
vector<aiQuatKey> rot;
int flags = ReadInt();
while (ChunkSize()) {
int frame = ReadInt();
if (flags & 1) {
trans.push_back(aiVectorKey(frame, ReadVec3()));
}
if (flags & 2) {
scale.push_back(aiVectorKey(frame, ReadVec3()));
}
if (flags & 4) {
rot.push_back(aiQuatKey(frame, ReadQuat()));
}
}
if (flags & 1) {
nodeAnim->mNumPositionKeys = static_cast<unsigned int>(trans.size());
nodeAnim->mPositionKeys = to_array(trans);
}
if (flags & 2) {
nodeAnim->mNumScalingKeys = static_cast<unsigned int>(scale.size());
nodeAnim->mScalingKeys = to_array(scale);
}
if (flags & 4) {
nodeAnim->mNumRotationKeys = static_cast<unsigned int>(rot.size());
nodeAnim->mRotationKeys = to_array(rot);
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadANIM() {
/*int flags=*/ReadInt();
int frames = ReadInt();
float fps = ReadFloat();
std::unique_ptr<aiAnimation> anim(new aiAnimation);
anim->mDuration = frames;
anim->mTicksPerSecond = fps;
_animations.emplace_back(std::move(anim));
}
// ------------------------------------------------------------------------------------------------
aiNode *B3DImporter::ReadNODE(aiNode *parent) {
string name = ReadString();
aiVector3D t = ReadVec3();
aiVector3D s = ReadVec3();
aiQuaternion r = ReadQuat();
aiMatrix4x4 trans, scale, rot;
aiMatrix4x4::Translation(t, trans);
aiMatrix4x4::Scaling(s, scale);
rot = aiMatrix4x4(r.GetMatrix());
aiMatrix4x4 tform = trans * rot * scale;
int nodeid = static_cast<int>(_nodes.size());
aiNode *node = new aiNode(name);
_nodes.push_back(node);
node->mParent = parent;
node->mTransformation = tform;
std::unique_ptr<aiNodeAnim> nodeAnim;
vector<unsigned> meshes;
vector<aiNode *> children;
while (ChunkSize()) {
const string chunk = ReadChunk();
if (chunk == "MESH") {
unsigned int n = static_cast<unsigned int>(_meshes.size());
ReadMESH();
for (unsigned int i = n; i < static_cast<unsigned int>(_meshes.size()); ++i) {
meshes.push_back(i);
}
} else if (chunk == "BONE") {
ReadBONE(nodeid);
} else if (chunk == "ANIM") {
ReadANIM();
} else if (chunk == "KEYS") {
if (!nodeAnim) {
nodeAnim.reset(new aiNodeAnim);
nodeAnim->mNodeName = node->mName;
}
ReadKEYS(nodeAnim.get());
} else if (chunk == "NODE") {
aiNode *child = ReadNODE(node);
children.push_back(child);
}
ExitChunk();
}
if (nodeAnim) {
_nodeAnims.emplace_back(std::move(nodeAnim));
}
node->mNumMeshes = static_cast<unsigned int>(meshes.size());
node->mMeshes = to_array(meshes);
node->mNumChildren = static_cast<unsigned int>(children.size());
node->mChildren = to_array(children);
return node;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBB3D(aiScene *scene) {
_textures.clear();
_materials.clear();
_vertices.clear();
_meshes.clear();
DeleteAllBarePointers(_nodes);
_nodes.clear();
_nodeAnims.clear();
_animations.clear();
string t = ReadChunk();
if (t == "BB3D") {
int version = ReadInt();
if (!DefaultLogger::isNullLogger()) {
char dmp[128];
ai_snprintf(dmp, 128, "B3D file format version: %i", version);
ASSIMP_LOG_INFO(dmp);
}
while (ChunkSize()) {
const string chunk = ReadChunk();
if (chunk == "TEXS") {
ReadTEXS();
} else if (chunk == "BRUS") {
ReadBRUS();
} else if (chunk == "NODE") {
ReadNODE(0);
}
ExitChunk();
}
}
ExitChunk();
if (!_nodes.size()) {
Fail("No nodes");
}
if (!_meshes.size()) {
Fail("No meshes");
}
// Fix nodes/meshes/bones
for (size_t i = 0; i < _nodes.size(); ++i) {
aiNode *node = _nodes[i];
for (size_t j = 0; j < node->mNumMeshes; ++j) {
aiMesh *mesh = _meshes[node->mMeshes[j]].get();
int n_tris = mesh->mNumFaces;
int n_verts = mesh->mNumVertices = n_tris * 3;
aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = 0, *mc = 0;
if (_vflags & 1) {
mn = mesh->mNormals = new aiVector3D[n_verts];
}
if (_tcsets) {
mc = mesh->mTextureCoords[0] = new aiVector3D[n_verts];
}
aiFace *face = mesh->mFaces;
vector<vector<aiVertexWeight>> vweights(_nodes.size());
for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) {
for (int faceIndex = 0; faceIndex < 3; ++faceIndex) {
Vertex &v = _vertices[face->mIndices[faceIndex]];
*mv++ = v.vertex;
if (mn) *mn++ = v.normal;
if (mc) *mc++ = v.texcoords;
face->mIndices[faceIndex] = vertIdx + faceIndex;
for (int k = 0; k < 4; ++k) {
if (!v.weights[k])
break;
int bone = v.bones[k];
float weight = v.weights[k];
vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight));
}
}
++face;
}
vector<aiBone *> bones;
for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) {
vector<aiVertexWeight> &weights = vweights[weightIndx];
if (!weights.size()) {
continue;
}
aiBone *bone = new aiBone;
bones.push_back(bone);
aiNode *bnode = _nodes[weightIndx];
bone->mName = bnode->mName;
bone->mNumWeights = static_cast<unsigned int>(weights.size());
bone->mWeights = to_array(weights);
aiMatrix4x4 mat = bnode->mTransformation;
while (bnode->mParent) {
bnode = bnode->mParent;
mat = bnode->mTransformation * mat;
}
bone->mOffsetMatrix = mat.Inverse();
}
mesh->mNumBones = static_cast<unsigned int>(bones.size());
mesh->mBones = to_array(bones);
}
}
//nodes
scene->mRootNode = _nodes[0];
_nodes.clear(); // node ownership now belongs to scene
//material
if (!_materials.size()) {
_materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial));
}
scene->mNumMaterials = static_cast<unsigned int>(_materials.size());
scene->mMaterials = unique_to_array(_materials);
//meshes
scene->mNumMeshes = static_cast<unsigned int>(_meshes.size());
scene->mMeshes = unique_to_array(_meshes);
//animations
if (_animations.size() == 1 && _nodeAnims.size()) {
aiAnimation *anim = _animations.back().get();
anim->mNumChannels = static_cast<unsigned int>(_nodeAnims.size());
anim->mChannels = unique_to_array(_nodeAnims);
scene->mNumAnimations = static_cast<unsigned int>(_animations.size());
scene->mAnimations = unique_to_array(_animations);
}
// convert to RH
MakeLeftHandedProcess makeleft;
makeleft.Execute(scene);
FlipWindingOrderProcess flip;
flip.Execute(scene);
}
#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

View File

@ -0,0 +1,537 @@
/** Implementation of the BVH loader */
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
#include "BVHLoader.h"
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/TinyFormatter.h>
#include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/Importer.hpp>
#include <map>
#include <memory>
using namespace Assimp;
using namespace Assimp::Formatter;
static const aiImporterDesc desc = {
"BVH Importer (MoCap)",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"bvh"
};
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
template<typename... T>
AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) {
throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BVHLoader::BVHLoader() :
mLine(),
mAnimTickDuration(),
mAnimNumFrames(),
noSkeletonMesh() {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BVHLoader::~BVHLoader() {}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
// check file extension
const std::string extension = GetExtension(pFile);
if (extension == "bvh")
return true;
if ((!extension.length() || cs) && pIOHandler) {
const char *tokens[] = { "HIERARCHY" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
void BVHLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc *BVHLoader::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
mFileName = pFile;
// read file into memory
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open file ", pFile, ".");
}
size_t fileSize = file->FileSize();
if (fileSize == 0) {
throw DeadlyImportError("File is too small.");
}
mBuffer.resize(fileSize);
file->Read(&mBuffer.front(), 1, fileSize);
// start reading
mReader = mBuffer.begin();
mLine = 1;
ReadStructure(pScene);
if (!noSkeletonMesh) {
// build a dummy mesh for the skeleton so that we see something at least
SkeletonMeshBuilder meshBuilder(pScene);
}
// construct an animation from all the motion data we read
CreateAnimation(pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the file
void BVHLoader::ReadStructure(aiScene *pScene) {
// first comes hierarchy
std::string header = GetNextToken();
if (header != "HIERARCHY")
ThrowException("Expected header string \"HIERARCHY\".");
ReadHierarchy(pScene);
// then comes the motion data
std::string motion = GetNextToken();
if (motion != "MOTION")
ThrowException("Expected beginning of motion data \"MOTION\".");
ReadMotion(pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the hierarchy
void BVHLoader::ReadHierarchy(aiScene *pScene) {
std::string root = GetNextToken();
if (root != "ROOT")
ThrowException("Expected root node \"ROOT\".");
// Go read the hierarchy from here
pScene->mRootNode = ReadNode();
}
// ------------------------------------------------------------------------------------------------
// Reads a node and recursively its childs and returns the created node;
aiNode *BVHLoader::ReadNode() {
// first token is name
std::string nodeName = GetNextToken();
if (nodeName.empty() || nodeName == "{")
ThrowException("Expected node name, but found \"", nodeName, "\".");
// then an opening brace should follow
std::string openBrace = GetNextToken();
if (openBrace != "{")
ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node
aiNode *node = new aiNode(nodeName);
std::vector<aiNode *> childNodes;
// and create an bone entry for it
mNodes.push_back(Node(node));
Node &internNode = mNodes.back();
// now read the node's contents
std::string siteToken;
while (1) {
std::string token = GetNextToken();
// node offset to parent node
if (token == "OFFSET")
ReadNodeOffset(node);
else if (token == "CHANNELS")
ReadNodeChannels(internNode);
else if (token == "JOINT") {
// child node follows
aiNode *child = ReadNode();
child->mParent = node;
childNodes.push_back(child);
} else if (token == "End") {
// The real symbol is "End Site". Second part comes in a separate token
siteToken.clear();
siteToken = GetNextToken();
if (siteToken != "Site")
ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\".");
aiNode *child = ReadEndSite(nodeName);
child->mParent = node;
childNodes.push_back(child);
} else if (token == "}") {
// we're done with that part of the hierarchy
break;
} else {
// everything else is a parse error
ThrowException("Unknown keyword \"", token, "\".");
}
}
// add the child nodes if there are any
if (childNodes.size() > 0) {
node->mNumChildren = static_cast<unsigned int>(childNodes.size());
node->mChildren = new aiNode *[node->mNumChildren];
std::copy(childNodes.begin(), childNodes.end(), node->mChildren);
}
// and return the sub-hierarchy we built here
return node;
}
// ------------------------------------------------------------------------------------------------
// Reads an end node and returns the created node.
aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
// check opening brace
std::string openBrace = GetNextToken();
if (openBrace != "{")
ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node
aiNode *node = new aiNode("EndSite_" + pParentName);
// now read the node's contents. Only possible entry is "OFFSET"
std::string token;
while (1) {
token.clear();
token = GetNextToken();
// end node's offset
if (token == "OFFSET") {
ReadNodeOffset(node);
} else if (token == "}") {
// we're done with the end node
break;
} else {
// everything else is a parse error
ThrowException("Unknown keyword \"", token, "\".");
}
}
// and return the sub-hierarchy we built here
return node;
}
// ------------------------------------------------------------------------------------------------
// Reads a node offset for the given node
void BVHLoader::ReadNodeOffset(aiNode *pNode) {
// Offset consists of three floats to read
aiVector3D offset;
offset.x = GetNextTokenAsFloat();
offset.y = GetNextTokenAsFloat();
offset.z = GetNextTokenAsFloat();
// build a transformation matrix from it
pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x,
0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z,
0.0f, 0.0f, 0.0f, 1.0f);
}
// ------------------------------------------------------------------------------------------------
// Reads the animation channels for the given node
void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
// number of channels. Use the float reader because we're lazy
float numChannelsFloat = GetNextTokenAsFloat();
unsigned int numChannels = (unsigned int)numChannelsFloat;
for (unsigned int a = 0; a < numChannels; a++) {
std::string channelToken = GetNextToken();
if (channelToken == "Xposition")
pNode.mChannels.push_back(Channel_PositionX);
else if (channelToken == "Yposition")
pNode.mChannels.push_back(Channel_PositionY);
else if (channelToken == "Zposition")
pNode.mChannels.push_back(Channel_PositionZ);
else if (channelToken == "Xrotation")
pNode.mChannels.push_back(Channel_RotationX);
else if (channelToken == "Yrotation")
pNode.mChannels.push_back(Channel_RotationY);
else if (channelToken == "Zrotation")
pNode.mChannels.push_back(Channel_RotationZ);
else
ThrowException("Invalid channel specifier \"", channelToken, "\".");
}
}
// ------------------------------------------------------------------------------------------------
// Reads the motion data
void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
// Read number of frames
std::string tokenFrames = GetNextToken();
if (tokenFrames != "Frames:")
ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\".");
float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int)numFramesFloat;
// Read frame duration
std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken();
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\".");
mAnimTickDuration = GetNextTokenAsFloat();
// resize value vectors for each node
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames);
// now read all the data and store it in the corresponding node's value vector
for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) {
// on each line read the values for all nodes
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) {
// get as many values as the node has channels
for (unsigned int c = 0; c < it->mChannels.size(); ++c)
it->mChannelValues.push_back(GetNextTokenAsFloat());
}
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
}
}
// ------------------------------------------------------------------------------------------------
// Retrieves the next token
std::string BVHLoader::GetNextToken() {
// skip any preceding whitespace
while (mReader != mBuffer.end()) {
if (!isspace(*mReader))
break;
// count lines
if (*mReader == '\n')
mLine++;
++mReader;
}
// collect all chars till the next whitespace. BVH is easy in respect to that.
std::string token;
while (mReader != mBuffer.end()) {
if (isspace(*mReader))
break;
token.push_back(*mReader);
++mReader;
// little extra logic to make sure braces are counted correctly
if (token == "{" || token == "}")
break;
}
// empty token means end of file, which is just fine
return token;
}
// ------------------------------------------------------------------------------------------------
// Reads the next token as a float
float BVHLoader::GetNextTokenAsFloat() {
std::string token = GetNextToken();
if (token.empty())
ThrowException("Unexpected end of file while trying to read a float");
// check if the float is valid by testing if the atof() function consumed every char of the token
const char *ctoken = token.c_str();
float result = 0.0f;
ctoken = fast_atoreal_move<float>(ctoken, result);
if (ctoken != token.c_str() + token.length())
ThrowException("Expected a floating point number, but found \"", token, "\".");
return result;
}
// ------------------------------------------------------------------------------------------------
// Constructs an animation for the motion data and stores it in the given scene
void BVHLoader::CreateAnimation(aiScene *pScene) {
// create the animation
pScene->mNumAnimations = 1;
pScene->mAnimations = new aiAnimation *[1];
aiAnimation *anim = new aiAnimation;
pScene->mAnimations[0] = anim;
// put down the basic parameters
anim->mName.Set("Motion");
anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration);
anim->mDuration = double(mAnimNumFrames - 1);
// now generate the tracks for all nodes
anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
// FIX: set the array elements to nullptr to ensure proper deletion if an exception is thrown
for (unsigned int i = 0; i < anim->mNumChannels; ++i)
anim->mChannels[i] = nullptr;
for (unsigned int a = 0; a < anim->mNumChannels; a++) {
const Node &node = mNodes[a];
const std::string nodeName = std::string(node.mNode->mName.data);
aiNodeAnim *nodeAnim = new aiNodeAnim;
anim->mChannels[a] = nodeAnim;
nodeAnim->mNodeName.Set(nodeName);
std::map<BVHLoader::ChannelType, int> channelMap;
//Build map of channels
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
channelMap[node.mChannels[channel]] = channel;
}
// translational part, if given
if (node.mChannels.size() == 6) {
nodeAnim->mNumPositionKeys = mAnimNumFrames;
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
aiVectorKey *poskey = nodeAnim->mPositionKeys;
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
poskey->mTime = double(fr);
// Now compute all translations
for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
//Find channel in node
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
if (mapIter == channelMap.end())
throw DeadlyImportError("Missing position channel in node ", nodeName);
else {
int channelIdx = mapIter->second;
switch (channel) {
case Channel_PositionX:
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionY:
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionZ:
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
default:
break;
}
}
}
++poskey;
}
} else {
// if no translation part is given, put a default sequence
aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
nodeAnim->mNumPositionKeys = 1;
nodeAnim->mPositionKeys = new aiVectorKey[1];
nodeAnim->mPositionKeys[0].mTime = 0.0;
nodeAnim->mPositionKeys[0].mValue = nodePos;
}
// rotation part. Always present. First find value offsets
{
// Then create the number of rotation keys
nodeAnim->mNumRotationKeys = mAnimNumFrames;
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
aiMatrix4x4 temp;
aiMatrix3x3 rotMatrix;
for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) {
switch (node.mChannels[channelIdx]) {
case Channel_RotationX:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
case Channel_RotationY:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
case Channel_RotationZ:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
default:
break;
}
}
rotkey->mTime = double(fr);
rotkey->mValue = aiQuaternion(rotMatrix);
++rotkey;
}
}
// scaling part. Always just a default track
{
nodeAnim->mNumScalingKeys = 1;
nodeAnim->mScalingKeys = new aiVectorKey[1];
nodeAnim->mScalingKeys[0].mTime = 0.0;
nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f);
}
}
}
#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER

View File

@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiNode;
namespace Assimp
{
namespace Assimp {
// --------------------------------------------------------------------------------
/** Loader class to read Motion Capturing data from a .bvh file.
@ -63,12 +62,10 @@ namespace Assimp
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
* inside the loader just to be able to see something.
*/
class BVHLoader : public BaseImporter
{
class BVHLoader : public BaseImporter {
/** Possible animation channels for which the motion data holds the values */
enum ChannelType
{
enum ChannelType {
Channel_PositionX,
Channel_PositionY,
Channel_PositionZ,
@ -78,21 +75,19 @@ class BVHLoader : public BaseImporter
};
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
struct Node
{
struct Node {
const aiNode *mNode;
std::vector<ChannelType> mChannels;
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
Node()
: mNode(nullptr)
{ }
Node() :
mNode(nullptr) {}
explicit Node( const aiNode* pNode) : mNode( pNode) { }
explicit Node(const aiNode *pNode) :
mNode(pNode) {}
};
public:
BVHLoader();
~BVHLoader();
@ -105,8 +100,6 @@ public:
const aiImporterDesc *GetInfo() const;
protected:
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
@ -141,7 +134,8 @@ protected:
float GetNextTokenAsFloat();
/** 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 */
void CreateAnimation(aiScene *pScene);

View File

@ -42,22 +42,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Conversion of Blender's new BMesh stuff
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderBMesh.h"
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderBMesh.h"
#include "BlenderTessellator.h"
namespace Assimp
{
template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
{
namespace Assimp {
template <>
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
static auto prefix = "BLEND_BMESH: ";
return prefix;
}
}
} // namespace Assimp
using namespace Assimp;
using namespace Assimp::Blender;
@ -66,32 +64,28 @@ using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
BMesh(mesh),
triMesh( NULL )
{
triMesh(nullptr) {
ai_assert(nullptr != mesh);
}
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::~BlenderBMeshConverter( )
{
BlenderBMeshConverter::~BlenderBMeshConverter() {
DestroyTriMesh();
}
// ------------------------------------------------------------------------------------------------
bool BlenderBMeshConverter::ContainsBMesh( ) const
{
bool BlenderBMeshConverter::ContainsBMesh() const {
// TODO - Should probably do some additional verification here
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
}
// ------------------------------------------------------------------------------------------------
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
{
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
AssertValidMesh();
AssertValidSizes();
PrepareTriMesh();
for ( int i = 0; i < BMesh->totpoly; ++i )
{
for (int i = 0; i < BMesh->totpoly; ++i) {
const MPoly &poly = BMesh->mpoly[i];
ConvertPolyToFaces(poly);
}
@ -100,32 +94,25 @@ const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidMesh( )
{
if ( !ContainsBMesh( ) )
{
void BlenderBMeshConverter::AssertValidMesh() {
if (!ContainsBMesh()) {
ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidSizes( )
{
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
{
void BlenderBMeshConverter::AssertValidSizes() {
if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
ThrowException("BMesh poly array has incorrect size");
}
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
{
if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
ThrowException("BMesh loop array has incorrect size");
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::PrepareTriMesh( )
{
if ( triMesh )
{
void BlenderBMeshConverter::PrepareTriMesh() {
if (triMesh) {
DestroyTriMesh();
}
@ -135,34 +122,27 @@ void BlenderBMeshConverter::PrepareTriMesh( )
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::DestroyTriMesh( )
{
void BlenderBMeshConverter::DestroyTriMesh() {
delete triMesh;
triMesh = NULL;
triMesh = nullptr;
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
{
void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
if ( poly.totloop == 3 || poly.totloop == 4 )
{
if (poly.totloop == 3 || poly.totloop == 4) {
AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0);
// UVs are optional, so only convert when present.
if ( BMesh->mloopuv.size() )
{
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
{
if (BMesh->mloopuv.size()) {
if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
ThrowException("BMesh uv loop array has incorrect size");
}
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0);
}
}
else if ( poly.totloop > 4 )
{
} else if (poly.totloop > 4) {
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
BlenderTessellatorGL tessGL(*this);
tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
@ -174,13 +154,13 @@ void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
{
void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
MFace face;
face.v1 = v1;
face.v2 = v2;
face.v3 = v3;
face.v4 = v4;
face.flag = 0;
// TODO - Work out how materials work
face.mat_nr = 0;
triMesh->mface.push_back(face);
@ -188,15 +168,13 @@ void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
{
void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) {
MTFace mtface;
memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
if ( uv4 )
{
if (uv4) {
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
}

View File

@ -0,0 +1,181 @@
#include "BlenderCustomData.h"
#include "BlenderDNA.h"
#include <array>
#include <functional>
namespace Assimp {
namespace Blender {
/**
* @brief read/convert of Structure array to memory
*/
template <typename T>
bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
for (size_t i = 0; i < cnt; ++i) {
T read;
s.Convert(read, db);
*p = read;
p++;
}
return true;
}
/**
* @brief pointer to function read memory for n CustomData types
*/
typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db);
typedef ElemBase *(*PCreate)(const size_t cnt);
typedef void (*PDestroy)(ElemBase *);
#define IMPL_STRUCT_READ(ty) \
bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
ty *ptr = dynamic_cast<ty *>(v); \
if (nullptr == ptr) { \
return false; \
} \
return read<ty>(db.dna[#ty], ptr, cnt, db); \
}
#define IMPL_STRUCT_CREATE(ty) \
ElemBase *create##ty(const size_t cnt) { \
return new ty[cnt]; \
}
#define IMPL_STRUCT_DESTROY(ty) \
void destroy##ty(ElemBase *pE) { \
ty *p = dynamic_cast<ty *>(pE); \
delete[] p; \
}
/**
* @brief helper macro to define Structure functions
*/
#define IMPL_STRUCT(ty) \
IMPL_STRUCT_READ(ty) \
IMPL_STRUCT_CREATE(ty) \
IMPL_STRUCT_DESTROY(ty)
// supported structures for CustomData
IMPL_STRUCT(MVert)
IMPL_STRUCT(MEdge)
IMPL_STRUCT(MFace)
IMPL_STRUCT(MTFace)
IMPL_STRUCT(MTexPoly)
IMPL_STRUCT(MLoopUV)
IMPL_STRUCT(MLoopCol)
IMPL_STRUCT(MPoly)
IMPL_STRUCT(MLoop)
/**
* @brief describes the size of data and the read function to be used for single CustomerData.type
*/
struct CustomDataTypeDescription {
PRead Read; ///< function to read one CustomData type element
PCreate Create; ///< function to allocate n type elements
PDestroy Destroy;
CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) :
Read(read), Create(create), Destroy(destroy) {}
};
/**
* @brief helper macro to define Structure type specific CustomDataTypeDescription
* @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function
*/
#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \
CustomDataTypeDescription { &read##ty, &create##ty, &destroy##ty }
/**
* @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type
*/
#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \
CustomDataTypeDescription { nullptr, nullptr, nullptr }
/**
* @brief descriptors for data pointed to from CustomDataLayer.data
* @note some of the CustomData uses already well defined Structures
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
* use a special readfunction for that cases
*/
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION } };
bool isValidCustomDataType(const int cdtype) {
return cdtype >= 0 && cdtype < CD_NUMTYPES;
}
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) {
throw Error("CustomData.type ", cdtype, " out of index");
}
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
// allocate cnt elements and parse them from file
out.reset(cdtd.Create(cnt), cdtd.Destroy);
return cdtd.Read(out.get(), cnt, db);
}
return false;
}
std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
if (it->get()->type == cdtype && name == it->get()->name) {
return *it;
}
}
return nullptr;
}
const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
if (pLayer && pLayer->data) {
return pLayer->data.get();
}
return nullptr;
}
} // namespace Blender
} // namespace Assimp

View File

@ -45,12 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* serialized set of data structures.
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include <assimp/StreamReader.h>
#include <assimp/fast_atof.h>
#include <assimp/TinyFormatter.h>
#include <assimp/fast_atof.h>
using namespace Assimp;
using namespace Assimp::Blender;
@ -72,8 +71,7 @@ struct Type {
};
// ------------------------------------------------------------------------------------------------
void DNAParser::Parse ()
{
void DNAParser::Parse() {
StreamReaderAny &stream = *db.reader.get();
DNA &dna = db.dna;
@ -94,7 +92,8 @@ void DNAParser::Parse ()
}
// type dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "TYPE")) {
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
}
@ -107,7 +106,8 @@ void DNAParser::Parse ()
}
// type length dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "TLEN")) {
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
}
@ -117,7 +117,8 @@ void DNAParser::Parse ()
}
// structures dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "STRC")) {
throw DeadlyImportError("BlenderDNA: Expected STRC field");
}
@ -129,10 +130,7 @@ void DNAParser::Parse ()
uint16_t n = stream.GetI2();
if (n >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure name" ,n,
" (there are only ", types.size(), " entries)"
));
throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)");
}
// maintain separate indexes
@ -141,7 +139,6 @@ void DNAParser::Parse ()
dna.structures.push_back(Structure());
Structure &s = dna.structures.back();
s.name = types[n].name;
//s.index = dna.structures.size()-1;
n = stream.GetI2();
s.fields.reserve(n);
@ -151,10 +148,7 @@ void DNAParser::Parse ()
uint16_t j = stream.GetI2();
if (j >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"
));
throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)");
}
s.fields.push_back(Field());
Field &f = s.fields.back();
@ -165,10 +159,7 @@ void DNAParser::Parse ()
j = stream.GetI2();
if (j >= names.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"
));
throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)");
}
f.name = names[j];
@ -190,10 +181,7 @@ void DNAParser::Parse ()
if (*f.name.rbegin() == ']') {
const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) {
throw DeadlyImportError((format(),
"BlenderDNA: Encountered invalid array declaration ",
f.name
));
throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name);
}
f.flags |= FieldFlag_Array;
@ -220,13 +208,11 @@ void DNAParser::Parse ()
dna.RegisterConverters();
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
#include <fstream>
// ------------------------------------------------------------------------------------------------
void DNA :: DumpToFile()
{
void DNA ::DumpToFile() {
// we don't bother using the VFS here for this is only for debugging.
// (and all your bases are belong to us).
@ -235,8 +221,10 @@ void DNA :: DumpToFile()
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
return;
}
f << "Field format: type name offset size" << "\n";
f << "Structure format: name size" << "\n";
f << "Field format: type name offset size"
<< "\n";
f << "Structure format: name size"
<< "\n";
for (const Structure &s : structures) {
f << s.name << " " << s.size << "\n\n";
@ -254,9 +242,7 @@ void DNA :: DumpToFile()
// ------------------------------------------------------------------------------------------------
/*static*/ void DNA ::ExtractArraySize(
const std::string &out,
size_t array_sizes[2]
)
{
size_t array_sizes[2]) {
array_sizes[0] = array_sizes[1] = 1;
std::string::size_type pos = out.find('[');
if (pos++ == std::string::npos) {
@ -274,9 +260,7 @@ void DNA :: DumpToFile()
// ------------------------------------------------------------------------------------------------
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
const Structure &structure,
const FileDatabase& db
) const
{
const FileDatabase &db) const {
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
if (it == converters.end()) {
return std::shared_ptr<ElemBase>();
@ -292,16 +276,14 @@ std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
const Structure &structure,
const FileDatabase & /*db*/
) const
{
) const {
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
return it == converters.end() ? FactoryPair() : (*it).second;
}
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
// ------------------------------------------------------------------------------------------------
void DNA :: AddPrimitiveStructures()
{
void DNA ::AddPrimitiveStructures() {
// NOTE: these are just dummies. Their presence enforces
// Structure::Convert<target_type> to be called on these
// empty structures. These converters are special
@ -320,19 +302,16 @@ void DNA :: AddPrimitiveStructures()
structures.back().name = "short";
structures.back().size = 2;
indices["char"] = structures.size();
structures.push_back(Structure());
structures.back().name = "char";
structures.back().size = 1;
indices["float"] = structures.size();
structures.push_back(Structure());
structures.back().name = "float";
structures.back().size = 4;
indices["double"] = structures.size();
structures.push_back(Structure());
structures.back().name = "double";
@ -342,8 +321,7 @@ void DNA :: AddPrimitiveStructures()
}
// ------------------------------------------------------------------------------------------------
void SectionParser :: Next()
{
void SectionParser ::Next() {
stream.SetCurrentPos(current.start + current.size);
const char tmp[] = {
@ -366,10 +344,8 @@ void SectionParser :: Next()
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
ASSIMP_LOG_DEBUG(current.id);
ASSIMP_LOG_VERBOSE_DEBUG(current.id);
#endif
}
#endif

View File

@ -49,10 +49,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/BaseImporter.h>
#include <assimp/StreamReader.h>
#include <assimp/DefaultLogger.hpp>
#include <stdint.h>
#include <memory>
#include <assimp/DefaultLogger.hpp>
#include <map>
#include <memory>
// enable verbose log output. really verbose, so be careful.
#ifdef ASSIMP_BUILD_DEBUG
@ -63,7 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
template <bool,bool> class StreamReader;
template <bool, bool>
class StreamReader;
typedef StreamReader<true, true> StreamReaderAny;
namespace Blender {
@ -82,9 +83,9 @@ class ObjectCache;
* ancestry. */
// -------------------------------------------------------------------------------
struct Error : DeadlyImportError {
Error (const std::string& s)
: DeadlyImportError(s) {
// empty
template <typename... T>
explicit Error(T &&...args) :
DeadlyImportError(args...) {
}
};
@ -93,9 +94,8 @@ struct Error : DeadlyImportError {
* descendents. It serves as base class for all data structure fields. */
// -------------------------------------------------------------------------------
struct ElemBase {
ElemBase()
: dna_type(nullptr)
{
ElemBase() :
dna_type(nullptr) {
// empty
}
@ -120,8 +120,8 @@ struct ElemBase {
* they used to point to.*/
// -------------------------------------------------------------------------------
struct Pointer {
Pointer()
: val() {
Pointer() :
val() {
// empty
}
uint64_t val;
@ -131,8 +131,8 @@ struct Pointer {
/** Represents a generic offset within a BLEND file */
// -------------------------------------------------------------------------------
struct FileOffset {
FileOffset()
: val() {
FileOffset() :
val() {
// empty
}
uint64_t val;
@ -186,7 +186,7 @@ struct Field {
};
// -------------------------------------------------------------------------------
/** Range of possible behaviours for fields absend in the input file. Some are
/** Range of possible behaviors for fields absence in the input file. Some are
* mission critical so we need them, while others can silently be default
* initialized and no animations are harmed. */
// -------------------------------------------------------------------------------
@ -212,16 +212,15 @@ enum ErrorPolicy {
* meaningful contents. */
// -------------------------------------------------------------------------------
class Structure {
template <template <typename> class> friend class ObjectCache;
template <template <typename> class>
friend class ObjectCache;
public:
Structure()
: cache_idx(static_cast<size_t>(-1) ){
Structure() :
cache_idx(static_cast<size_t>(-1)) {
// empty
}
public:
// publicly accessible members
std::string name;
vector<Field> fields;
@ -229,11 +228,9 @@ public:
size_t size;
public:
// --------------------------------------------------------
/** Access a field of the structure by its canonical name. The pointer version
* returns NULL on failure while the reference version raises an import error. */
* returns nullptr on failure while the reference version raises an import error. */
inline const Field &operator[](const std::string &ss) const;
inline const Field *Get(const std::string &ss) const;
@ -251,8 +248,6 @@ public:
return name != other.name;
}
public:
// --------------------------------------------------------
/** Try to read an instance of the structure from the stream
* and attempt to convert to `T`. This is done by
@ -260,7 +255,8 @@ public:
* a compiler complain is the result.
* @param dest Destination value to be written
* @param db File database, including input stream. */
template <typename T> void Convert (T& dest, const FileDatabase& db) const;
template <typename T>
void Convert(T &dest, const FileDatabase &db) const;
// --------------------------------------------------------
// generic converter
@ -269,9 +265,8 @@ public:
// --------------------------------------------------------
// generic allocator
template <typename T> std::shared_ptr<ElemBase> Allocate() const;
template <typename T>
std::shared_ptr<ElemBase> Allocate() const;
// --------------------------------------------------------
// field parsing for 1d arrays
@ -332,7 +327,6 @@ public:
bool ReadCustomDataPtr(std::shared_ptr<ElemBase> &out, int cdtype, const char *name, const FileDatabase &db) const;
private:
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(TOUT<T> &out, const Pointer &ptrval,
@ -354,17 +348,18 @@ private:
const FileDatabase &db) const;
private:
// ------------------------------------------------------------------------------
template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
template <typename T>
T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
out = std::shared_ptr<T>(new T());
s = 1;
return out.get();
}
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
template <typename T>
T *_allocate(vector<T> &out, size_t &s) const {
out.resize(s);
return s ? &out.front() : NULL;
return s ? &out.front() : nullptr;
}
// --------------------------------------------------------
@ -372,14 +367,14 @@ private:
struct _defaultInitializer {
template <typename T, unsigned int N>
void operator ()(T (& out)[N], const char* = NULL) {
void operator()(T (&out)[N], const char * = nullptr) {
for (unsigned int i = 0; i < N; ++i) {
out[i] = T();
}
}
template <typename T, unsigned int N, unsigned int M>
void operator ()(T (& out)[N][M], const char* = NULL) {
void operator()(T (&out)[N][M], const char * = nullptr) {
for (unsigned int i = 0; i < N; ++i) {
for (unsigned int j = 0; j < M; ++j) {
out[i][j] = T();
@ -388,18 +383,18 @@ private:
}
template <typename T>
void operator ()(T& out, const char* = NULL) {
void operator()(T &out, const char * = nullptr) {
out = T();
}
};
private:
mutable size_t cache_idx;
};
// --------------------------------------------------------
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
template <>
struct Structure::_defaultInitializer<ErrorPolicy_Warn> {
template <typename T>
void operator()(T &out, const char *reason = "<add reason>") {
@ -410,7 +405,8 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
}
};
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
template <>
struct Structure::_defaultInitializer<ErrorPolicy_Fail> {
template <typename T>
void operator()(T & /*out*/, const char * = "") {
@ -421,13 +417,12 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
};
// -------------------------------------------------------------------------------------------------------
template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
template <>
inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
const Pointer &ptrval,
const FileDatabase &db,
const Field &f,
bool
) const;
bool) const;
// -------------------------------------------------------------------------------
/** Represents the full data structure information for a single BLEND file.
@ -435,14 +430,11 @@ template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(st
* #DNAParser does the reading and represents currently the only place where
* DNA is altered.*/
// -------------------------------------------------------------------------------
class DNA
{
class DNA {
public:
typedef void (Structure::*ConvertProcPtr)(
std::shared_ptr<ElemBase> in,
const FileDatabase&
) const;
const FileDatabase &) const;
typedef std::shared_ptr<ElemBase> (
Structure::*AllocProcPtr)() const;
@ -450,15 +442,13 @@ public:
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
public:
std::map<std::string, FactoryPair> converters;
vector<Structure> structures;
std::map<std::string, size_t> indices;
public:
// --------------------------------------------------------
/** Access a structure by its canonical name, the pointer version returns NULL on failure
/** Access a structure by its canonical name, the pointer version returns nullptr on failure
* while the reference version raises an error. */
inline const Structure &operator[](const std::string &ss) const;
inline const Structure *Get(const std::string &ss) const;
@ -468,7 +458,6 @@ public:
inline const Structure &operator[](const size_t i) const;
public:
// --------------------------------------------------------
/** Add structure definitions for all the primitive types,
* i.e. integer, short, char, float */
@ -483,7 +472,6 @@ public:
* known at compile time (consier Object::data).*/
void RegisterConverters();
// --------------------------------------------------------
/** Take an input blob from the stream, interpret it according to
* a its structure name and convert it to the intermediate
@ -493,8 +481,7 @@ public:
* @return A null pointer if no appropriate converter is available.*/
std::shared_ptr<ElemBase> ConvertBlobToStructure(
const Structure &structure,
const FileDatabase& db
) const;
const FileDatabase &db) const;
// --------------------------------------------------------
/** Find a suitable conversion function for a given Structure.
@ -506,9 +493,7 @@ public:
* @return A null pointer in .first if no appropriate converter is available.*/
FactoryPair GetBlobToStructureConverter(
const Structure &structure,
const FileDatabase& db
) const;
const FileDatabase &db) const;
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
// --------------------------------------------------------
@ -528,24 +513,28 @@ public:
* encountered. */
static void ExtractArraySize(
const std::string &out,
size_t array_sizes[2]
);
size_t array_sizes[2]);
};
// special converters for primitive types
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
template <>
inline void Structure ::Convert<int>(int &dest, const FileDatabase &db) const;
template <>
inline void Structure ::Convert<short>(short &dest, const FileDatabase &db) const;
template <>
inline void Structure ::Convert<char>(char &dest, const FileDatabase &db) const;
template <>
inline void Structure ::Convert<float>(float &dest, const FileDatabase &db) const;
template <>
inline void Structure ::Convert<double>(double &dest, const FileDatabase &db) const;
template <>
inline void Structure ::Convert<Pointer>(Pointer &dest, const FileDatabase &db) const;
// -------------------------------------------------------------------------------
/** Describes a master file block header. Each master file sections holds n
* elements of a certain SDNA structure (or otherwise unspecified data). */
// -------------------------------------------------------------------------------
struct FileBlockHead
{
struct FileBlockHead {
// points right after the header of the file block
StreamReaderAny::pos start;
@ -561,8 +550,6 @@ struct FileBlockHead
// number of structure instances to follow
size_t num;
// file blocks are sorted by address to quickly locate specific memory addresses
bool operator<(const FileBlockHead &o) const {
return address.val < o.address.val;
@ -582,45 +569,36 @@ inline bool operator< (const Pointer& a, const Pointer& b) {
// -------------------------------------------------------------------------------
/** Utility to read all master file blocks in turn. */
// -------------------------------------------------------------------------------
class SectionParser
{
class SectionParser {
public:
// --------------------------------------------------------
/** @param stream Inout stream, must point to the
* first section in the file. Call Next() once
* to have it read.
* @param ptr64 Pointer size in file is 64 bits? */
SectionParser(StreamReaderAny& stream,bool ptr64)
: stream(stream)
, ptr64(ptr64)
{
SectionParser(StreamReaderAny &stream, bool ptr64) :
stream(stream), ptr64(ptr64) {
current.size = current.start = 0;
}
public:
// --------------------------------------------------------
const FileBlockHead &GetCurrent() const {
return current;
}
public:
// --------------------------------------------------------
/** Advance to the next section.
* @throw DeadlyImportError if the last chunk was passed. */
void Next();
public:
FileBlockHead current;
StreamReaderAny &stream;
bool ptr64;
};
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
// -------------------------------------------------------------------------------
/** Import statistics, i.e. number of file blocks read*/
@ -628,17 +606,13 @@ public:
class Statistics {
public:
Statistics ()
: fields_read ()
, pointers_resolved ()
, cache_hits ()
Statistics() :
fields_read(), pointers_resolved(), cache_hits()
// , blocks_read ()
, cached_objects ()
{}
,
cached_objects() {}
public:
/** total number of fields we read */
unsigned int fields_read;
@ -662,17 +636,13 @@ public:
* avoids circular references and avoids object duplication. */
// -------------------------------------------------------------------------------
template <template <typename> class TOUT>
class ObjectCache
{
class ObjectCache {
public:
typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
public:
ObjectCache(const FileDatabase& db)
: db(db)
{
ObjectCache(const FileDatabase &db) :
db(db) {
// currently there are only ~400 structure records per blend file.
// we read only a small part of them and don't cache objects
// which we don't need, so this should suffice.
@ -680,14 +650,14 @@ public:
}
public:
// --------------------------------------------------------
/** Check whether a specific item is in the cache.
* @param s Data type of the item
* @param out Output pointer. Unchanged if the
* cache doesn't know the item yet.
* @param ptr Item address to look for. */
template <typename T> void get (
template <typename T>
void get(
const Structure &s,
TOUT<T> &out,
const Pointer &ptr) const;
@ -700,27 +670,27 @@ public:
* @param s Data type of the item
* @param out Item to insert into the cache
* @param ptr address (cache key) of the item. */
template <typename T> void set
(const Structure& s,
template <typename T>
void set(const Structure &s,
const TOUT<T> &out,
const Pointer &ptr);
private:
mutable vector<StructureCache> caches;
const FileDatabase &db;
};
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
template <> class ObjectCache<Blender::vector>
{
template <>
class ObjectCache<Blender::vector> {
public:
ObjectCache(const FileDatabase &) {}
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
template <typename T>
void get(const Structure &, vector<T> &, const Pointer &) {}
template <typename T>
void set(const Structure &, const vector<T> &, const Pointer &) {}
};
#ifdef _MSC_VER
@ -731,16 +701,13 @@ public:
/** Memory representation of a full BLEND file and all its dependencies. The
* output aiScene is constructed from an instance of this data structure. */
// -------------------------------------------------------------------------------
class FileDatabase
{
template <template <typename> class TOUT> friend class ObjectCache;
class FileDatabase {
template <template <typename> class TOUT>
friend class ObjectCache;
public:
FileDatabase()
: _cacheArrays(*this)
, _cache(*this)
, next_cache_idx()
{}
FileDatabase() :
_cacheArrays(*this), _cache(*this), next_cache_idx() {}
public:
// publicly accessible fields
@ -752,7 +719,6 @@ public:
vector<FileBlockHead> entries;
public:
Statistics &stats() const {
return _stats;
}
@ -772,8 +738,6 @@ public:
}
private:
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
mutable Statistics _stats;
#endif
@ -791,18 +755,14 @@ private:
// -------------------------------------------------------------------------------
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
// -------------------------------------------------------------------------------
class DNAParser
{
class DNAParser {
public:
/** Bind the parser to a empty DNA and an input stream */
DNAParser(FileDatabase& db)
: db(db)
{}
DNAParser(FileDatabase &db) :
db(db) {}
public:
// --------------------------------------------------------
/** Locate the DNA in the file and parse it. The input
* stream is expected to point to the beginning of the DN1
@ -814,14 +774,12 @@ public:
void Parse();
public:
/** Obtain a reference to the extracted DNA information */
const Blender::DNA &GetDNA() const {
return db.dna;
}
private:
FileDatabase &db;
};
@ -835,9 +793,8 @@ private:
*/
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
} // end Blend
} // end Assimp
} // namespace Blender
} // namespace Assimp
#include "BlenderDNA.inl"

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -58,9 +57,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) {
throw Error((Formatter::format(),
"BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
));
throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
}
return fields[(*it).second];
@ -70,16 +67,14 @@ const Field& Structure :: operator [] (const std::string& ss) const
const Field* Structure :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &fields[(*it).second];
return it == indices.end() ? nullptr : &fields[(*it).second];
}
//--------------------------------------------------------------------------------
const Field& Structure :: operator [] (const size_t i) const
{
if (i >= fields.size()) {
throw Error((Formatter::format(),
"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
));
throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`");
}
return fields[i];
@ -110,9 +105,7 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab
// is the input actually an array?
if (!(f.flags & FieldFlag_Array)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M
));
throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
}
db.reader->IncPtr(f.offset);
@ -149,9 +142,9 @@ void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileD
// is the input actually an 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
));
);
}
db.reader->IncPtr(f.offset);
@ -196,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
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer"));
throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer");
}
db.reader->IncPtr(f->offset);
@ -239,11 +232,13 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
try {
f = &(*this)[name];
#ifdef _DEBUG
// sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array"));
throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array");
}
#endif // _DEBUG
db.reader->IncPtr(f->offset);
@ -321,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
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"));
throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer");
}
db.reader->IncPtr(f->offset);
@ -368,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
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"));
throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer");
}
db.reader->IncPtr(f->offset);
@ -427,9 +422,9 @@ bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const Fil
// and check if it matches the type which we expect.
const Structure& ss = db.dna[block->dna_index];
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"
));
);
}
// try to retrieve the object from the cache
@ -613,16 +608,14 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
if (it == db.entries.end()) {
// this is crucial, pointers may not be invalid.
// this is either a corrupted file or an attempted attack.
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range"
));
throw DeadlyImportError("Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range");
}
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",
(*it).address.val," ends at 0x",
(*it).address.val + (*it).size
));
(*it).address.val + (*it).size);
}
return &*it;
}
@ -675,7 +668,7 @@ template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,
out = static_cast<T>(db.reader->GetF8());
}
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);
}
}
@ -783,9 +776,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) {
throw Error((Formatter::format(),
"BlendDNA: Did not find a structure named `",ss,"`"
));
throw Error("BlendDNA: Did not find a structure named `",ss,"`");
}
return structures[(*it).second];
@ -795,16 +786,14 @@ const Structure& DNA :: operator [] (const std::string& ss) const
const Structure* DNA :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &structures[(*it).second];
return it == indices.end() ? nullptr : &structures[(*it).second];
}
//--------------------------------------------------------------------------------
const Structure& DNA :: operator [] (const size_t i) const
{
if (i >= structures.size()) {
throw Error((Formatter::format(),
"BlendDNA: There is no structure with index `",i,"`"
));
throw Error("BlendDNA: There is no structure with index `",i,"`");
}
return structures[i];

View File

@ -45,27 +45,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the Blender3D importer class.
*/
//#define ASSIMP_BUILD_NO_COMPRESSED_BLEND
// Uncomment this to disable support for (gzip)compressed .BLEND files
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderIntermediate.h"
#include "BlenderModifier.h"
#include "BlenderBMesh.h"
#include "BlenderCustomData.h"
#include "BlenderIntermediate.h"
#include "BlenderModifier.h"
#include <assimp/StringUtils.h>
#include <assimp/scene.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/StringComparison.h>
#include <assimp/StreamReader.h>
#include <assimp/MemoryIOWrapper.h>
#include <assimp/StreamReader.h>
#include <assimp/StringComparison.h>
#include <cctype>
// zlib is needed for compressed blend files
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
@ -76,12 +74,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif
namespace Assimp {
template<> const char* LogFunctions<BlenderImporter>::Prefix()
{
template <>
const char *LogFunctions<BlenderImporter>::Prefix() {
static auto prefix = "BLEND: ";
return prefix;
}
}
} // namespace Assimp
using namespace Assimp;
using namespace Assimp::Blender;
@ -100,18 +98,16 @@ static const aiImporterDesc blenderDesc = {
"blend"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BlenderImporter::BlenderImporter()
: modifier_cache(new BlenderModifierShowcase()) {
BlenderImporter::BlenderImporter() :
modifier_cache(new BlenderModifierShowcase()) {
// empty
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BlenderImporter::~BlenderImporter()
{
BlenderImporter::~BlenderImporter() {
delete modifier_cache;
}
@ -120,8 +116,7 @@ static const char* TokensForSearch[] = { "blender" };
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
const std::string &extension = GetExtension(pFile);
if (extension == "blend") {
return true;
@ -136,36 +131,30 @@ bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, b
// ------------------------------------------------------------------------------------------------
// List all extensions handled by this loader
void BlenderImporter::GetExtensionList(std::set<std::string>& app)
{
void BlenderImporter::GetExtensionList(std::set<std::string> &app) {
app.insert("blend");
}
// ------------------------------------------------------------------------------------------------
// Loader registry entry
const aiImporterDesc* BlenderImporter::GetInfo () const
{
const aiImporterDesc *BlenderImporter::GetInfo() const {
return &blenderDesc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
{
void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
// nothing to be done for the moment
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void BlenderImporter::InternReadFile(const std::string &pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
std::vector<Bytef> uncompressed;
#endif
FileDatabase file;
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (!stream) {
@ -206,7 +195,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
inflateInit2(&zstream, 16 + MAX_WBITS);
zstream.next_in = reinterpret_cast<Bytef *>(reader->GetPtr());
zstream.avail_in = reader->GetRemainingSize();
zstream.avail_in = (uInt)reader->GetRemainingSize();
size_t total = 0l;
@ -227,8 +216,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
total += have;
uncompressed.resize(total);
memcpy(uncompressed.data() + total - have, block, have);
}
while (ret != Z_STREAM_END);
} while (ret != Z_STREAM_END);
// terminate zlib
inflateEnd(&zstream);
@ -252,8 +240,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
LogInfo((format(), "Blender version is ", magic[0], ".", magic + 1,
" (64bit: ", file.i64bit ? "true" : "false",
", little endian: ",file.little?"true":"false",")"
));
", little endian: ", file.little ? "true" : "false", ")"));
ParseBlendFile(file, stream);
@ -264,14 +251,14 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream> stream)
{
void BlenderImporter::ParseBlendFile(FileDatabase &out, std::shared_ptr<IOStream> stream) {
out.reader = std::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream, out.little));
DNAParser dna_reader(out);
const DNA* dna = NULL;
const DNA *dna = nullptr;
out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks
out.entries.reserve(128);
{ // even small BLEND files tend to consist of many file blocks
SectionParser parser(*out.reader.get(), out.i64bit);
// first parse the file in search for the DNA and insert all other sections into the database
@ -280,8 +267,7 @@ void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream
if (head.id == "ENDB") {
break; // only valid end of the file
}
else if (head.id == "DNA1") {
} else if (head.id == "DNA1") {
dna_reader.Parse();
dna = &dna_reader.GetDNA();
continue;
@ -298,9 +284,8 @@ void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
{
const FileBlockHead* block = NULL;
void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
const FileBlockHead *block = nullptr;
std::map<std::string, size_t>::const_iterator it = file.dna.indices.find("Scene");
if (it == file.dna.indices.end()) {
ThrowException("There is no `Scene` structure record");
@ -332,14 +317,12 @@ void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
"(Stats) Fields read: ", file.stats().fields_read,
", pointers resolved: ", file.stats().pointers_resolved,
", cache hits: ", file.stats().cache_hits,
", cached objects: " ,file.stats().cached_objects
);
", cached objects: ", file.stats().cached_objects);
#endif
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileDatabase& file)
{
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
ConversionData conv(file);
// FIXME it must be possible to take the hierarchy directly from
@ -418,9 +401,10 @@ void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileD
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const MTex* tex, const Image* img, ConversionData& conv_data)
{
(void)mat; (void)tex; (void)conv_data;
void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const MTex *tex, const Image *img, ConversionData &conv_data) {
(void)mat;
(void)tex;
(void)conv_data;
aiString name;
// check if the file contents are bundled with the BLEND file
@ -466,13 +450,11 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
else if (map_type & MTex::MapType_NORM) {
if (tex->tex->imaflag & Tex::ImageFlags_NORMALMAP) {
texture_type = aiTextureType_NORMALS;
}
else {
} else {
texture_type = aiTextureType_HEIGHT;
}
out->AddProperty(&tex->norfac, 1, AI_MATKEY_BUMPSCALING);
}
else if (map_type & MTex::MapType_COLSPEC)
} else if (map_type & MTex::MapType_COLSPEC)
texture_type = aiTextureType_SPECULAR;
else if (map_type & MTex::MapType_COLMIR)
texture_type = aiTextureType_REFLECTION;
@ -493,26 +475,23 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
out->AddProperty(&name, AI_MATKEY_TEXTURE(texture_type,
conv_data.next_texture[texture_type]++));
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
{
(void)mat; (void)tex; (void)conv_data;
void BlenderImporter::AddSentinelTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
(void)mat;
(void)tex;
(void)conv_data;
aiString name;
name.length = ai_snprintf(name.data, MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
GetTextureTypeDisplayString(tex->tex->type)
);
GetTextureTypeDisplayString(tex->tex->type));
out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(
conv_data.next_texture[aiTextureType_DIFFUSE]++)
);
conv_data.next_texture[aiTextureType_DIFFUSE]++));
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
{
void BlenderImporter::ResolveTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
const Tex *rtex = tex->tex.get();
if (!rtex || !rtex->type) {
return;
@ -521,8 +500,7 @@ void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const
// We can't support most of the texture types because they're mostly procedural.
// These are substituted by a dummy texture.
const char *dispnam = "";
switch( rtex->type )
{
switch (rtex->type) {
// these are listed in blender's UI
case Tex::Type_CLOUDS:
case Tex::Type_WOOD:
@ -559,8 +537,7 @@ void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData& conv_data)
{
void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData &conv_data) {
// add a default material if necessary
unsigned int index = static_cast<unsigned int>(-1);
for (aiMesh *mesh : conv_data.meshes.get()) {
@ -593,8 +570,7 @@ void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData& conv_data)
}
}
void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
{
void BlenderImporter::AddBlendParams(aiMaterial *result, const Material *source) {
aiColor3D diffuseColor(source->r, source->g, source->b);
result->AddProperty(&diffuseColor, 1, "$mat.blend.diffuse.color", 0, 0);
@ -607,7 +583,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
int diffuseRamp = 0;
result->AddProperty(&diffuseRamp, 1, "$mat.blend.diffuse.ramp", 0, 0);
aiColor3D specularColor(source->specr, source->specg, source->specb);
result->AddProperty(&specularColor, 1, "$mat.blend.specular.color", 0, 0);
@ -623,7 +598,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
int specularHardness = source->har;
result->AddProperty(&specularHardness, 1, "$mat.blend.specular.hardness", 0, 0);
int transparencyUse = source->mode & MA_TRANSPARENCY ? 1 : 0;
result->AddProperty(&transparencyUse, 1, "$mat.blend.transparency.use", 0, 0);
@ -666,7 +640,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
int transparencyGlossSamples = source->samp_gloss_tra;
result->AddProperty(&transparencyGlossSamples, 1, "$mat.blend.transparency.glossSamples", 0, 0);
int mirrorUse = source->mode & MA_RAYMIRROR ? 1 : 0;
result->AddProperty(&mirrorUse, 1, "$mat.blend.mirror.use", 0, 0);
@ -704,8 +677,7 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
result->AddProperty(&mirrorGlossAnisotropic, 1, "$mat.blend.mirror.glossAnisotropic", 0, 0);
}
void BlenderImporter::BuildMaterials(ConversionData& conv_data)
{
void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
conv_data.materials->reserve(conv_data.materials_raw.size());
BuildDefaultMaterial(conv_data);
@ -773,34 +745,27 @@ 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);
if (strcmp(dt->dna_type, check)) {
ThrowException((format(),
"Expected object at ",std::hex,dt," to be of type `",check,
"`, but it claims to be a `",dt->dna_type,"`instead"
));
ThrowException("Expected object at ", std::hex, dt, " to be of type `", check,
"`, but it claims to be a `", dt->dna_type, "`instead");
}
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::NotSupportedObjectType(const Object* obj, const char* type)
{
void BlenderImporter::NotSupportedObjectType(const Object *obj, const char *type) {
LogWarn((format(), "Object `", obj->id.name, "` - type is unsupported: `", type, "`, skipping"));
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/, const Mesh *mesh,
ConversionData& conv_data, TempArray<std::vector,aiMesh>& temp
)
{
ConversionData &conv_data, TempArray<std::vector, aiMesh> &temp) {
// TODO: Resolve various problems with BMesh triangulation before re-enabling.
// See issues #400, #373, #318 #315 and #132.
#if defined(TODO_FIX_BMESH_CONVERSION)
BlenderBMeshConverter BMeshConverter(mesh);
if ( BMeshConverter.ContainsBMesh( ) )
{
if (BMeshConverter.ContainsBMesh()) {
mesh = BMeshConverter.TriangulateBMesh();
}
#endif
@ -874,18 +839,16 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
std::shared_ptr<Material> mat = mesh->mat[it.first];
const std::deque<std::shared_ptr<Material>>::iterator has = std::find(
conv_data.materials_raw.begin(),
conv_data.materials_raw.end(),mat
);
conv_data.materials_raw.end(), mat);
if (has != conv_data.materials_raw.end()) {
out->mMaterialIndex = static_cast<unsigned int>(std::distance(conv_data.materials_raw.begin(), has));
}
else {
} else {
out->mMaterialIndex = static_cast<unsigned int>(conv_data.materials_raw.size());
conv_data.materials_raw.push_back(mat);
}
}
else out->mMaterialIndex = static_cast<unsigned int>( -1 );
} else
out->mMaterialIndex = static_cast<unsigned int>(-1);
}
for (int i = 0; i < mesh->totface; ++i) {
@ -966,8 +929,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
++vn;
out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
}
else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
} else
out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
// }
// }
@ -990,8 +953,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
// which are assigned by the genblenddna.py script and
// cannot be changed without breaking the entire
// import process.
for (int j = 0;j < mf.totloop; ++j)
{
for (int j = 0; j < mf.totloop; ++j) {
const MLoop &loop = mesh->mloop[mf.loopstart + j];
if (loop.v >= mesh->totvert) {
@ -1010,14 +972,10 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
++vo;
++vn;
}
if (mf.totloop == 3)
{
if (mf.totloop == 3) {
out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
}
else
{
} else {
out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
}
}
@ -1056,13 +1014,13 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
if (itMatTexUvMapping == matTexUvMappings.end()) {
// default behaviour like before
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
}
else {
} else {
// create texture coords for every mapped tex
for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
(*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
@ -1125,7 +1083,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
(*it)->mNumFaces = (*it)->mNumVertices = 0;
@ -1151,7 +1110,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
ThrowException("Number of faces is larger than the corresponding color face array");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
(*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
(*it)->mNumFaces = (*it)->mNumVertices = 0;
@ -1171,7 +1131,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
vo->b = col->b;
vo->a = col->a;
}
for (unsigned int n = f.mNumIndices; n < 4; ++n);
for (unsigned int n = f.mNumIndices; n < 4; ++n)
;
}
for (int i = 0; i < mesh->totpoly; ++i) {
@ -1188,17 +1149,14 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
vo->b = ai_real(col.b) * scaleZeroToOne;
vo->a = ai_real(col.a) * scaleZeroToOne;
}
}
}
return;
}
// ------------------------------------------------------------------------------------------------
aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* cam, ConversionData& /*conv_data*/)
{
aiCamera *BlenderImporter::ConvertCamera(const Scene & /*in*/, const Object *obj, const Camera *cam, ConversionData & /*conv_data*/) {
std::unique_ptr<aiCamera> out(new aiCamera());
out->mName = obj->id.name + 2;
out->mPosition = aiVector3D(0.f, 0.f, 0.f);
@ -1214,13 +1172,11 @@ aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj,
}
// ------------------------------------------------------------------------------------------------
aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/)
{
aiLight *BlenderImporter::ConvertLight(const Scene & /*in*/, const Object *obj, const Lamp *lamp, ConversionData & /*conv_data*/) {
std::unique_ptr<aiLight> out(new aiLight());
out->mName = obj->id.name + 2;
switch (lamp->type)
{
switch (lamp->type) {
case Lamp::Type_Local:
out->mType = aiLightSource_POINT;
break;
@ -1247,8 +1203,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
if (lamp->area_shape == 0) {
out->mSize = aiVector2D(lamp->area_size, lamp->area_size);
}
else {
} else {
out->mSize = aiVector2D(lamp->area_size, lamp->area_sizey);
}
@ -1268,14 +1223,11 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
// If default values are supplied, compute the coefficients from light's max distance
// Read this: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
//
if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f)
{
if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f) {
out->mAttenuationConstant = 1.0f;
out->mAttenuationLinear = 2.0f / lamp->dist;
out->mAttenuationQuadratic = 1.0f / (lamp->dist * lamp->dist);
}
else
{
} else {
out->mAttenuationConstant = lamp->constant_coefficient;
out->mAttenuationLinear = lamp->linear_coefficient;
out->mAttenuationQuadratic = lamp->quadratic_coefficient;
@ -1285,8 +1237,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
}
// ------------------------------------------------------------------------------------------------
aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform)
{
aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, ConversionData &conv_data, const aiMatrix4x4 &parentTransform) {
std::deque<const Object *> children;
for (ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end();) {
const Object *object = *it;
@ -1301,12 +1252,10 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
std::unique_ptr<aiNode> node(new aiNode(obj->id.name + 2)); // skip over the name prefix 'OB'
if (obj->data) {
switch (obj->type)
{
switch (obj->type) {
case Object ::Type_EMPTY:
break; // do nothing
// supported object types
case Object ::Type_MESH: {
const size_t old = conv_data.meshes->size();
@ -1319,27 +1268,24 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
node->mMeshes[i] = static_cast<unsigned int>(i + old);
}
}}
break;
}
} break;
case Object ::Type_LAMP: {
CheckActualType(obj->data.get(), "Lamp");
aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>(
obj->data.get()),conv_data);
aiLight *mesh = ConvertLight(in, obj, static_cast<const Lamp *>(obj->data.get()), conv_data);
if (mesh) {
conv_data.lights->push_back(mesh);
}}
break;
}
} break;
case Object ::Type_CAMERA: {
CheckActualType(obj->data.get(), "Camera");
aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>(
obj->data.get()),conv_data);
aiCamera *mesh = ConvertCamera(in, obj, static_cast<const Camera *>(obj->data.get()), conv_data);
if (mesh) {
conv_data.cameras->push_back(mesh);
}}
break;
}
} break;
// unsupported object types / log, but do not break
case Object ::Type_CURVE:

View File

@ -106,51 +106,18 @@ class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter
public:
BlenderImporter();
~BlenderImporter();
public:
// --------------------
bool CanRead( const std::string& pFile,
IOSystem* pIOHandler,
bool checkSig
) const;
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
protected:
// --------------------
const aiImporterDesc* GetInfo () const;
// --------------------
void GetExtensionList(std::set<std::string>& app);
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
);
// --------------------
void ParseBlendFile(Blender::FileDatabase& out,
std::shared_ptr<IOStream> stream
);
// --------------------
void ExtractScene(Blender::Scene& out,
const Blender::FileDatabase& file
);
// --------------------
void ConvertBlendFile(aiScene* out,
const Blender::Scene& in,
const Blender::FileDatabase& file
);
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
void ParseBlendFile(Blender::FileDatabase& out, std::shared_ptr<IOStream> stream);
void ExtractScene(Blender::Scene& out, const Blender::FileDatabase& file);
void ConvertBlendFile(aiScene* out, const Blender::Scene& in, const Blender::FileDatabase& file);
private:
// --------------------
aiNode* ConvertNode(const Blender::Scene& in,
const Blender::Object* obj,
Blender::ConversionData& conv_info,

View File

@ -68,7 +68,7 @@ static const fpCreateModifier creators[] = {
&god<BlenderModifier_Mirror>,
&god<BlenderModifier_Subdivision>,
NULL // sentinel
nullptr // sentinel
};
// ------------------------------------------------------------------------------------------------
@ -127,7 +127,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
cnt++;
curgod = NULL;
curgod = nullptr;
break;
}
}

View File

@ -0,0 +1,838 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2020, ASSIMP Development 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 Development 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 BlenderScene.cpp
* @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderScene.h"
#include "BlenderCustomData.h"
#include "BlenderDNA.h"
#include "BlenderSceneGen.h"
using namespace Assimp;
using namespace Assimp::Blender;
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Object>(
Object &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat, "obmat", db);
ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv, "parentinv", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr, "parsubstr", db);
{
std::shared_ptr<Object> parent;
ReadFieldPtr<ErrorPolicy_Warn>(parent, "*parent", db);
dest.parent = parent.get();
}
ReadFieldPtr<ErrorPolicy_Warn>(dest.track, "*track", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy, "*proxy", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from, "*proxy_from", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group, "*proxy_group", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group, "*dup_group", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.data, "*data", db);
ReadField<ErrorPolicy_Igno>(dest.modifiers, "modifiers", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Group>(
Group &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Igno>(dest.layer, "layer", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject, "*gobject", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTex>(
MTex &dest,
const FileDatabase &db) const {
int temp_short = 0;
ReadField<ErrorPolicy_Igno>(temp_short, "mapto", db);
dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
int temp = 0;
ReadField<ErrorPolicy_Igno>(temp, "blendtype", db);
dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
ReadFieldPtr<ErrorPolicy_Igno>(dest.object, "*object", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tex, "*tex", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.uvname, "uvname", db);
ReadField<ErrorPolicy_Igno>(temp, "projx", db);
dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp, "projy", db);
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp, "projz", db);
dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(dest.mapping, "mapping", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs, "ofs", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.size, "size", db);
ReadField<ErrorPolicy_Igno>(dest.rot, "rot", db);
ReadField<ErrorPolicy_Igno>(dest.texflag, "texflag", db);
ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
ReadField<ErrorPolicy_Igno>(dest.pmapto, "pmapto", db);
ReadField<ErrorPolicy_Igno>(dest.pmaptoneg, "pmaptoneg", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
ReadField<ErrorPolicy_Igno>(dest.colspecfac, "colspecfac", db);
ReadField<ErrorPolicy_Igno>(dest.mirrfac, "mirrfac", db);
ReadField<ErrorPolicy_Igno>(dest.alphafac, "alphafac", db);
ReadField<ErrorPolicy_Igno>(dest.difffac, "difffac", db);
ReadField<ErrorPolicy_Igno>(dest.specfac, "specfac", db);
ReadField<ErrorPolicy_Igno>(dest.emitfac, "emitfac", db);
ReadField<ErrorPolicy_Igno>(dest.hardfac, "hardfac", db);
ReadField<ErrorPolicy_Igno>(dest.norfac, "norfac", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<TFace>(
TFace &dest,
const FileDatabase &db) const {
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.col, "col", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<SubsurfModifierData>(
SubsurfModifierData &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
ReadField<ErrorPolicy_Warn>(dest.subdivType, "subdivType", db);
ReadField<ErrorPolicy_Fail>(dest.levels, "levels", db);
ReadField<ErrorPolicy_Igno>(dest.renderLevels, "renderLevels", db);
ReadField<ErrorPolicy_Igno>(dest.flags, "flags", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MFace>(
MFace &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
ReadField<ErrorPolicy_Fail>(dest.v3, "v3", db);
ReadField<ErrorPolicy_Fail>(dest.v4, "v4", db);
ReadField<ErrorPolicy_Fail>(dest.mat_nr, "mat_nr", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Lamp>(
Lamp &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
ReadField<ErrorPolicy_Igno>(dest.flags, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
ReadField<ErrorPolicy_Igno>(dest.totex, "totex", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
ReadField<ErrorPolicy_Igno>(dest.energy, "energy", db);
ReadField<ErrorPolicy_Warn>(dest.dist, "dist", db);
ReadField<ErrorPolicy_Igno>(dest.spotsize, "spotsize", db);
ReadField<ErrorPolicy_Igno>(dest.spotblend, "spotblend", db);
ReadField<ErrorPolicy_Warn>(dest.constant_coefficient, "coeff_const", db);
ReadField<ErrorPolicy_Warn>(dest.linear_coefficient, "coeff_lin", db);
ReadField<ErrorPolicy_Warn>(dest.quadratic_coefficient, "coeff_quad", db);
ReadField<ErrorPolicy_Igno>(dest.att1, "att1", db);
ReadField<ErrorPolicy_Igno>(dest.att2, "att2", db);
ReadField<ErrorPolicy_Igno>(temp, "falloff_type", db);
dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
ReadField<ErrorPolicy_Igno>(dest.sun_brightness, "sun_brightness", db);
ReadField<ErrorPolicy_Igno>(dest.area_size, "area_size", db);
ReadField<ErrorPolicy_Igno>(dest.area_sizey, "area_sizey", db);
ReadField<ErrorPolicy_Igno>(dest.area_sizez, "area_sizez", db);
ReadField<ErrorPolicy_Igno>(dest.area_shape, "area_shape", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MDeformWeight>(
MDeformWeight &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.def_nr, "def_nr", db);
ReadField<ErrorPolicy_Fail>(dest.weight, "weight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<PackedFile>(
PackedFile &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Warn>(dest.size, "size", db);
ReadField<ErrorPolicy_Warn>(dest.seek, "seek", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.data, "*data", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Base>(
Base &dest,
const FileDatabase &db) const {
// note: as per https://github.com/assimp/assimp/issues/128,
// reading the Object linked list recursively is prone to stack overflow.
// This structure converter is therefore an hand-written exception that
// does it iteratively.
const int initial_pos = db.reader->GetCurrentPos();
std::pair<Base *, int> todo = std::make_pair(&dest, initial_pos);
for (;;) {
Base &cur_dest = *todo.first;
db.reader->SetCurrentPos(todo.second);
// we know that this is a double-linked, circular list which we never
// traverse backwards, so don't bother resolving the back links.
cur_dest.prev = nullptr;
ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object, "*object", db);
// the return value of ReadFieldPtr indicates whether the object
// was already cached. In this case, we don't need to resolve
// it again.
if (!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next, "*next", db, true) && cur_dest.next) {
todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
continue;
}
break;
}
db.reader->SetCurrentPos(initial_pos + size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTFace>(
MTFace &dest,
const FileDatabase &db) const {
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Material>(
Material &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.specr, "specr", db);
ReadField<ErrorPolicy_Warn>(dest.specg, "specg", db);
ReadField<ErrorPolicy_Warn>(dest.specb, "specb", db);
ReadField<ErrorPolicy_Igno>(dest.har, "har", db);
ReadField<ErrorPolicy_Warn>(dest.ambr, "ambr", db);
ReadField<ErrorPolicy_Warn>(dest.ambg, "ambg", db);
ReadField<ErrorPolicy_Warn>(dest.ambb, "ambb", db);
ReadField<ErrorPolicy_Igno>(dest.mirr, "mirr", db);
ReadField<ErrorPolicy_Igno>(dest.mirg, "mirg", db);
ReadField<ErrorPolicy_Igno>(dest.mirb, "mirb", db);
ReadField<ErrorPolicy_Warn>(dest.emit, "emit", db);
ReadField<ErrorPolicy_Igno>(dest.ray_mirror, "ray_mirror", db);
ReadField<ErrorPolicy_Warn>(dest.alpha, "alpha", db);
ReadField<ErrorPolicy_Igno>(dest.ref, "ref", db);
ReadField<ErrorPolicy_Igno>(dest.translucency, "translucency", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.roughness, "roughness", db);
ReadField<ErrorPolicy_Igno>(dest.darkness, "darkness", db);
ReadField<ErrorPolicy_Igno>(dest.refrac, "refrac", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.group, "*group", db);
ReadField<ErrorPolicy_Warn>(dest.diff_shader, "diff_shader", db);
ReadField<ErrorPolicy_Warn>(dest.spec_shader, "spec_shader", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex, "*mtex", db);
ReadField<ErrorPolicy_Igno>(dest.amb, "amb", db);
ReadField<ErrorPolicy_Igno>(dest.ang, "ang", db);
ReadField<ErrorPolicy_Igno>(dest.spectra, "spectra", db);
ReadField<ErrorPolicy_Igno>(dest.spec, "spec", db);
ReadField<ErrorPolicy_Igno>(dest.zoffs, "zoffs", db);
ReadField<ErrorPolicy_Igno>(dest.add, "add", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir, "fresnel_mir", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir_i, "fresnel_mir_i", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra, "fresnel_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra_i, "fresnel_tra_i", db);
ReadField<ErrorPolicy_Igno>(dest.filter, "filter", db);
ReadField<ErrorPolicy_Igno>(dest.tx_limit, "tx_limit", db);
ReadField<ErrorPolicy_Igno>(dest.tx_falloff, "tx_falloff", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_mir, "gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_tra, "gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_mir, "adapt_thresh_mir", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_tra, "adapt_thresh_tra", db);
ReadField<ErrorPolicy_Igno>(dest.aniso_gloss_mir, "aniso_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.dist_mir, "dist_mir", db);
ReadField<ErrorPolicy_Igno>(dest.hasize, "hasize", db);
ReadField<ErrorPolicy_Igno>(dest.flaresize, "flaresize", db);
ReadField<ErrorPolicy_Igno>(dest.subsize, "subsize", db);
ReadField<ErrorPolicy_Igno>(dest.flareboost, "flareboost", db);
ReadField<ErrorPolicy_Igno>(dest.strand_sta, "strand_sta", db);
ReadField<ErrorPolicy_Igno>(dest.strand_end, "strand_end", db);
ReadField<ErrorPolicy_Igno>(dest.strand_ease, "strand_ease", db);
ReadField<ErrorPolicy_Igno>(dest.strand_surfnor, "strand_surfnor", db);
ReadField<ErrorPolicy_Igno>(dest.strand_min, "strand_min", db);
ReadField<ErrorPolicy_Igno>(dest.strand_widthfade, "strand_widthfade", db);
ReadField<ErrorPolicy_Igno>(dest.sbias, "sbias", db);
ReadField<ErrorPolicy_Igno>(dest.lbias, "lbias", db);
ReadField<ErrorPolicy_Igno>(dest.shad_alpha, "shad_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.param, "param", db);
ReadField<ErrorPolicy_Igno>(dest.rms, "rms", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_col, "rampfac_col", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_spec, "rampfac_spec", db);
ReadField<ErrorPolicy_Igno>(dest.friction, "friction", db);
ReadField<ErrorPolicy_Igno>(dest.fh, "fh", db);
ReadField<ErrorPolicy_Igno>(dest.reflect, "reflect", db);
ReadField<ErrorPolicy_Igno>(dest.fhdist, "fhdist", db);
ReadField<ErrorPolicy_Igno>(dest.xyfrict, "xyfrict", db);
ReadField<ErrorPolicy_Igno>(dest.sss_radius, "sss_radius", db);
ReadField<ErrorPolicy_Igno>(dest.sss_col, "sss_col", db);
ReadField<ErrorPolicy_Igno>(dest.sss_error, "sss_error", db);
ReadField<ErrorPolicy_Igno>(dest.sss_scale, "sss_scale", db);
ReadField<ErrorPolicy_Igno>(dest.sss_ior, "sss_ior", db);
ReadField<ErrorPolicy_Igno>(dest.sss_colfac, "sss_colfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_texfac, "sss_texfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_front, "sss_front", db);
ReadField<ErrorPolicy_Igno>(dest.sss_back, "sss_back", db);
ReadField<ErrorPolicy_Igno>(dest.material_type, "material_type", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth, "ray_depth", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth_tra, "ray_depth_tra", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_mir, "samp_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_tra, "samp_gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fadeto_mir, "fadeto_mir", db);
ReadField<ErrorPolicy_Igno>(dest.shade_flag, "shade_flag", db);
ReadField<ErrorPolicy_Igno>(dest.flarec, "flarec", db);
ReadField<ErrorPolicy_Igno>(dest.starc, "starc", db);
ReadField<ErrorPolicy_Igno>(dest.linec, "linec", db);
ReadField<ErrorPolicy_Igno>(dest.ringc, "ringc", db);
ReadField<ErrorPolicy_Igno>(dest.pr_lamp, "pr_lamp", db);
ReadField<ErrorPolicy_Igno>(dest.pr_texture, "pr_texture", db);
ReadField<ErrorPolicy_Igno>(dest.ml_flag, "ml_flag", db);
ReadField<ErrorPolicy_Igno>(dest.diff_shader, "diff_shader", db);
ReadField<ErrorPolicy_Igno>(dest.spec_shader, "spec_shader", db);
ReadField<ErrorPolicy_Igno>(dest.texco, "texco", db);
ReadField<ErrorPolicy_Igno>(dest.mapto, "mapto", db);
ReadField<ErrorPolicy_Igno>(dest.ramp_show, "ramp_show", db);
ReadField<ErrorPolicy_Igno>(dest.pad3, "pad3", db);
ReadField<ErrorPolicy_Igno>(dest.dynamode, "dynamode", db);
ReadField<ErrorPolicy_Igno>(dest.pad2, "pad2", db);
ReadField<ErrorPolicy_Igno>(dest.sss_flag, "sss_flag", db);
ReadField<ErrorPolicy_Igno>(dest.sss_preset, "sss_preset", db);
ReadField<ErrorPolicy_Igno>(dest.shadowonly_flag, "shadowonly_flag", db);
ReadField<ErrorPolicy_Igno>(dest.index, "index", db);
ReadField<ErrorPolicy_Igno>(dest.vcol_alpha, "vcol_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.pad4, "pad4", db);
ReadField<ErrorPolicy_Igno>(dest.seed1, "seed1", db);
ReadField<ErrorPolicy_Igno>(dest.seed2, "seed2", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTexPoly>(
MTexPoly &dest,
const FileDatabase &db) const {
{
std::shared_ptr<Image> tpage;
ReadFieldPtr<ErrorPolicy_Igno>(tpage, "*tpage", db);
dest.tpage = tpage.get();
}
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.transp, "transp", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Mesh>(
Mesh &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Fail>(dest.totface, "totface", db);
ReadField<ErrorPolicy_Fail>(dest.totedge, "totedge", db);
ReadField<ErrorPolicy_Fail>(dest.totvert, "totvert", db);
ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
ReadField<ErrorPolicy_Igno>(dest.totpoly, "totpoly", db);
ReadField<ErrorPolicy_Igno>(dest.subdiv, "subdiv", db);
ReadField<ErrorPolicy_Igno>(dest.subdivr, "subdivr", db);
ReadField<ErrorPolicy_Igno>(dest.subsurftype, "subsurftype", db);
ReadField<ErrorPolicy_Igno>(dest.smoothresh, "smoothresh", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mface, "*mface", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface, "*mtface", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tface, "*tface", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert, "*mvert", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.medge, "*medge", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop, "*mloop", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv, "*mloopuv", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol, "*mloopcol", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly, "*mpoly", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly, "*mtpoly", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert, "*dvert", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol, "*mcol", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mat, "**mat", db);
ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MDeformVert>(
MDeformVert &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Warn>(dest.dw, "*dw", db);
ReadField<ErrorPolicy_Igno>(dest.totweight, "totweight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<World>(
World &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoopCol>(
MLoopCol &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.r, "r", db);
ReadField<ErrorPolicy_Igno>(dest.g, "g", db);
ReadField<ErrorPolicy_Igno>(dest.b, "b", db);
ReadField<ErrorPolicy_Igno>(dest.a, "a", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MVert>(
MVert &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
//ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MEdge>(
MEdge &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
ReadField<ErrorPolicy_Igno>(dest.crease, "crease", db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoopUV>(
MLoopUV &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Igno>(dest.uv, "uv", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<GroupObject>(
GroupObject &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.ob, "*ob", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ListBase>(
ListBase &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.last, "*last", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoop>(
MLoop &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.v, "v", db);
ReadField<ErrorPolicy_Igno>(dest.e, "e", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ModifierData>(
ModifierData &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.prev, "*prev", db);
ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ID>(
ID &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MCol>(
MCol &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.r, "r", db);
ReadField<ErrorPolicy_Fail>(dest.g, "g", db);
ReadField<ErrorPolicy_Fail>(dest.b, "b", db);
ReadField<ErrorPolicy_Fail>(dest.a, "a", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MPoly>(
MPoly &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.loopstart, "loopstart", db);
ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
ReadField<ErrorPolicy_Igno>(dest.mat_nr, "mat_nr", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Scene>(
Scene &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Library>(
Library &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.filename, "filename", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.parent, "*parent", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Tex>(
Tex &dest,
const FileDatabase &db) const {
short temp_short = 0;
ReadField<ErrorPolicy_Igno>(temp_short, "imaflag", db);
dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
ReadFieldPtr<ErrorPolicy_Warn>(dest.ima, "*ima", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Camera>(
Camera &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Warn>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
ReadField<ErrorPolicy_Warn>(temp, "flag", db);
dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
ReadField<ErrorPolicy_Warn>(dest.lens, "lens", db);
ReadField<ErrorPolicy_Warn>(dest.sensor_x, "sensor_x", db);
ReadField<ErrorPolicy_Igno>(dest.clipsta, "clipsta", db);
ReadField<ErrorPolicy_Igno>(dest.clipend, "clipend", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MirrorModifierData>(
MirrorModifierData &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob, "*mirror_ob", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Image>(
Image &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadField<ErrorPolicy_Igno>(dest.ok, "ok", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.source, "source", db);
ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
ReadField<ErrorPolicy_Igno>(dest.pad1, "pad1", db);
ReadField<ErrorPolicy_Igno>(dest.lastframe, "lastframe", db);
ReadField<ErrorPolicy_Igno>(dest.tpageflag, "tpageflag", db);
ReadField<ErrorPolicy_Igno>(dest.totbind, "totbind", db);
ReadField<ErrorPolicy_Igno>(dest.xrep, "xrep", db);
ReadField<ErrorPolicy_Igno>(dest.yrep, "yrep", db);
ReadField<ErrorPolicy_Igno>(dest.twsta, "twsta", db);
ReadField<ErrorPolicy_Igno>(dest.twend, "twend", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile, "*packedfile", db);
ReadField<ErrorPolicy_Igno>(dest.lastupdate, "lastupdate", db);
ReadField<ErrorPolicy_Igno>(dest.lastused, "lastused", db);
ReadField<ErrorPolicy_Igno>(dest.animspeed, "animspeed", db);
ReadField<ErrorPolicy_Igno>(dest.gen_x, "gen_x", db);
ReadField<ErrorPolicy_Igno>(dest.gen_y, "gen_y", db);
ReadField<ErrorPolicy_Igno>(dest.gen_type, "gen_type", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CustomData>(
CustomData &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CustomDataLayer>(
CustomDataLayer &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
void DNA::RegisterConverters() {
converters["Object"] = DNA::FactoryPair(&Structure::Allocate<Object>, &Structure::Convert<Object>);
converters["Group"] = DNA::FactoryPair(&Structure::Allocate<Group>, &Structure::Convert<Group>);
converters["MTex"] = DNA::FactoryPair(&Structure::Allocate<MTex>, &Structure::Convert<MTex>);
converters["TFace"] = DNA::FactoryPair(&Structure::Allocate<TFace>, &Structure::Convert<TFace>);
converters["SubsurfModifierData"] = DNA::FactoryPair(&Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData>);
converters["MFace"] = DNA::FactoryPair(&Structure::Allocate<MFace>, &Structure::Convert<MFace>);
converters["Lamp"] = DNA::FactoryPair(&Structure::Allocate<Lamp>, &Structure::Convert<Lamp>);
converters["MDeformWeight"] = DNA::FactoryPair(&Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight>);
converters["PackedFile"] = DNA::FactoryPair(&Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile>);
converters["Base"] = DNA::FactoryPair(&Structure::Allocate<Base>, &Structure::Convert<Base>);
converters["MTFace"] = DNA::FactoryPair(&Structure::Allocate<MTFace>, &Structure::Convert<MTFace>);
converters["Material"] = DNA::FactoryPair(&Structure::Allocate<Material>, &Structure::Convert<Material>);
converters["MTexPoly"] = DNA::FactoryPair(&Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly>);
converters["Mesh"] = DNA::FactoryPair(&Structure::Allocate<Mesh>, &Structure::Convert<Mesh>);
converters["MDeformVert"] = DNA::FactoryPair(&Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert>);
converters["World"] = DNA::FactoryPair(&Structure::Allocate<World>, &Structure::Convert<World>);
converters["MLoopCol"] = DNA::FactoryPair(&Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol>);
converters["MVert"] = DNA::FactoryPair(&Structure::Allocate<MVert>, &Structure::Convert<MVert>);
converters["MEdge"] = DNA::FactoryPair(&Structure::Allocate<MEdge>, &Structure::Convert<MEdge>);
converters["MLoopUV"] = DNA::FactoryPair(&Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV>);
converters["GroupObject"] = DNA::FactoryPair(&Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject>);
converters["ListBase"] = DNA::FactoryPair(&Structure::Allocate<ListBase>, &Structure::Convert<ListBase>);
converters["MLoop"] = DNA::FactoryPair(&Structure::Allocate<MLoop>, &Structure::Convert<MLoop>);
converters["ModifierData"] = DNA::FactoryPair(&Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData>);
converters["ID"] = DNA::FactoryPair(&Structure::Allocate<ID>, &Structure::Convert<ID>);
converters["MCol"] = DNA::FactoryPair(&Structure::Allocate<MCol>, &Structure::Convert<MCol>);
converters["MPoly"] = DNA::FactoryPair(&Structure::Allocate<MPoly>, &Structure::Convert<MPoly>);
converters["Scene"] = DNA::FactoryPair(&Structure::Allocate<Scene>, &Structure::Convert<Scene>);
converters["Library"] = DNA::FactoryPair(&Structure::Allocate<Library>, &Structure::Convert<Library>);
converters["Tex"] = DNA::FactoryPair(&Structure::Allocate<Tex>, &Structure::Convert<Tex>);
converters["Camera"] = DNA::FactoryPair(&Structure::Allocate<Camera>, &Structure::Convert<Camera>);
converters["MirrorModifierData"] = DNA::FactoryPair(&Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData>);
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -55,7 +55,6 @@ namespace Blender {
// declared in the ./source/blender/makesdna directory.
// Stuff that is not used by Assimp is commented.
// NOTE
// this file serves as input data to the `./scripts/genblenddna.py`
// script. This script generates the actual binding code to read a
@ -127,7 +126,6 @@ struct ListBase : ElemBase {
std::shared_ptr<ElemBase> last;
};
// -------------------------------------------------------------------------------
struct PackedFile : ElemBase {
int size WARN;
@ -157,16 +155,13 @@ struct World : ElemBase {
// -------------------------------------------------------------------------------
struct MVert : ElemBase {
float co[3] FAIL;
float no[3] FAIL; // readed as short and divided through / 32767.f
float no[3] FAIL; // read as short and divided through / 32767.f
char flag;
int mat_nr WARN;
int bweight;
MVert() : ElemBase()
, flag(0)
, mat_nr(0)
, bweight(0)
{}
MVert() :
ElemBase(), flag(0), mat_nr(0), bweight(0) {}
};
// -------------------------------------------------------------------------------
@ -232,12 +227,11 @@ struct TFace : ElemBase {
// -------------------------------------------------------------------------------
struct MTFace : ElemBase {
MTFace()
: flag(0)
, mode(0)
, tile(0)
, unwrap(0)
{
MTFace() :
flag(0),
mode(0),
tile(0),
unwrap(0) {
}
float uv[4][2] FAIL;
@ -401,18 +395,17 @@ struct CustomDataLayer : ElemBase {
char name[64];
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
CustomDataLayer()
: ElemBase()
, type(0)
, offset(0)
, flag(0)
, active(0)
, active_rnd(0)
, active_clone(0)
, active_mask(0)
, uid(0)
, data(nullptr)
{
CustomDataLayer() :
ElemBase(),
type(0),
offset(0),
flag(0),
active(0),
active_rnd(0),
active_clone(0),
active_mask(0),
uid(0),
data(nullptr) {
memset(name, 0, sizeof name);
}
};
@ -490,8 +483,8 @@ struct Library : ElemBase {
// -------------------------------------------------------------------------------
struct Camera : ElemBase {
enum Type {
Type_PERSP = 0
,Type_ORTHO = 1
Type_PERSP = 0,
Type_ORTHO = 1
};
ID id FAIL;
@ -502,24 +495,23 @@ struct Camera : ElemBase {
float clipsta, clipend;
};
// -------------------------------------------------------------------------------
struct Lamp : ElemBase {
enum FalloffType {
FalloffType_Constant = 0x0
,FalloffType_InvLinear = 0x1
,FalloffType_InvSquare = 0x2
FalloffType_Constant = 0x0,
FalloffType_InvLinear = 0x1,
FalloffType_InvSquare = 0x2
//,FalloffType_Curve = 0x3
//,FalloffType_Sliders = 0x4
};
enum Type {
Type_Local = 0x0
,Type_Sun = 0x1
,Type_Spot = 0x2
,Type_Hemi = 0x3
,Type_Area = 0x4
Type_Local = 0x0,
Type_Sun = 0x1,
Type_Spot = 0x2,
Type_Hemi = 0x3,
Type_Area = 0x4
//,Type_YFPhoton = 0x5
};
@ -681,18 +673,20 @@ struct Object : ElemBase {
ID id FAIL;
enum Type {
Type_EMPTY = 0
,Type_MESH = 1
,Type_CURVE = 2
,Type_SURF = 3
,Type_FONT = 4
,Type_MBALL = 5
Type_EMPTY = 0,
Type_MESH = 1,
Type_CURVE = 2,
Type_SURF = 3,
Type_FONT = 4,
Type_MBALL = 5
,Type_LAMP = 10
,Type_CAMERA = 11
,
Type_LAMP = 10,
Type_CAMERA = 11
,Type_WAVE = 21
,Type_LATTICE = 22
,
Type_WAVE = 21,
Type_LATTICE = 22
};
Type type FAIL;
@ -709,30 +703,20 @@ struct Object : ElemBase {
ListBase modifiers;
Object()
: ElemBase()
, type( Type_EMPTY )
, parent( nullptr )
, track()
, proxy()
, proxy_from()
, data() {
Object() :
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
// empty
}
};
// -------------------------------------------------------------------------------
struct Base : ElemBase {
Base *prev WARN;
std::shared_ptr<Base> next WARN;
std::shared_ptr<Object> object WARN;
Base()
: ElemBase()
, prev( nullptr )
, next()
, object() {
Base() :
ElemBase(), prev(nullptr), next(), object() {
// empty
// empty
}
@ -748,11 +732,8 @@ struct Scene : ElemBase {
ListBase base;
Scene()
: ElemBase()
, camera()
, world()
, basact() {
Scene() :
ElemBase(), camera(), world(), basact() {
// empty
}
};
@ -784,8 +765,8 @@ struct Image : ElemBase {
short gen_x, gen_y, gen_type;
Image()
: ElemBase() {
Image() :
ElemBase() {
// empty
}
};
@ -795,33 +776,33 @@ struct Tex : ElemBase {
// actually, the only texture type we support is Type_IMAGE
enum Type {
Type_CLOUDS = 1
,Type_WOOD = 2
,Type_MARBLE = 3
,Type_MAGIC = 4
,Type_BLEND = 5
,Type_STUCCI = 6
,Type_NOISE = 7
,Type_IMAGE = 8
,Type_PLUGIN = 9
,Type_ENVMAP = 10
,Type_MUSGRAVE = 11
,Type_VORONOI = 12
,Type_DISTNOISE = 13
,Type_POINTDENSITY = 14
,Type_VOXELDATA = 15
Type_CLOUDS = 1,
Type_WOOD = 2,
Type_MARBLE = 3,
Type_MAGIC = 4,
Type_BLEND = 5,
Type_STUCCI = 6,
Type_NOISE = 7,
Type_IMAGE = 8,
Type_PLUGIN = 9,
Type_ENVMAP = 10,
Type_MUSGRAVE = 11,
Type_VORONOI = 12,
Type_DISTNOISE = 13,
Type_POINTDENSITY = 14,
Type_VOXELDATA = 15
};
enum ImageFlags {
ImageFlags_INTERPOL = 1
,ImageFlags_USEALPHA = 2
,ImageFlags_MIPMAP = 4
,ImageFlags_IMAROT = 16
,ImageFlags_CALCALPHA = 32
,ImageFlags_NORMALMAP = 2048
,ImageFlags_GAUSS_MIP = 4096
,ImageFlags_FILTER_MIN = 8192
,ImageFlags_DERIVATIVEMAP = 16384
ImageFlags_INTERPOL = 1,
ImageFlags_USEALPHA = 2,
ImageFlags_MIPMAP = 4,
ImageFlags_IMAROT = 16,
ImageFlags_CALCALPHA = 32,
ImageFlags_NORMALMAP = 2048,
ImageFlags_GAUSS_MIP = 4096,
ImageFlags_FILTER_MIN = 8192,
ImageFlags_DERIVATIVEMAP = 16384
};
ID id FAIL;
@ -876,11 +857,8 @@ struct Tex : ElemBase {
//char use_nodes;
Tex()
: ElemBase()
, imaflag( ImageFlags_INTERPOL )
, type( Type_CLOUDS )
, ima() {
Tex() :
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
// empty
}
};
@ -889,52 +867,52 @@ struct Tex : ElemBase {
struct MTex : ElemBase {
enum Projection {
Proj_N = 0
,Proj_X = 1
,Proj_Y = 2
,Proj_Z = 3
Proj_N = 0,
Proj_X = 1,
Proj_Y = 2,
Proj_Z = 3
};
enum Flag {
Flag_RGBTOINT = 0x1
,Flag_STENCIL = 0x2
,Flag_NEGATIVE = 0x4
,Flag_ALPHAMIX = 0x8
,Flag_VIEWSPACE = 0x10
Flag_RGBTOINT = 0x1,
Flag_STENCIL = 0x2,
Flag_NEGATIVE = 0x4,
Flag_ALPHAMIX = 0x8,
Flag_VIEWSPACE = 0x10
};
enum BlendType {
BlendType_BLEND = 0
,BlendType_MUL = 1
,BlendType_ADD = 2
,BlendType_SUB = 3
,BlendType_DIV = 4
,BlendType_DARK = 5
,BlendType_DIFF = 6
,BlendType_LIGHT = 7
,BlendType_SCREEN = 8
,BlendType_OVERLAY = 9
,BlendType_BLEND_HUE = 10
,BlendType_BLEND_SAT = 11
,BlendType_BLEND_VAL = 12
,BlendType_BLEND_COLOR = 13
BlendType_BLEND = 0,
BlendType_MUL = 1,
BlendType_ADD = 2,
BlendType_SUB = 3,
BlendType_DIV = 4,
BlendType_DARK = 5,
BlendType_DIFF = 6,
BlendType_LIGHT = 7,
BlendType_SCREEN = 8,
BlendType_OVERLAY = 9,
BlendType_BLEND_HUE = 10,
BlendType_BLEND_SAT = 11,
BlendType_BLEND_VAL = 12,
BlendType_BLEND_COLOR = 13
};
enum MapType {
MapType_COL = 1
,MapType_NORM = 2
,MapType_COLSPEC = 4
,MapType_COLMIR = 8
,MapType_REF = 16
,MapType_SPEC = 32
,MapType_EMIT = 64
,MapType_ALPHA = 128
,MapType_HAR = 256
,MapType_RAYMIRR = 512
,MapType_TRANSLU = 1024
,MapType_AMB = 2048
,MapType_DISPLACE = 4096
,MapType_WARP = 8192
MapType_COL = 1,
MapType_NORM = 2,
MapType_COLSPEC = 4,
MapType_COLMIR = 8,
MapType_REF = 16,
MapType_SPEC = 32,
MapType_EMIT = 64,
MapType_ALPHA = 128,
MapType_HAR = 256,
MapType_RAYMIRR = 512,
MapType_TRANSLU = 1024,
MapType_AMB = 2048,
MapType_DISPLACE = 4096,
MapType_WARP = 8192
};
// short texco, maptoneg;
@ -972,12 +950,12 @@ struct MTex : ElemBase {
//float shadowfac;
//float zenupfac, zendownfac, blendfac;
MTex()
: ElemBase() {
MTex() :
ElemBase() {
// empty
}
};
}
}
} // namespace Blender
} // namespace Assimp
#endif

View File

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

View File

@ -43,21 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the TrueSpace COB/SCN importer class.
*/
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
#include "COB/COBLoader.h"
#include "COB/COBScene.h"
#include "AssetLib/COB/COBLoader.h"
#include "AssetLib/COB/COBScene.h"
#include "PostProcessing/ConvertToLHProcess.h"
#include <assimp/StreamReader.h>
#include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h>
#include <assimp/LineSplitter.h>
#include <assimp/ParsingUtils.h>
#include <assimp/StreamReader.h>
#include <assimp/TinyFormatter.h>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
@ -65,7 +64,6 @@ using namespace Assimp;
using namespace Assimp::COB;
using namespace Assimp::Formatter;
static const float units[] = {
1000.f,
100.f,
@ -90,21 +88,17 @@ static const aiImporterDesc desc = {
"cob scn"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
COBImporter::COBImporter()
{}
COBImporter::COBImporter() {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
COBImporter::~COBImporter()
{}
COBImporter::~COBImporter() {}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
const std::string &extension = GetExtension(pFile);
if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
return true;
@ -119,22 +113,19 @@ bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc* COBImporter::GetInfo () const
{
const aiImporterDesc *COBImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void COBImporter::SetupProperties(const Importer* /*pImp*/)
{
void COBImporter::SetupProperties(const Importer * /*pImp*/) {
// nothing to be done for the moment
}
// ------------------------------------------------------------------------------------------------
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string& msg)
{
throw DeadlyImportError("COB: "+msg);
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
throw DeadlyImportError("COB: ", msg);
}
// ------------------------------------------------------------------------------------------------
@ -158,8 +149,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
// load data into intermediate structures
if (head[15] == 'A') {
ReadAsciiFile(scene, stream.get());
}
else {
} else {
ReadBinaryFile(scene, stream.get());
}
if (scene.nodes.empty()) {
@ -193,8 +183,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
for (std::shared_ptr<Node> &n : scene.nodes) {
if (n->type == Node::TYPE_LIGHT) {
++pScene->mNumLights;
}
else if (n->type == Node::TYPE_CAMERA) {
} else if (n->type == Node::TYPE_CAMERA) {
++pScene->mNumCameras;
}
}
@ -230,16 +219,14 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
}
// ------------------------------------------------------------------------------------------------
void ConvertTexture(std::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type)
{
void ConvertTexture(std::shared_ptr<Texture> tex, aiMaterial *out, aiTextureType type) {
const aiString path(tex->path);
out->AddProperty(&path, AI_MATKEY_TEXTURE(type, 0));
out->AddProperty(&tex->transform, 1, AI_MATKEY_UVTRANSFORM(type, 0));
}
// ------------------------------------------------------------------------------------------------
aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill)
{
aiNode *COBImporter::BuildNodes(const Node &root, const Scene &scin, aiScene *fill) {
aiNode *nd = new aiNode();
nd->mName.Set(root.name);
nd->mTransformation = root.transform;
@ -286,15 +273,15 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D(
ndmesh.texture_coords[v.uv_idx].x,
ndmesh.texture_coords[v.uv_idx].y,
0.f
);
0.f);
fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++;
}
}
outmesh->mMaterialIndex = fill->mNumMaterials;
}{ // create material
const Material* min = NULL;
}
{ // create material
const Material *min = nullptr;
for (const Material &m : scin.materials) {
if (m.parent_id == ndmesh.id && m.matnum == reflist.first) {
min = &m;
@ -303,7 +290,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
}
std::unique_ptr<const Material> defmat;
if (!min) {
ASSIMP_LOG_DEBUG(format()<<"Could not resolve material index "
ASSIMP_LOG_VERBOSE_DEBUG(format() << "Could not resolve material index "
<< reflist.first << " - creating default material for this slot");
defmat.reset(min = new Material());
@ -319,9 +306,9 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
mat->AddProperty(&tmp, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
{ int shader;
switch(min->shader)
{
int shader;
switch (min->shader) {
case Material::FLAT:
shader = aiShadingMode_Gouraud;
break;
@ -335,7 +322,9 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
break;
default:
ASSIMP_LOG_ERROR("Unknown option.");
ai_assert(false); // shouldn't be here
break;
}
mat->AddProperty(&shader, 1, AI_MATKEY_SHADING_MODEL);
if (shader != aiShadingMode_Gouraud) {
@ -365,8 +354,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
}
}
}
}
else if (Node::TYPE_LIGHT == root.type) {
} else if (Node::TYPE_LIGHT == root.type) {
const Light &ndlight = (const Light &)(root);
aiLight *outlight = fill->mLights[fill->mNumLights++] = new aiLight();
@ -378,8 +366,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
// XXX
outlight->mType = ndlight.ltype == Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL;
}
else if (Node::TYPE_CAMERA == root.type) {
} else if (Node::TYPE_CAMERA == root.type) {
const Camera &ndcam = (const Camera &)(root);
aiCamera *outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera();
@ -387,7 +374,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
}
// add meshes
if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0
if (nd->mNumMeshes) { // mMeshes must be nullptr if count is 0
nd->mMeshes = new unsigned int[nd->mNumMeshes];
for (unsigned int i = 0; i < nd->mNumMeshes; ++i) {
nd->mMeshes[i] = fill->mNumMeshes - i - 1;
@ -405,8 +392,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
// ------------------------------------------------------------------------------------------------
// Read an ASCII file into the given scene data structure
void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
{
void COBImporter::ReadAsciiFile(Scene &out, StreamReaderLE *stream) {
ChunkInfo ci;
for (LineSplitter splitter(*stream); splitter; ++splitter) {
@ -456,8 +442,7 @@ void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter)
{
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo &out, const LineSplitter &splitter) {
const char *all_tokens[8];
splitter.get_tokens(all_tokens);
@ -468,10 +453,8 @@ void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitt
}
// ------------------------------------------------------------------------------------------------
void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name)
{
const std::string error = format("Encountered unsupported chunk: ") << name <<
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
void COBImporter::UnsupportedChunk_Ascii(LineSplitter &splitter, const ChunkInfo &nfo, const char *name) {
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
// we can recover if the chunk size was specified.
if (nfo.size != static_cast<unsigned int>(-1)) {
@ -483,13 +466,12 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
// missing the next line.
splitter.get_stream().IncPtr(nfo.size);
splitter.swallow_next_increment();
}
else ThrowException(error);
} else
ThrowException(error);
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
{
void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, const ChunkInfo & /*nfo*/) {
for (; splitter; ++splitter) {
if (splitter.match_start("Name")) {
msh.name = std::string(splitter[1]);
@ -497,8 +479,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
// make nice names by merging the dupe count
std::replace(msh.name.begin(), msh.name.end(),
',', '_');
}
else if (splitter.match_start("Transform")) {
} else if (splitter.match_start("Transform")) {
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
const char *s = splitter->c_str();
for (unsigned int x = 0; x < 4; ++x) {
@ -514,8 +495,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
// ------------------------------------------------------------------------------------------------
template <typename T>
void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
{
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in) {
const char *rgb = *in;
for (unsigned int i = 0; i < 3; ++i) {
SkipSpaces(&rgb);
@ -528,8 +508,7 @@ void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadMat1_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Ascii(splitter, nfo, "Mat1");
}
@ -556,11 +535,9 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
if (shader == "metal") {
mat.shader = Material::METAL;
}
else if (shader == "phong") {
} else if (shader == "phong") {
mat.shader = Material::PHONG;
}
else if (shader != "flat") {
} else if (shader != "flat") {
ASSIMP_LOG_WARN_F("Unknown value for `shader` in `Mat1` chunk ", nfo.id);
}
@ -588,8 +565,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadUnit_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 1) {
return UnsupportedChunk_Ascii(splitter, nfo, "Unit");
}
@ -606,8 +582,8 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
const unsigned int t = strtoul10(splitter[1]);
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
,1.f):units[t];
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
units[t];
return;
}
}
@ -615,16 +591,14 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadChan_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadChan_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Ascii(splitter, nfo, "Chan");
}
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadLght_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Ascii(splitter, nfo, "Lght");
}
@ -637,14 +611,11 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
if (splitter.match_start("Infinite ")) {
msh.ltype = Light::INFINITE;
}
else if (splitter.match_start("Local ")) {
} else if (splitter.match_start("Local ")) {
msh.ltype = Light::LOCAL;
}
else if (splitter.match_start("Spot ")) {
} else if (splitter.match_start("Spot ")) {
msh.ltype = Light::SPOT;
}
else {
} else {
ASSIMP_LOG_WARN_F("Unknown kind of light source in `Lght` chunk ", nfo.id, " : ", *splitter);
msh.ltype = Light::SPOT;
}
@ -675,8 +646,7 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadCame_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 2) {
return UnsupportedChunk_Ascii(splitter, nfo, "Came");
}
@ -693,8 +663,7 @@ void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadBone_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 5) {
return UnsupportedChunk_Ascii(splitter, nfo, "Bone");
}
@ -709,8 +678,7 @@ void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadGrou_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 1) {
return UnsupportedChunk_Ascii(splitter, nfo, "Grou");
}
@ -723,8 +691,7 @@ void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Ascii(splitter, nfo, "PolH");
}
@ -755,8 +722,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
SkipSpaces(&s);
v.z = fast_atof(&s);
}
}
else if (splitter.match_start("Texture Vertices")) {
} else if (splitter.match_start("Texture Vertices")) {
const unsigned int cnt = strtoul10(splitter[2]);
msh.texture_coords.resize(cnt);
@ -770,8 +736,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
SkipSpaces(&s);
v.y = fast_atof(&s);
}
}
else if (splitter.match_start("Faces")) {
} else if (splitter.match_start("Faces")) {
const unsigned int cnt = strtoul10(splitter[1]);
msh.faces.reserve(cnt);
@ -813,8 +778,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
if (nfo.version <= 4) {
break;
}
}
else if (splitter.match_start("DrawFlags")) {
} else if (splitter.match_start("DrawFlags")) {
msh.draw_flags = strtoul10(splitter[1]);
break;
}
@ -822,8 +786,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
{
void COBImporter::ReadBitM_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
if (nfo.version > 1) {
return UnsupportedChunk_Ascii(splitter, nfo, "BitM");
}
@ -849,8 +812,7 @@ void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const C
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
{
void COBImporter::ReadString_Binary(std::string &out, StreamReaderLE &reader) {
out.resize(reader.GetI2());
for (char &c : out) {
c = reader.GetI1();
@ -858,8 +820,7 @@ void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/)
{
void COBImporter::ReadBasicNodeInfo_Binary(Node &msh, StreamReaderLE &reader, const ChunkInfo & /*nfo*/) {
const unsigned int dupes = reader.GetI2();
ReadString_Binary(msh.name, reader);
@ -877,27 +838,23 @@ void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, co
}
// ------------------------------------------------------------------------------------------------
void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkInfo& nfo, const char* name)
{
const std::string error = format("Encountered unsupported chunk: ") << name <<
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
void COBImporter::UnsupportedChunk_Binary(StreamReaderLE &reader, const ChunkInfo &nfo, const char *name) {
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
// we can recover if the chunk size was specified.
if (nfo.size != static_cast<unsigned int>(-1)) {
ASSIMP_LOG_ERROR(error);
reader.IncPtr(nfo.size);
}
else ThrowException(error);
} else
ThrowException(error);
}
// ------------------------------------------------------------------------------------------------
// tiny utility guard to aid me at staying within chunk boundaries.
class chunk_guard {
public:
chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader)
: nfo(nfo)
, reader(reader)
, cur(reader.GetCurrentPos()) {
chunk_guard(const COB::ChunkInfo &nfo, StreamReaderLE &reader) :
nfo(nfo), reader(reader), cur(reader.GetCurrentPos()) {
// empty
}
@ -927,11 +884,7 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
while (1) {
std::string type;
type += reader -> GetI1()
,type += reader -> GetI1()
,type += reader -> GetI1()
,type += reader -> GetI1()
;
type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1();
ChunkInfo nfo;
nfo.version = reader->GetI2() * 10;
@ -943,20 +896,15 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
if (type == "PolH") {
ReadPolH_Binary(out, *reader, nfo);
}
else if (type == "BitM") {
} else if (type == "BitM") {
ReadBitM_Binary(out, *reader, nfo);
}
else if (type == "Grou") {
} else if (type == "Grou") {
ReadGrou_Binary(out, *reader, nfo);
}
else if (type == "Lght") {
} else if (type == "Lght") {
ReadLght_Binary(out, *reader, nfo);
}
else if (type == "Came") {
} else if (type == "Came") {
ReadCame_Binary(out, *reader, nfo);
}
else if (type == "Mat1") {
} else if (type == "Mat1") {
ReadMat1_Binary(out, *reader, nfo);
}
/* else if (type == "Bone") {
@ -967,24 +915,21 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
}*/
else if (type == "Unit") {
ReadUnit_Binary(out, *reader, nfo);
}
else if (type == "OLay") {
} else if (type == "OLay") {
// ignore layer index silently.
if (nfo.size != static_cast<unsigned int>(-1)) {
reader->IncPtr(nfo.size);
}
else return UnsupportedChunk_Binary(*reader,nfo,type.c_str());
}
else if (type == "END ") {
} else
return UnsupportedChunk_Binary(*reader, nfo, type.c_str());
} else if (type == "END ") {
return;
}
else UnsupportedChunk_Binary(*reader,nfo,type.c_str());
} else
UnsupportedChunk_Binary(*reader, nfo, type.c_str());
}
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadPolH_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Binary(reader, nfo, "PolH");
}
@ -1023,8 +968,8 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
if (msh.faces.empty()) {
ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id);
}
}
else msh.faces.push_back(Face());
} else
msh.faces.push_back(Face());
Face &f = msh.faces.back();
const size_t num = reader.GetI2();
@ -1054,8 +999,7 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadBitM_Binary(COB::Scene & /*out*/, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 1) {
return UnsupportedChunk_Binary(reader, nfo, "BitM");
}
@ -1070,8 +1014,7 @@ void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, c
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadMat1_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 8) {
return UnsupportedChunk_Binary(reader, nfo, "Mat1");
}
@ -1172,8 +1115,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadCame_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 2) {
return UnsupportedChunk_Binary(reader, nfo, "Came");
}
@ -1195,8 +1137,7 @@ void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadLght_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 2) {
return UnsupportedChunk_Binary(reader, nfo, "Lght");
}
@ -1211,8 +1152,7 @@ void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadGrou_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 2) {
return UnsupportedChunk_Binary(reader, nfo, "Grou");
}
@ -1227,8 +1167,7 @@ void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const
}
// ------------------------------------------------------------------------------------------------
void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
{
void COBImporter::ReadUnit_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
if (nfo.version > 1) {
return UnsupportedChunk_Binary(reader, nfo, "Unit");
}
@ -1241,8 +1180,8 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
if (nd->id == nfo.parent_id) {
const unsigned int t = reader.GetI2();
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
ASSIMP_LOG_WARN_F(t," is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
,1.f):units[t];
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
units[t];
return;
}

View File

@ -127,8 +127,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
// Check whether we can read from the file
if( file.get() == NULL) {
throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
if( file.get() == nullptr) {
throw DeadlyImportError( "Failed to open CSM file ", pFile, ".");
}
// allocate storage and copy the contents of the file to a memory buffer
@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
*ot++ = *buffer++;
*ot = '\0';
nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
}
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,257 @@
/*
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 ColladaExporter.h
* Declares the exporter class to write a scene to a Collada file
*/
#ifndef AI_COLLADAEXPORTER_H_INC
#define AI_COLLADAEXPORTER_H_INC
#include <assimp/ai_assert.h>
#include <assimp/material.h>
#include <array>
#include <map>
#include <sstream>
#include <unordered_set>
#include <vector>
struct aiScene;
struct aiNode;
struct aiLight;
struct aiBone;
namespace Assimp {
class IOSystem;
/// Helper class to export a given scene to a Collada file. Just for my personal
/// comfort when implementing it.
class ColladaExporter {
public:
/// Constructor for a specific scene to export
ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file);
/// Destructor
virtual ~ColladaExporter();
protected:
/// Starts writing the contents
void WriteFile();
/// Writes the asset header
void WriteHeader();
/// Writes the embedded textures
void WriteTextures();
/// Writes the material setup
void WriteMaterials();
/// Writes the cameras library
void WriteCamerasLibrary();
// Write a camera entry
void WriteCamera(size_t pIndex);
/// Writes the cameras library
void WriteLightsLibrary();
// Write a camera entry
void WriteLight(size_t pIndex);
void WritePointLight(const aiLight *const light);
void WriteDirectionalLight(const aiLight *const light);
void WriteSpotLight(const aiLight *const light);
void WriteAmbienttLight(const aiLight *const light);
/// Writes the controller library
void WriteControllerLibrary();
/// Writes a skin controller of the given mesh
void WriteController(size_t pIndex);
/// Writes the geometry library
void WriteGeometryLibrary();
/// Writes the given mesh
void WriteGeometry(size_t pIndex);
//enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
// customized to add animation related type
enum FloatDataType { FloatType_Vector,
FloatType_TexCoord2,
FloatType_TexCoord3,
FloatType_Color,
FloatType_Mat4x4,
FloatType_Weight,
FloatType_Time };
/// Writes a float array of the given type
void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount);
/// Writes the scene library
void WriteSceneLibrary();
// customized, Writes the animation library
void WriteAnimationsLibrary();
void WriteAnimationLibrary(size_t pIndex);
std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call.
/// Recursively writes the given node
void WriteNode(const aiNode *pNode);
/// Enters a new xml element, which increases the indentation
void PushTag() { startstr.append(" "); }
/// Leaves an element, decreasing the indentation
void PopTag() {
ai_assert(startstr.length() > 1);
startstr.erase(startstr.length() - 2);
}
void CreateNodeIds(const aiNode *node);
/// Get or Create a unique Node ID string for the given Node
std::string GetNodeUniqueId(const aiNode *node);
std::string GetNodeName(const aiNode *node);
std::string GetBoneUniqueId(const aiBone *bone);
enum class AiObjectType {
Mesh,
Material,
Animation,
Light,
Camera,
Count,
};
/// Get or Create a unique ID string for the given scene object index
std::string GetObjectUniqueId(AiObjectType type, size_t pIndex);
/// Get or Create a name string for the given scene object index
std::string GetObjectName(AiObjectType type, size_t pIndex);
typedef std::map<size_t, std::string> IndexIdMap;
typedef std::pair<std::string, std::string> NameIdPair;
NameIdPair AddObjectIndexToMaps(AiObjectType type, size_t pIndex);
// Helpers
inline IndexIdMap &GetObjectIdMap(AiObjectType type) { return mObjectIdMap[static_cast<size_t>(type)]; }
inline IndexIdMap &GetObjectNameMap(AiObjectType type) { return mObjectNameMap[static_cast<size_t>(type)]; }
private:
std::unordered_set<std::string> mUniqueIds; // Cache of used unique ids
std::map<const void *, std::string> mNodeIdMap; // Cache of encoded node and bone ids
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectIdMap; // Cache of encoded unique IDs
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectNameMap; // Cache of encoded names
public:
/// Stringstream to write all output into
std::stringstream mOutput;
/// The IOSystem for output
IOSystem *mIOSystem;
/// Path of the directory where the scene will be exported
const std::string mPath;
/// Name of the file (without extension) where the scene will be exported
const std::string mFile;
/// The scene to be written
const aiScene *const mScene;
std::string mSceneId;
bool mAdd_root_node = false;
/// current line start string, contains the current indentation for simple stream insertion
std::string startstr;
/// current line end string for simple stream insertion
const std::string endstr;
// pair of color and texture - texture precedences color
struct Surface {
bool exist;
aiColor4D color;
std::string texture;
size_t channel;
Surface() {
exist = false;
channel = 0;
}
};
struct Property {
bool exist;
ai_real value;
Property() :
exist(false),
value(0.0) {}
};
// summarize a material in an convenient way.
struct Material {
std::string id;
std::string name;
std::string shading_model;
Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
Property shininess, transparency, index_refraction;
Material() {}
};
std::map<unsigned int, std::string> textures;
public:
/// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
/// Reads a single surface entry from the given material keys
bool ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex);
/// Writes an image entry for the given surface
void WriteImageEntry(const Surface &pSurface, const std::string &imageId);
/// Writes the two parameters necessary for referencing a texture in an effect entry
void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId);
/// Writes a color-or-texture entry into an effect definition
void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId);
/// Writes a scalar property
void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName);
};
} // namespace Assimp
#endif // !! AI_COLLADAEXPORTER_H_INC

View File

@ -1,5 +1,3 @@
/** Helper structures for the Collada loader */
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
@ -40,11 +38,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** Helper structures for the Collada loader */
#include "ColladaHelper.h"
#include <assimp/commonMetaData.h>
#include <assimp/ParsingUtils.h>
#include <assimp/commonMetaData.h>
namespace Assimp {
namespace Collada {
@ -54,7 +53,7 @@ const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
return result;
};
}
const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
@ -63,39 +62,32 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
for (auto &val : result)
{
for (auto &val : result) {
ToCamelCase(val.first);
}
return result;
};
}
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
{
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
return result;
}
// ------------------------------------------------------------------------------------------------
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
void ToCamelCase(std::string &text)
{
void ToCamelCase(std::string &text) {
if (text.empty())
return;
// Capitalise first character
auto it = text.begin();
(*it) = ToUpper(*it);
++it;
for (/*started above*/ ; it != text.end(); /*iterated below*/)
{
if ((*it) == '_')
{
for (/*started above*/; it != text.end(); /*iterated below*/) {
if ((*it) == '_') {
it = text.erase(it);
if (it != text.end())
(*it) = ToUpper(*it);
}
else
{
} else {
// Make lower case
(*it) = ToLower(*it);
++it;

View File

@ -0,0 +1,678 @@
/*
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.
----------------------------------------------------------------------
*/
/** Helper structures for the Collada loader */
#ifndef AI_COLLADAHELPER_H_INC
#define AI_COLLADAHELPER_H_INC
#include <assimp/light.h>
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <stdint.h>
#include <map>
#include <set>
#include <vector>
struct aiMaterial;
namespace Assimp {
namespace Collada {
/// Collada file versions which evolved during the years ...
enum FormatVersion {
FV_1_5_n,
FV_1_4_n,
FV_1_3_n
};
/// Transformation types that can be applied to a node
enum TransformType {
TF_LOOKAT,
TF_ROTATE,
TF_TRANSLATE,
TF_SCALE,
TF_SKEW,
TF_MATRIX
};
/// Different types of input data to a vertex or face
enum InputType {
IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Position,
IT_Normal,
IT_Texcoord,
IT_Color,
IT_Tangent,
IT_Bitangent
};
/// Supported controller types
enum ControllerType {
Skin,
Morph
};
/// Supported morph methods
enum MorphMethod {
Normalized,
Relative
};
/// Common metadata keys as <Collada, Assimp>
using MetaKeyPair = std::pair<std::string, std::string>;
using MetaKeyPairVector = std::vector<MetaKeyPair>;
/// Collada as lower_case (native)
const MetaKeyPairVector &GetColladaAssimpMetaKeys();
// Collada as CamelCase (used by Assimp for consistency)
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
/// Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool"
void ToCamelCase(std::string &text);
/// Contains all data for one of the different transformation types
struct Transform {
std::string mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType;
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
};
/// A collada camera.
struct Camera {
Camera() :
mOrtho(false),
mHorFov(10e10f),
mVerFov(10e10f),
mAspect(10e10f),
mZNear(0.1f),
mZFar(1000.f) {}
/// Name of camera
std::string mName;
/// True if it is an orthographic camera
bool mOrtho;
/// Horizontal field of view in degrees
ai_real mHorFov;
/// Vertical field of view in degrees
ai_real mVerFov;
/// Screen aspect
ai_real mAspect;
/// Near& far z
ai_real mZNear, mZFar;
};
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
/** A collada light source. */
struct Light {
Light() :
mType(aiLightSource_UNDEFINED),
mAttConstant(1.f),
mAttLinear(0.f),
mAttQuadratic(0.f),
mFalloffAngle(180.f),
mFalloffExponent(0.f),
mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
mIntensity(1.f) {}
/// Type of the light source aiLightSourceType + ambient
unsigned int mType;
/// Color of the light
aiColor3D mColor;
/// Light attenuation
ai_real mAttConstant, mAttLinear, mAttQuadratic;
/// Spot light falloff
ai_real mFalloffAngle;
ai_real mFalloffExponent;
// -----------------------------------------------------
// FCOLLADA extension from here
/// ... related stuff from maja and max extensions
ai_real mPenumbraAngle;
ai_real mOuterAngle;
/// Common light intensity
ai_real mIntensity;
};
/** Short vertex index description */
struct InputSemanticMapEntry {
InputSemanticMapEntry() :
mSet(0),
mType(IT_Invalid) {}
/// Index of set, optional
unsigned int mSet;
/// Type of referenced vertex input
InputType mType;
};
/// Table to map from effect to vertex input semantics
struct SemanticMappingTable {
/// Name of material
std::string mMatName;
/// List of semantic map commands, grouped by effect semantic name
std::map<std::string, InputSemanticMapEntry> mMap;
/// For std::find
bool operator==(const std::string &s) const {
return s == mMatName;
}
};
/// A reference to a mesh inside a node, including materials assigned to the various subgroups.
/// The ID refers to either a mesh or a controller which specifies the mesh
struct MeshInstance {
///< ID of the mesh or controller to be instanced
std::string mMeshOrController;
///< Map of materials by the subgroup ID they're applied to
std::map<std::string, SemanticMappingTable> mMaterials;
};
/// A reference to a camera inside a node
struct CameraInstance {
///< ID of the camera
std::string mCamera;
};
/// A reference to a light inside a node
struct LightInstance {
///< ID of the camera
std::string mLight;
};
/// A reference to a node inside a node
struct NodeInstance {
///< ID of the node
std::string mNode;
};
/// A node in a scene hierarchy
struct Node {
std::string mName;
std::string mID;
std::string mSID;
Node *mParent;
std::vector<Node *> mChildren;
/// Operations in order to calculate the resulting transformation to parent.
std::vector<Transform> mTransforms;
/// Meshes at this node
std::vector<MeshInstance> mMeshes;
/// Lights at this node
std::vector<LightInstance> mLights;
/// Cameras at this node
std::vector<CameraInstance> mCameras;
/// Node instances at this node
std::vector<NodeInstance> mNodeInstances;
/// Root-nodes: Name of primary camera, if any
std::string mPrimaryCamera;
/// Constructor. Begin with a zero parent
Node() :
mParent(nullptr) {
// empty
}
/// Destructor: delete all children subsequently
~Node() {
for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
delete *it;
}
}
};
/// Data source array: either floats or strings
struct Data {
bool mIsStringArray;
std::vector<ai_real> mValues;
std::vector<std::string> mStrings;
};
/// Accessor to a data array
struct Accessor {
size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values
size_t mStride; // Stride in number of values
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
size_t mSubOffset[4]; // Sub-offset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
std::string mSource; // URL of the source array
mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
Accessor() {
mCount = 0;
mSize = 0;
mOffset = 0;
mStride = 0;
mData = nullptr;
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
}
};
/// A single face in a mesh
struct Face {
std::vector<size_t> mIndices;
};
/// An input channel for mesh data, referring to a single accessor
struct InputChannel {
InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
std::string mAccessor; // ID of the accessor where to read the actual values from.
mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. nullptr else
InputChannel() {
mType = IT_Invalid;
mIndex = 0;
mOffset = 0;
mResolved = nullptr;
}
};
/// Subset of a mesh with a certain material
struct SubMesh {
std::string mMaterial; ///< subgroup identifier
size_t mNumFaces; ///< number of faces in this sub-mesh
};
/// Contains data for a single mesh
struct Mesh {
Mesh(const std::string &id) :
mId(id) {
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mNumUVComponents[i] = 2;
}
}
const std::string mId;
std::string mName;
// just to check if there's some sophisticated addressing involved...
// which we don't support, and therefore should warn about.
std::string mVertexID;
// Vertex data addressed by vertex indices
std::vector<InputChannel> mPerVertexData;
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
std::vector<aiVector3D> mPositions;
std::vector<aiVector3D> mNormals;
std::vector<aiVector3D> mTangents;
std::vector<aiVector3D> mBitangents;
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
// Faces. Stored are only the number of vertices for each face.
// 1 == point, 2 == line, 3 == triangle, 4+ == poly
std::vector<size_t> mFaceSize;
// Position indices for all faces in the sequence given in mFaceSize -
// necessary for bone weight assignment
std::vector<size_t> mFacePosIndices;
// Sub-meshes in this mesh, each with a given material
std::vector<SubMesh> mSubMeshes;
};
/// Which type of primitives the ReadPrimitives() function is going to read
enum PrimitiveType {
Prim_Invalid,
Prim_Lines,
Prim_LineStrip,
Prim_Triangles,
Prim_TriStrips,
Prim_TriFans,
Prim_Polylist,
Prim_Polygon
};
/// A skeleton controller to deform a mesh with the use of joints
struct Controller {
// controller type
ControllerType mType;
// Morphing method if type is Morph
MorphMethod mMethod;
// the URL of the mesh deformed by the controller.
std::string mMeshId;
// accessor URL of the joint names
std::string mJointNameSource;
///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases
ai_real mBindShapeMatrix[16];
// accessor URL of the joint inverse bind matrices
std::string mJointOffsetMatrixSource;
// input channel: joint names.
InputChannel mWeightInputJoints;
// input channel: joint weights
InputChannel mWeightInputWeights;
// Number of weights per vertex.
std::vector<size_t> mWeightCounts;
// JointIndex-WeightIndex pairs for all vertices
std::vector<std::pair<size_t, size_t>> mWeights;
std::string mMorphTarget;
std::string mMorphWeight;
};
/// A collada material. Pretty much the only member is a reference to an effect.
struct Material {
std::string mName;
std::string mEffect;
};
/// Type of the effect param
enum ParamType {
Param_Sampler,
Param_Surface
};
/// A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them
struct EffectParam {
ParamType mType;
std::string mReference; // to which other thing the param is referring to.
};
/// Shading type supported by the standard effect spec of Collada
enum ShadeType {
Shade_Invalid,
Shade_Constant,
Shade_Lambert,
Shade_Phong,
Shade_Blinn
};
/// Represents a texture sampler in collada
struct Sampler {
Sampler() :
mWrapU(true),
mWrapV(true),
mMirrorU(),
mMirrorV(),
mOp(aiTextureOp_Multiply),
mUVId(UINT_MAX),
mWeighting(1.f),
mMixWithPrevious(1.f) {}
/// Name of image reference
std::string mName;
/// Wrap U?
bool mWrapU;
/// Wrap V?
bool mWrapV;
/// Mirror U?
bool mMirrorU;
/// Mirror V?
bool mMirrorV;
/// Blend mode
aiTextureOp mOp;
/// UV transformation
aiUVTransform mTransform;
/// Name of source UV channel
std::string mUVChannel;
/// Resolved UV channel index or UINT_MAX if not known
unsigned int mUVId;
// OKINO/MAX3D extensions from here
// -------------------------------------------------------
/// Weighting factor
ai_real mWeighting;
/// Mixing factor from OKINO
ai_real mMixWithPrevious;
};
/// A collada effect. Can contain about anything according to the Collada spec,
/// but we limit our version to a reasonable subset.
struct Effect {
/// Shading mode
ShadeType mShadeType;
/// Colors
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
mTransparent, mReflective;
/// Textures
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
mTexTransparent, mTexBump, mTexReflective;
/// Scalar factory
ai_real mShininess, mRefractIndex, mReflectivity;
ai_real mTransparency;
bool mHasTransparency;
bool mRGBTransparency;
bool mInvertTransparency;
/// local params referring to each other by their SID
using ParamLibrary = std::map<std::string, Collada::EffectParam>;
ParamLibrary mParams;
// MAX3D extensions
// ---------------------------------------------------------
// Double-sided?
bool mDoubleSided, mWireframe, mFaceted;
Effect() :
mShadeType(Shade_Phong),
mEmissive(0, 0, 0, 1),
mAmbient(0.1f, 0.1f, 0.1f, 1),
mDiffuse(0.6f, 0.6f, 0.6f, 1),
mSpecular(0.4f, 0.4f, 0.4f, 1),
mTransparent(0, 0, 0, 1),
mShininess(10.0f),
mRefractIndex(1.f),
mReflectivity(0.f),
mTransparency(1.f),
mHasTransparency(false),
mRGBTransparency(false),
mInvertTransparency(false),
mDoubleSided(false),
mWireframe(false),
mFaceted(false) {
}
};
/// An image, meaning texture
struct Image {
std::string mFileName;
/// Embedded image data
std::vector<uint8_t> mImageData;
/// File format hint of embedded image data
std::string mEmbeddedFormat;
};
/// An animation channel.
struct AnimationChannel {
/// URL of the data to animate. Could be about anything, but we support only the
/// "NodeID/TransformID.SubElement" notation
std::string mTarget;
/// Source URL of the time values. Collada calls them "input". Meh.
std::string mSourceTimes;
/// Source URL of the value values. Collada calls them "output".
std::string mSourceValues;
/// Source URL of the IN_TANGENT semantic values.
std::string mInTanValues;
/// Source URL of the OUT_TANGENT semantic values.
std::string mOutTanValues;
/// Source URL of the INTERPOLATION semantic values.
std::string mInterpolationValues;
};
/// An animation. Container for 0-x animation channels or 0-x animations
struct Animation {
/// Anim name
std::string mName;
/// the animation channels, if any
std::vector<AnimationChannel> mChannels;
/// the sub-animations, if any
std::vector<Animation *> mSubAnims;
/// Destructor
~Animation() {
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
delete *it;
}
}
/// Collect all channels in the animation hierarchy into a single channel list.
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
Animation *pAnim = (*it);
pAnim->CollectChannelsRecursively(channels);
}
}
/// Combine all single-channel animations' channel into the same (parent) animation channel list.
void CombineSingleChannelAnimations() {
CombineSingleChannelAnimationsRecursively(this);
}
void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
std::set<std::string> childrenTargets;
bool childrenAnimationsHaveDifferentChannels = true;
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
Animation *anim = *it;
CombineSingleChannelAnimationsRecursively(anim);
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
childrenTargets.insert(anim->mChannels[0].mTarget);
} else {
childrenAnimationsHaveDifferentChannels = false;
}
++it;
}
// We only want to combine animations if they have different channels
if (childrenAnimationsHaveDifferentChannels) {
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
Animation *anim = *it;
pParent->mChannels.push_back(anim->mChannels[0]);
it = pParent->mSubAnims.erase(it);
delete anim;
continue;
}
}
}
};
/// Description of a collada animation channel which has been determined to affect the current node
struct ChannelEntry {
const Collada::AnimationChannel *mChannel; ///< the source channel
std::string mTargetId;
std::string mTransformId; // the ID of the transformation step of the node which is influenced
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
size_t mSubElement; // starting index inside the transform data
// resolved data references
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data *mTimeData; ///> Source data array for the time values
const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data *mValueData; ///> Source datat array for the key value values
ChannelEntry() :
mChannel(),
mTransformIndex(),
mSubElement(),
mTimeAccessor(),
mTimeData(),
mValueAccessor(),
mValueData() {}
};
} // end of namespace Collada
} // end of namespace Assimp
#endif // AI_COLLADAHELPER_H_INC

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