Merge branch 'master' into pugi_xml
commit
2be731d1bf
|
@ -70,8 +70,8 @@ IncludeCategories:
|
||||||
- Regex: '^<.*'
|
- Regex: '^<.*'
|
||||||
Priority: 3
|
Priority: 3
|
||||||
# IncludeIsMainRegex: '(Test)?$'
|
# IncludeIsMainRegex: '(Test)?$'
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: false
|
||||||
# IndentPPDirectives: None
|
#IndentPPDirectives: AfterHash
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
# IndentWrappedFunctionNames: false
|
# IndentWrappedFunctionNames: false
|
||||||
# JavaScriptQuotes: Leave
|
# JavaScriptQuotes: Leave
|
||||||
|
@ -108,7 +108,7 @@ IndentWidth: 4
|
||||||
# SpacesInParentheses: false
|
# SpacesInParentheses: false
|
||||||
# SpacesInSquareBrackets: false
|
# SpacesInSquareBrackets: false
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
UseTab: Always
|
UseTab: Never
|
||||||
---
|
---
|
||||||
### C++ specific config ###
|
### C++ specific config ###
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
patreon: assimp
|
patreon: assimp
|
||||||
ko_fi: kimkulling
|
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
|
||||||
|
open_collective: assimp
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
name: C/C++ CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
job:
|
||||||
|
name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang]
|
||||||
|
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
|
||||||
|
include:
|
||||||
|
- name: windows-msvc
|
||||||
|
os: windows-latest
|
||||||
|
cxx: cl.exe
|
||||||
|
cc: cl.exe
|
||||||
|
- name: ubuntu-clang
|
||||||
|
os: ubuntu-latest
|
||||||
|
cxx: clang++
|
||||||
|
cc: clang
|
||||||
|
- name: macos-clang
|
||||||
|
os: macos-latest
|
||||||
|
cxx: clang++
|
||||||
|
cc: clang
|
||||||
|
- name: ubuntu-gcc
|
||||||
|
os: ubuntu-latest
|
||||||
|
cxx: g++
|
||||||
|
cc: gcc
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
|
||||||
|
- uses: lukka/set-shell-env@v1
|
||||||
|
with:
|
||||||
|
CXX: ${{ matrix.cxx }}
|
||||||
|
CC: ${{ matrix.cc }}
|
||||||
|
|
||||||
|
- name: configure and build
|
||||||
|
uses: lukka/run-cmake@v2
|
||||||
|
with:
|
||||||
|
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||||
|
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||||
|
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release'
|
||||||
|
buildWithCMakeArgs: '-- -v'
|
||||||
|
buildDirectory: '${{ github.workspace }}/build/'
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
run: cd build/bin && ./unit
|
||||||
|
shell: bash
|
|
@ -0,0 +1,56 @@
|
||||||
|
name: C/C++ Sanitizer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
job1:
|
||||||
|
name: adress-sanitizer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: lukka/get-cmake@latest
|
||||||
|
- uses: lukka/set-shell-env@v1
|
||||||
|
with:
|
||||||
|
CXX: clang++
|
||||||
|
CC: clang
|
||||||
|
|
||||||
|
- name: configure and build
|
||||||
|
uses: lukka/run-cmake@v2
|
||||||
|
with:
|
||||||
|
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||||
|
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||||
|
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_ASAN=ON'
|
||||||
|
buildWithCMakeArgs: '-- -v'
|
||||||
|
buildDirectory: '${{ github.workspace }}/build/'
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
run: cd build/bin && ./unit
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
job2:
|
||||||
|
name: undefined-behavior-sanitizer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: lukka/get-cmake@latest
|
||||||
|
- uses: lukka/set-shell-env@v1
|
||||||
|
with:
|
||||||
|
CXX: clang++
|
||||||
|
CC: clang
|
||||||
|
|
||||||
|
- name: configure and build
|
||||||
|
uses: lukka/run-cmake@v2
|
||||||
|
with:
|
||||||
|
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||||
|
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||||
|
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_UBSAN=ON'
|
||||||
|
buildWithCMakeArgs: '-- -v'
|
||||||
|
buildDirectory: '${{ github.workspace }}/build/'
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
run: cd build/bin && ./unit
|
||||||
|
shell: bash
|
|
@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/
|
||||||
tools/assimp_view/assimp_viewer.vcxproj.user
|
tools/assimp_view/assimp_viewer.vcxproj.user
|
||||||
*.pyc
|
*.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
|
# Unix editor backups
|
||||||
*~
|
*~
|
||||||
test/gtest/src/gtest-stamp/gtest-gitinfo.txt
|
test/gtest/src/gtest-stamp/gtest-gitinfo.txt
|
||||||
|
|
317
CMakeLists.txt
317
CMakeLists.txt
|
@ -39,17 +39,17 @@ SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
|
||||||
CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
|
CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
|
||||||
|
|
||||||
# Toggles the use of the hunter package manager
|
# Toggles the use of the hunter package manager
|
||||||
option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
||||||
|
|
||||||
include("cmake/HunterGate.cmake")
|
IF(ASSIMP_HUNTER_ENABLED)
|
||||||
HunterGate(
|
include("cmake/HunterGate.cmake")
|
||||||
|
HunterGate(
|
||||||
URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
|
URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
|
||||||
SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
|
SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(HUNTER_ENABLED)
|
|
||||||
add_definitions(-DASSIMP_USE_HUNTER)
|
add_definitions(-DASSIMP_USE_HUNTER)
|
||||||
ENDIF(HUNTER_ENABLED)
|
ENDIF()
|
||||||
|
|
||||||
PROJECT( Assimp VERSION 5.0.1 )
|
PROJECT( Assimp VERSION 5.0.1 )
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ OPTION( BUILD_SHARED_LIBS
|
||||||
ON
|
ON
|
||||||
)
|
)
|
||||||
|
|
||||||
OPTION( BUILD_FRAMEWORK
|
OPTION( ASSIMP_BUILD_FRAMEWORK
|
||||||
"Build package as Mac OS X Framework bundle."
|
"Build package as Mac OS X Framework bundle."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
|
@ -100,14 +100,14 @@ OPTION ( ASSIMP_COVERALLS
|
||||||
"Enable this to measure test coverage."
|
"Enable this to measure test coverage."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
|
OPTION( ASSIMP_INSTALL
|
||||||
|
"Disable this if you want to use assimp as a submodule."
|
||||||
|
ON
|
||||||
|
)
|
||||||
OPTION ( ASSIMP_ERROR_MAX
|
OPTION ( ASSIMP_ERROR_MAX
|
||||||
"Enable all warnings."
|
"Enable all warnings."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
OPTION ( ASSIMP_WERROR
|
|
||||||
"Treat warnings as errors."
|
|
||||||
OFF
|
|
||||||
)
|
|
||||||
OPTION ( ASSIMP_ASAN
|
OPTION ( ASSIMP_ASAN
|
||||||
"Enable AddressSanitizer."
|
"Enable AddressSanitizer."
|
||||||
OFF
|
OFF
|
||||||
|
@ -116,30 +116,36 @@ OPTION ( ASSIMP_UBSAN
|
||||||
"Enable Undefined Behavior sanitizer."
|
"Enable Undefined Behavior sanitizer."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
OPTION ( SYSTEM_IRRXML
|
OPTION ( ASSIMP_SYSTEM_IRRXML
|
||||||
"Use system installed Irrlicht/IrrXML library."
|
"Use system installed Irrlicht/IrrXML library."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
OPTION ( BUILD_DOCS
|
OPTION ( ASSIMP_BUILD_DOCS
|
||||||
"Build documentation using Doxygen."
|
"Build documentation using Doxygen."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
OPTION( INJECT_DEBUG_POSTFIX
|
OPTION( ASSIMP_INJECT_DEBUG_POSTFIX
|
||||||
"Inject debug postfix in .a/.so/.dll lib names"
|
"Inject debug postfix in .a/.so/.dll lib names"
|
||||||
ON
|
ON
|
||||||
)
|
)
|
||||||
|
|
||||||
OPTION ( IGNORE_GIT_HASH
|
OPTION ( ASSIMP_IGNORE_GIT_HASH
|
||||||
"Don't call git to get the hash."
|
"Don't call git to get the hash."
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
IF (IOS AND NOT HUNTER_ENABLED)
|
IF ( WIN32 )
|
||||||
|
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
|
||||||
|
"If the Assimp view tool is built. (requires DirectX)"
|
||||||
|
OFF )
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
|
||||||
IF (NOT CMAKE_BUILD_TYPE)
|
IF (NOT CMAKE_BUILD_TYPE)
|
||||||
SET(CMAKE_BUILD_TYPE "Release")
|
SET(CMAKE_BUILD_TYPE "Release")
|
||||||
ENDIF (NOT CMAKE_BUILD_TYPE)
|
ENDIF ()
|
||||||
ADD_DEFINITIONS(-DENABLE_BITCODE)
|
ADD_DEFINITIONS(-DENABLE_BITCODE)
|
||||||
ENDIF (IOS AND NOT HUNTER_ENABLED)
|
ENDIF ()
|
||||||
|
|
||||||
# Use subset of Windows.h
|
# Use subset of Windows.h
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
@ -155,19 +161,19 @@ IF(MSVC)
|
||||||
# Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
|
# Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
|
||||||
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
|
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF(MSVC)
|
ENDIF()
|
||||||
|
|
||||||
IF (BUILD_FRAMEWORK)
|
IF (ASSIMP_BUILD_FRAMEWORK)
|
||||||
SET (BUILD_SHARED_LIBS ON)
|
SET (BUILD_SHARED_LIBS ON)
|
||||||
MESSAGE(STATUS "Framework bundle building enabled")
|
MESSAGE(STATUS "Framework bundle building enabled")
|
||||||
ENDIF(BUILD_FRAMEWORK)
|
ENDIF()
|
||||||
|
|
||||||
IF(NOT BUILD_SHARED_LIBS)
|
IF(NOT BUILD_SHARED_LIBS)
|
||||||
MESSAGE(STATUS "Shared libraries disabled")
|
MESSAGE(STATUS "Shared libraries disabled")
|
||||||
SET(LINK_SEARCH_START_STATIC TRUE)
|
SET(LINK_SEARCH_START_STATIC TRUE)
|
||||||
ELSE()
|
ELSE()
|
||||||
MESSAGE(STATUS "Shared libraries enabled")
|
MESSAGE(STATUS "Shared libraries enabled")
|
||||||
ENDIF(NOT BUILD_SHARED_LIBS)
|
ENDIF()
|
||||||
|
|
||||||
# Define here the needed parameters
|
# Define here the needed parameters
|
||||||
SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||||
|
@ -177,12 +183,12 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER
|
||||||
SET (ASSIMP_SOVERSION 5)
|
SET (ASSIMP_SOVERSION 5)
|
||||||
|
|
||||||
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
||||||
if(NOT HUNTER_ENABLED)
|
if(NOT ASSIMP_HUNTER_ENABLED)
|
||||||
# Enable C++11 support globally
|
# Enable C++11 support globally
|
||||||
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(NOT IGNORE_GIT_HASH)
|
IF(NOT ASSIMP_IGNORE_GIT_HASH)
|
||||||
# Get the current working branch
|
# Get the current working branch
|
||||||
EXECUTE_PROCESS(
|
EXECUTE_PROCESS(
|
||||||
COMMAND git rev-parse --abbrev-ref HEAD
|
COMMAND git rev-parse --abbrev-ref HEAD
|
||||||
|
@ -204,11 +210,11 @@ ENDIF()
|
||||||
|
|
||||||
IF(NOT GIT_COMMIT_HASH)
|
IF(NOT GIT_COMMIT_HASH)
|
||||||
SET(GIT_COMMIT_HASH 0)
|
SET(GIT_COMMIT_HASH 0)
|
||||||
ENDIF(NOT GIT_COMMIT_HASH)
|
ENDIF()
|
||||||
|
|
||||||
IF(ASSIMP_DOUBLE_PRECISION)
|
IF(ASSIMP_DOUBLE_PRECISION)
|
||||||
ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
|
ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
|
||||||
ENDIF(ASSIMP_DOUBLE_PRECISION)
|
ENDIF()
|
||||||
|
|
||||||
CONFIGURE_FILE(
|
CONFIGURE_FILE(
|
||||||
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
|
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
|
||||||
|
@ -238,33 +244,32 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
|
||||||
IF( UNIX )
|
IF( UNIX )
|
||||||
# Use GNUInstallDirs for Unix predefined directories
|
# Use GNUInstallDirs for Unix predefined directories
|
||||||
INCLUDE(GNUInstallDirs)
|
INCLUDE(GNUInstallDirs)
|
||||||
ENDIF( UNIX )
|
ENDIF()
|
||||||
|
|
||||||
# Grouped compiler settings
|
# Grouped compiler settings ########################################
|
||||||
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
|
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
|
||||||
IF(NOT HUNTER_ENABLED)
|
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
# hide all not-exported symbols
|
# hide all not-exported symbols
|
||||||
SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||||
ELSEIF(MSVC)
|
ELSEIF(MSVC)
|
||||||
# enable multi-core compilation with MSVC
|
# enable multi-core compilation with MSVC
|
||||||
ADD_COMPILE_OPTIONS(/MP)
|
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX )
|
||||||
ADD_COMPILE_OPTIONS( /bigobj )
|
|
||||||
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
||||||
IF(MSVC12)
|
IF(MSVC12)
|
||||||
ADD_COMPILE_OPTIONS(/wd4351)
|
ADD_COMPILE_OPTIONS(/wd4351)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
|
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 HUNTER_ENABLED)
|
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
ENDIF()
|
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}")
|
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||||
ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
||||||
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
|
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
|
||||||
|
@ -272,7 +277,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
||||||
ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
|
ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
|
||||||
message(WARNING "MinGW is old, if you experience errors, update MinGW.")
|
message(WARNING "MinGW is old, if you experience errors, update MinGW.")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
IF(NOT HUNTER_ENABLED)
|
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||||
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
@ -281,7 +286,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
||||||
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF ( IOS AND NOT HUNTER_ENABLED)
|
IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
|
||||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
|
||||||
|
@ -290,7 +295,7 @@ IF ( IOS AND NOT HUNTER_ENABLED)
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
|
||||||
# Experimental for pdb generation
|
# Experimental for pdb generation
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF( IOS AND NOT HUNTER_ENABLED)
|
ENDIF()
|
||||||
|
|
||||||
IF (ASSIMP_COVERALLS)
|
IF (ASSIMP_COVERALLS)
|
||||||
MESSAGE(STATUS "Coveralls enabled")
|
MESSAGE(STATUS "Coveralls enabled")
|
||||||
|
@ -309,16 +314,6 @@ IF (ASSIMP_ERROR_MAX)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
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)
|
IF (ASSIMP_ASAN)
|
||||||
MESSAGE(STATUS "AddressSanitizer enabled")
|
MESSAGE(STATUS "AddressSanitizer enabled")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||||
|
@ -339,22 +334,18 @@ INCLUDE (PrecompiledHeader)
|
||||||
# source tree. During an out-of-source build, however, do not litter this
|
# source tree. During an out-of-source build, however, do not litter this
|
||||||
# directory, since that is probably what the user wanted to avoid.
|
# directory, since that is probably what the user wanted to avoid.
|
||||||
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
||||||
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
|
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
|
||||||
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
|
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
|
||||||
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
|
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
|
||||||
ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
ELSE()
|
||||||
|
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||||
# Cache these to allow the user to override them manually.
|
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||||
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
|
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||||
"Path the built library files are installed to." )
|
ENDIF ()
|
||||||
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." )
|
|
||||||
|
|
||||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
IF (ASSIMP_INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||||
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
|
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||||
ELSE()
|
ELSE()
|
||||||
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
|
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||||
|
@ -367,7 +358,7 @@ IF (NOT TARGET uninstall)
|
||||||
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(HUNTER_ENABLED)
|
IF(ASSIMP_HUNTER_ENABLED)
|
||||||
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||||
set(INCLUDE_INSTALL_DIR "include")
|
set(INCLUDE_INSTALL_DIR "include")
|
||||||
|
|
||||||
|
@ -404,13 +395,35 @@ IF(HUNTER_ENABLED)
|
||||||
NAMESPACE "${NAMESPACE}"
|
NAMESPACE "${NAMESPACE}"
|
||||||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||||
)
|
)
|
||||||
ELSE(HUNTER_ENABLED)
|
ELSE()
|
||||||
# cmake configuration files
|
# cmake configuration files
|
||||||
if(${BUILD_SHARED_LIBS})
|
if(${BUILD_SHARED_LIBS})
|
||||||
set(BUILD_LIB_TYPE SHARED)
|
set(BUILD_LIB_TYPE SHARED)
|
||||||
else()
|
else()
|
||||||
set(BUILD_LIB_TYPE STATIC)
|
set(BUILD_LIB_TYPE STATIC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
IF( UNIX )
|
||||||
|
# Use GNUInstallDirs for Unix predefined directories
|
||||||
|
INCLUDE(GNUInstallDirs)
|
||||||
|
|
||||||
|
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
|
||||||
|
ELSE()
|
||||||
|
# Cache these to allow the user to override them on non-Unix platforms
|
||||||
|
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
|
||||||
|
"Path the built library files are installed to." )
|
||||||
|
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
|
||||||
|
"Path the header files are installed to." )
|
||||||
|
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
|
||||||
|
"Path the tool executables are installed to." )
|
||||||
|
|
||||||
|
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
|
||||||
|
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
|
||||||
|
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
||||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
|
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
|
||||||
IF (is_multi_config)
|
IF (is_multi_config)
|
||||||
|
@ -432,22 +445,20 @@ ELSE(HUNTER_ENABLED)
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
|
||||||
${PACKAGE_TARGETS_FILE}
|
${PACKAGE_TARGETS_FILE}
|
||||||
DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||||
ENDIF(HUNTER_ENABLED)
|
ENDIF()
|
||||||
|
|
||||||
FIND_PACKAGE( DirectX )
|
IF( ASSIMP_BUILD_DOCS )
|
||||||
|
|
||||||
IF( BUILD_DOCS )
|
|
||||||
ADD_SUBDIRECTORY(doc)
|
ADD_SUBDIRECTORY(doc)
|
||||||
ENDIF( BUILD_DOCS )
|
ENDIF()
|
||||||
|
|
||||||
# Look for system installed irrXML
|
# Look for system installed irrXML
|
||||||
IF ( SYSTEM_IRRXML )
|
IF ( ASSIMP_SYSTEM_IRRXML )
|
||||||
FIND_PACKAGE( IrrXML REQUIRED )
|
FIND_PACKAGE( IrrXML REQUIRED )
|
||||||
ENDIF( SYSTEM_IRRXML )
|
ENDIF()
|
||||||
|
|
||||||
# Search for external dependencies, and build them from source if not found
|
# Search for external dependencies, and build them from source if not found
|
||||||
# Search for zlib
|
# Search for zlib
|
||||||
IF(HUNTER_ENABLED)
|
IF(ASSIMP_HUNTER_ENABLED)
|
||||||
hunter_add_package(ZLIB)
|
hunter_add_package(ZLIB)
|
||||||
find_package(ZLIB CONFIG REQUIRED)
|
find_package(ZLIB CONFIG REQUIRED)
|
||||||
|
|
||||||
|
@ -455,10 +466,10 @@ IF(HUNTER_ENABLED)
|
||||||
set(ZLIB_FOUND TRUE)
|
set(ZLIB_FOUND TRUE)
|
||||||
set(ZLIB_LIBRARIES ZLIB::zlib)
|
set(ZLIB_LIBRARIES ZLIB::zlib)
|
||||||
set(ASSIMP_BUILD_MINIZIP TRUE)
|
set(ASSIMP_BUILD_MINIZIP TRUE)
|
||||||
ELSE(HUNTER_ENABLED)
|
ELSE()
|
||||||
IF ( NOT ASSIMP_BUILD_ZLIB )
|
IF ( NOT ASSIMP_BUILD_ZLIB )
|
||||||
FIND_PACKAGE(ZLIB)
|
FIND_PACKAGE(ZLIB)
|
||||||
ENDIF( NOT ASSIMP_BUILD_ZLIB )
|
ENDIF()
|
||||||
|
|
||||||
IF( NOT ZLIB_FOUND )
|
IF( NOT ZLIB_FOUND )
|
||||||
MESSAGE(STATUS "compiling zlib from sources")
|
MESSAGE(STATUS "compiling zlib from sources")
|
||||||
|
@ -481,46 +492,46 @@ ELSE(HUNTER_ENABLED)
|
||||||
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
|
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
|
||||||
# need to ensure we don't link with system zlib or minizip as well.
|
# need to ensure we don't link with system zlib or minizip as well.
|
||||||
SET(ASSIMP_BUILD_MINIZIP 1)
|
SET(ASSIMP_BUILD_MINIZIP 1)
|
||||||
ELSE(NOT ZLIB_FOUND)
|
ELSE()
|
||||||
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
|
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
|
||||||
SET(ZLIB_LIBRARIES_LINKED -lz)
|
SET(ZLIB_LIBRARIES_LINKED -lz)
|
||||||
ENDIF(NOT ZLIB_FOUND)
|
ENDIF()
|
||||||
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
|
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
|
||||||
ENDIF(HUNTER_ENABLED)
|
ENDIF()
|
||||||
|
|
||||||
IF( NOT IOS )
|
IF( NOT IOS )
|
||||||
IF( NOT ASSIMP_BUILD_MINIZIP )
|
IF( NOT ASSIMP_BUILD_MINIZIP )
|
||||||
use_pkgconfig(UNZIP minizip)
|
use_pkgconfig(UNZIP minizip)
|
||||||
ENDIF( NOT ASSIMP_BUILD_MINIZIP )
|
ENDIF()
|
||||||
ELSE ( NOT IOS )
|
ELSE ()
|
||||||
IF( NOT BUILD_SHARED_LIBS )
|
IF( NOT BUILD_SHARED_LIBS )
|
||||||
IF( NOT ASSIMP_BUILD_MINIZIP )
|
IF( NOT ASSIMP_BUILD_MINIZIP )
|
||||||
use_pkgconfig(UNZIP minizip)
|
use_pkgconfig(UNZIP minizip)
|
||||||
ENDIF( NOT ASSIMP_BUILD_MINIZIP )
|
ENDIF()
|
||||||
ENDIF ( NOT BUILD_SHARED_LIBS )
|
ENDIF ()
|
||||||
ENDIF ( NOT IOS )
|
ENDIF ()
|
||||||
|
|
||||||
IF ( ASSIMP_NO_EXPORT )
|
IF ( ASSIMP_NO_EXPORT )
|
||||||
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
|
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
|
||||||
MESSAGE( STATUS "Build an import-only version of Assimp." )
|
MESSAGE( STATUS "Build an import-only version of Assimp." )
|
||||||
ENDIF( ASSIMP_NO_EXPORT )
|
ENDIF()
|
||||||
|
|
||||||
SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
|
SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
|
||||||
"describe the current architecture."
|
"describe the current architecture."
|
||||||
)
|
)
|
||||||
IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
||||||
ELSE ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
ELSE()
|
||||||
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
|
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
|
||||||
ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
ENDIF()
|
||||||
|
|
||||||
# ${CMAKE_GENERATOR}
|
# ${CMAKE_GENERATOR}
|
||||||
SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
|
SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
|
||||||
"describe the current compiler."
|
"describe the current compiler."
|
||||||
)
|
)
|
||||||
IF ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
IF( ASSIMP_BUILD_COMPILER STREQUAL "")
|
||||||
ELSE ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
ELSE()
|
||||||
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
|
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
|
||||||
ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
ENDIF()
|
||||||
|
|
||||||
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
|
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
|
||||||
|
|
||||||
|
@ -566,91 +577,97 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
||||||
MESSAGE( FATAL_ERROR
|
MESSAGE( FATAL_ERROR
|
||||||
"C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
|
"C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
|
||||||
)
|
)
|
||||||
ENDIF ( MSVC )
|
ENDIF ()
|
||||||
ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
ELSE ()
|
||||||
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
|
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
|
||||||
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
ENDIF ()
|
||||||
|
|
||||||
IF(NOT HUNTER_ENABLED)
|
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||||
ADD_SUBDIRECTORY(contrib)
|
ADD_SUBDIRECTORY(contrib)
|
||||||
ENDIF(NOT HUNTER_ENABLED)
|
ENDIF()
|
||||||
|
|
||||||
ADD_SUBDIRECTORY( code/ )
|
ADD_SUBDIRECTORY( code/ )
|
||||||
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||||
# The viewer for windows only
|
# The viewer for windows only
|
||||||
IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
IF ( WIN32 )
|
||||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
|
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
|
||||||
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||||
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
||||||
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
ENDIF ()
|
||||||
ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
ENDIF ()
|
||||||
# Te command line tool
|
# The command line tool
|
||||||
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
|
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
|
||||||
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
ENDIF ()
|
||||||
|
|
||||||
IF ( ASSIMP_BUILD_SAMPLES)
|
IF ( ASSIMP_BUILD_SAMPLES)
|
||||||
|
SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples )
|
||||||
|
SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode )
|
||||||
IF ( WIN32 )
|
IF ( WIN32 )
|
||||||
ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
|
ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
|
||||||
ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 )
|
ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 )
|
||||||
ENDIF ( WIN32 )
|
ENDIF ()
|
||||||
ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
|
ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
|
||||||
ENDIF ( ASSIMP_BUILD_SAMPLES )
|
ENDIF ()
|
||||||
|
|
||||||
IF ( ASSIMP_BUILD_TESTS )
|
IF ( ASSIMP_BUILD_TESTS )
|
||||||
ADD_SUBDIRECTORY( test/ )
|
ADD_SUBDIRECTORY( test/ )
|
||||||
ENDIF ( ASSIMP_BUILD_TESTS )
|
ENDIF ()
|
||||||
|
|
||||||
# Generate a pkg-config .pc for the Assimp library.
|
# Generate a pkg-config .pc for the Assimp library.
|
||||||
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
|
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
|
||||||
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
IF ( ASSIMP_INSTALL )
|
||||||
|
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
IF ( ASSIMP_INSTALL )
|
||||||
# Packing information
|
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
||||||
SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
|
# Packing information
|
||||||
SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
|
SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
|
||||||
SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp")
|
SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
|
||||||
SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}")
|
SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp")
|
||||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}")
|
SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}")
|
||||||
SET(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" )
|
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}")
|
||||||
SET(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}")
|
SET(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" )
|
||||||
SET(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}")
|
SET(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}")
|
||||||
SET(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}")
|
SET(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}")
|
||||||
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
|
SET(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}")
|
||||||
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
|
||||||
|
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||||
|
|
||||||
STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
|
STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
|
||||||
STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
|
STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
|
||||||
|
|
||||||
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
|
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
|
||||||
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
|
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
|
||||||
SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries")
|
SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries")
|
||||||
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs")
|
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs")
|
||||||
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" )
|
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" )
|
||||||
SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" )
|
SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" )
|
||||||
SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" )
|
SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" )
|
||||||
SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config)
|
SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config)
|
||||||
|
|
||||||
# debian
|
# debian
|
||||||
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||||
SET(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}")
|
SET(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
|
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
|
||||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
|
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
|
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
|
||||||
set(cPACK_DEBIAN_PACKAGE_NAME "assimp")
|
SET(cPACK_DEBIAN_PACKAGE_NAME "assimp")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
|
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
|
||||||
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
|
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
|
||||||
SET(CPACK_DEBIAN_CHANGELOG)
|
SET(CPACK_DEBIAN_CHANGELOG)
|
||||||
execute_process(COMMAND lsb_release -is
|
execute_process(COMMAND lsb_release -is
|
||||||
OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
RESULT_VARIABLE _lsb_release_failed)
|
RESULT_VARIABLE _lsb_release_failed)
|
||||||
SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton")
|
SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton")
|
||||||
STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME)
|
STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME)
|
||||||
IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" )
|
IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" )
|
||||||
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
|
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
|
||||||
|
ENDIF()
|
||||||
|
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
|
||||||
|
INCLUDE(CPack)
|
||||||
|
INCLUDE(DebSourcePPA)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
|
|
||||||
INCLUDE(CPack)
|
|
||||||
INCLUDE(DebSourcePPA)
|
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -671,7 +688,7 @@ if(WIN32)
|
||||||
SET(ASSIMP_MSVC_VERSION "vc140")
|
SET(ASSIMP_MSVC_VERSION "vc140")
|
||||||
ELSEIF(MSVC15)
|
ELSEIF(MSVC15)
|
||||||
SET(ASSIMP_MSVC_VERSION "vc141")
|
SET(ASSIMP_MSVC_VERSION "vc141")
|
||||||
ENDIF(MSVC12)
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(MSVC12 OR MSVC14 OR MSVC15 )
|
IF(MSVC12 OR MSVC14 OR MSVC15 )
|
||||||
|
@ -696,5 +713,5 @@ if(WIN32)
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF(MSVC12 OR MSVC14 OR MSVC15 )
|
ENDIF()
|
||||||
ENDIF (WIN32)
|
ENDIF ()
|
||||||
|
|
100
INSTALL
100
INSTALL
|
@ -1,50 +1,50 @@
|
||||||
|
|
||||||
========================================================================
|
========================================================================
|
||||||
Open Asset Import Library (assimp) INSTALL
|
Open Asset Import Library (assimp) INSTALL
|
||||||
========================================================================
|
========================================================================
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
Getting the documentation
|
Getting the documentation
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
A regularly-updated copy is available at
|
A regularly-updated copy is available at
|
||||||
http://assimp.sourceforge.net/lib_html/index.html
|
http://assimp.sourceforge.net/lib_html/index.html
|
||||||
|
|
||||||
A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
|
A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
|
||||||
To build the doxygen documentation on your own, follow these steps:
|
To build the doxygen documentation on your own, follow these steps:
|
||||||
|
|
||||||
a) download & install latest doxygen
|
a) download & install latest doxygen
|
||||||
b) make sure doxygen is in the executable search path
|
b) make sure doxygen is in the executable search path
|
||||||
c) navigate to ./doc
|
c) navigate to ./doc
|
||||||
d) and run 'doxygen'
|
d) and run 'doxygen'
|
||||||
|
|
||||||
Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
|
Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
|
||||||
Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
|
Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
|
||||||
and configure the path to it in the DOXYFILE first.
|
and configure the path to it in the DOXYFILE first.
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
Building Assimp
|
Building Assimp
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
More detailed build instructions can be found in the documentation,
|
More detailed build instructions can be found in the documentation,
|
||||||
this section is just for the inpatient among you.
|
this section is just for the inpatient among you.
|
||||||
|
|
||||||
CMake is the preferred build system for Assimp. The minimum required version
|
CMake is the preferred build system for Assimp. The minimum required version
|
||||||
is 2.6. If you don't have it yet, downloads for CMake can be found on
|
is 2.6. If you don't have it yet, downloads for CMake can be found on
|
||||||
http://www.cmake.org/.
|
http://www.cmake.org/.
|
||||||
|
|
||||||
For Unix:
|
For Unix:
|
||||||
|
|
||||||
1. mkdir build && cd build
|
1. mkdir build && cd build
|
||||||
2. cmake .. -G 'Unix Makefiles'
|
2. cmake .. -G 'Unix Makefiles'
|
||||||
3. make -j4
|
3. make -j4
|
||||||
|
|
||||||
For Windows:
|
For Windows:
|
||||||
1. Open a command prompt
|
1. Open a command prompt
|
||||||
2. mkdir build
|
2. mkdir build
|
||||||
3. cd build
|
3. cd build
|
||||||
4. cmake ..
|
4. cmake ..
|
||||||
5. cmake --build .
|
5. cmake --build .
|
||||||
|
|
||||||
For iOS:
|
For iOS:
|
||||||
Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS
|
Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS
|
||||||
|
|
24
Readme.md
24
Readme.md
|
@ -2,6 +2,8 @@ Open Asset Import Library (assimp)
|
||||||
==================================
|
==================================
|
||||||
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
||||||
### Current project status ###
|
### Current project status ###
|
||||||
|
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
|
||||||
|
![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)
|
[![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)
|
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
|
||||||
<a href="https://scan.coverity.com/projects/5607">
|
<a href="https://scan.coverity.com/projects/5607">
|
||||||
|
@ -178,6 +180,28 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a
|
||||||
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
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.
|
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>
|
||||||
|
|
||||||
|
#### 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 ###
|
### License ###
|
||||||
Our license is based on the modified, __3-clause BSD__-License.
|
Our license is based on the modified, __3-clause BSD__-License.
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ matrix:
|
||||||
|
|
||||||
image:
|
image:
|
||||||
- Visual Studio 2013
|
- Visual Studio 2013
|
||||||
- Visual Studio 2015
|
#- Visual Studio 2015
|
||||||
- Visual Studio 2017
|
#- Visual Studio 2017
|
||||||
- Visual Studio 2019
|
- Visual Studio 2019
|
||||||
- MinGW
|
#- MinGW
|
||||||
|
|
||||||
platform:
|
platform:
|
||||||
- Win32
|
- Win32
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
exec_prefix=@CMAKE_INSTALL_PREFIX@/
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
|
|
||||||
includedir=@CMAKE_INSTALL_PREFIX@/../include/@ASSIMP_INCLUDE_INSTALL_DIR@
|
|
||||||
|
|
||||||
Name: @CMAKE_PROJECT_NAME@
|
Name: @CMAKE_PROJECT_NAME@
|
||||||
Description: Import various well-known 3D model formats in an uniform manner.
|
Description: Import various well-known 3D model formats in an uniform manner.
|
||||||
|
|
|
@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||||
|
|
||||||
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
||||||
|
|
||||||
|
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
if(MSVC_TOOLSET_VERSION)
|
if(MSVC_TOOLSET_VERSION)
|
||||||
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
||||||
|
@ -35,8 +37,6 @@ if(MSVC)
|
||||||
endif()
|
endif()
|
||||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
|
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)
|
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||||
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
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@")
|
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
|
||||||
|
@ -44,22 +44,22 @@ if(MSVC)
|
||||||
# Import target "assimp::assimp" for configuration "Debug"
|
# Import target "assimp::assimp" for configuration "Debug"
|
||||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
|
IMPORTED_IMPLIB_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
|
||||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
|
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
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 "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
|
||||||
else()
|
else()
|
||||||
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||||
|
|
||||||
# Import target "assimp::assimp" for configuration "Debug"
|
# Import target "assimp::assimp" for configuration "Debug"
|
||||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
@ -73,25 +73,28 @@ else()
|
||||||
else()
|
else()
|
||||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Import target "assimp::assimp" for configuration "Debug"
|
||||||
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
|
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
|
||||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
|
||||||
else()
|
else()
|
||||||
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||||
|
|
||||||
|
# Import target "assimp::assimp" for configuration "Debug"
|
||||||
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Commands beyond this point should not need to know the version.
|
# Commands beyond this point should not need to know the version.
|
||||||
set(CMAKE_IMPORT_FILE_VERSION)
|
set(CMAKE_IMPORT_FILE_VERSION)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||||
|
|
||||||
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
||||||
|
|
||||||
|
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
if(MSVC_TOOLSET_VERSION)
|
if(MSVC_TOOLSET_VERSION)
|
||||||
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
||||||
|
@ -34,8 +36,6 @@ if(MSVC)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
|
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)
|
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||||
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||||
|
@ -44,22 +44,22 @@ if(MSVC)
|
||||||
# Import target "assimp::assimp" for configuration "Release"
|
# Import target "assimp::assimp" for configuration "Release"
|
||||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
|
IMPORTED_IMPLIB_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
|
||||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
|
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
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 "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
|
||||||
else()
|
else()
|
||||||
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||||
|
|
||||||
# Import target "assimp::assimp" for configuration "Release"
|
# Import target "assimp::assimp" for configuration "Release"
|
||||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
@ -73,20 +73,25 @@ else()
|
||||||
else()
|
else()
|
||||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Import target "assimp::assimp" for configuration "Release"
|
||||||
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
|
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
|
||||||
|
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
|
||||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
|
||||||
else()
|
else()
|
||||||
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||||
|
|
||||||
|
# Import target "assimp::assimp" for configuration "Release"
|
||||||
|
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||||
)
|
)
|
||||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
|
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -43,23 +43,13 @@ unset(_targetsDefined)
|
||||||
unset(_targetsNotDefined)
|
unset(_targetsNotDefined)
|
||||||
unset(_expectedTargets)
|
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
|
# Create imported target assimp::assimp
|
||||||
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
|
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
|
||||||
|
|
||||||
set_target_properties(assimp::assimp PROPERTIES
|
set_target_properties(assimp::assimp PROPERTIES
|
||||||
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
|
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
|
||||||
INTERFACE_assimp_MAJOR_VERSION "1"
|
INTERFACE_assimp_MAJOR_VERSION "1"
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include"
|
INTERFACE_INCLUDE_DIRECTORIES "@CMAKE_INSTALL_FULL_INCLUDEDIR@"
|
||||||
#INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
|
#INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,9 +64,6 @@ foreach(f ${CONFIG_FILES})
|
||||||
include(${f})
|
include(${f})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Cleanup temporary variables.
|
|
||||||
set(_IMPORT_PREFIX)
|
|
||||||
|
|
||||||
# Loop over all imported files and verify that they actually exist
|
# Loop over all imported files and verify that they actually exist
|
||||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||||
|
|
|
@ -1,701 +0,0 @@
|
||||||
/*
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
Open Asset Import Library (assimp)
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
|
||||||
with or without modification, are permitted provided that the following
|
|
||||||
conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer in the documentation and/or other
|
|
||||||
materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of the assimp team, nor the names of its
|
|
||||||
contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior
|
|
||||||
written permission of the assimp team.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// \file AMFImporter.cpp
|
|
||||||
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
|
|
||||||
/// \date 2016
|
|
||||||
/// \author smal.root@gmail.com
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
|
||||||
|
|
||||||
// Header files, Assimp.
|
|
||||||
#include "AMFImporter.hpp"
|
|
||||||
#include "AMFImporter_Macro.hpp"
|
|
||||||
|
|
||||||
#include <assimp/DefaultIOSystem.h>
|
|
||||||
#include <assimp/fast_atof.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace Assimp {
|
|
||||||
|
|
||||||
/// \var aiImporterDesc AMFImporter::Description
|
|
||||||
/// Constant which hold importer description
|
|
||||||
const aiImporterDesc AMFImporter::Description = {
|
|
||||||
"Additive manufacturing file format(AMF) Importer",
|
|
||||||
"smalcom",
|
|
||||||
"",
|
|
||||||
"See documentation in source code. Chapter: Limitations.",
|
|
||||||
aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
"amf"
|
|
||||||
};
|
|
||||||
|
|
||||||
void AMFImporter::Clear() {
|
|
||||||
mNodeElement_Cur = nullptr;
|
|
||||||
mUnit.clear();
|
|
||||||
mMaterial_Converted.clear();
|
|
||||||
mTexture_Converted.clear();
|
|
||||||
// Delete all elements
|
|
||||||
if (!mNodeElement_List.empty()) {
|
|
||||||
for (AMFNodeElementBase *ne : mNodeElement_List) {
|
|
||||||
delete ne;
|
|
||||||
}
|
|
||||||
|
|
||||||
mNodeElement_List.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AMFImporter::~AMFImporter() {
|
|
||||||
if (mXmlParser != nullptr) {
|
|
||||||
delete mXmlParser;
|
|
||||||
mXmlParser = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<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;
|
|
||||||
XmlNode *root = mXmlParser->parse(file.get());
|
|
||||||
if (nullptr == root) {
|
|
||||||
throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// start reading
|
|
||||||
// search for root tag <amf>
|
|
||||||
|
|
||||||
if (!root->find_child("amf")) {
|
|
||||||
throw DeadlyImportError("Root node \"amf\" not found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseNode_Root(*root);
|
|
||||||
|
|
||||||
delete mXmlParser;
|
|
||||||
mXmlParser = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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(XmlNode &root) {
|
|
||||||
std::string unit, version;
|
|
||||||
AMFNodeElementBase *ne(nullptr);
|
|
||||||
|
|
||||||
// Read attributes for node <amf>.
|
|
||||||
for (pugi::xml_attribute_iterator ait = root.attributes_begin(); ait != root.attributes_end(); ++ait) {
|
|
||||||
if (ait->name() == "unit") {
|
|
||||||
unit = ait->as_string();
|
|
||||||
} else if (ait->name() == "version") {
|
|
||||||
version = ait->as_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check attributes
|
|
||||||
if (!mUnit.empty()) {
|
|
||||||
if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) {
|
|
||||||
throw DeadlyImportError("Root node does not contain any units.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create root node element.
|
|
||||||
ne = new AMFRoot(nullptr);
|
|
||||||
|
|
||||||
// set first "current" element
|
|
||||||
mNodeElement_Cur = ne;
|
|
||||||
|
|
||||||
// and assign attributes values
|
|
||||||
((AMFRoot *)ne)->Unit = unit;
|
|
||||||
((AMFRoot *)ne)->Version = version;
|
|
||||||
|
|
||||||
// Check for child nodes
|
|
||||||
for (pugi::xml_node child : node->children()) {
|
|
||||||
if (child.name() == "object") {
|
|
||||||
ParseNode_Object(child);
|
|
||||||
} else if (child.name() == "material") {
|
|
||||||
ParseNode_Material(child);
|
|
||||||
} else if (child.name() == "texture") {
|
|
||||||
ParseNode_Texture(child);
|
|
||||||
} else if (child.name() == "constellation") {
|
|
||||||
ParseNode_Constellation(child);
|
|
||||||
} else if (child.name() == "metadata") {
|
|
||||||
ParseNode_Metadata(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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 &root) {
|
|
||||||
std::string id = root.attribute("id").as_string();
|
|
||||||
|
|
||||||
// create and if needed - define new grouping object.
|
|
||||||
AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
|
|
||||||
|
|
||||||
AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience
|
|
||||||
|
|
||||||
for (pugi::xml_node &child : root.children()) {
|
|
||||||
if (child.name() == "instance") {
|
|
||||||
ParseNode_Instance(child);
|
|
||||||
} else if (child.name() == "metadata") {
|
|
||||||
ParseNode_Metadata(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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 &root) {
|
|
||||||
std::string objectid = root.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.
|
|
||||||
AMFNodeElementBase *ne = new AMFInstance(mNodeElement_Cur);
|
|
||||||
|
|
||||||
AMFInstance &als = *((AMFInstance *)ne); // alias for convenience
|
|
||||||
|
|
||||||
als.ObjectID = objectid;
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool read_flag[6] = { false, false, false, false, false, false };
|
|
||||||
|
|
||||||
als.Delta.Set(0, 0, 0);
|
|
||||||
als.Rotation.Set(0, 0, 0);
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("instance");
|
|
||||||
MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
|
|
||||||
MACRO_NODECHECK_LOOPEND("instance");
|
|
||||||
ParseHelper_Node_Exit();
|
|
||||||
// also convert degrees to radians.
|
|
||||||
als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
|
|
||||||
als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
|
|
||||||
als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
|
|
||||||
} // if(!mReader->isEmptyElement())
|
|
||||||
else {
|
|
||||||
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
|
|
||||||
} // if(!mReader->isEmptyElement()) else
|
|
||||||
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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) {
|
|
||||||
|
|
||||||
std::string id;
|
|
||||||
for (pugi::xml_attribute_iterator ait = node.attributes_begin(); ait != node.attributes_end(); ++ait) {
|
|
||||||
if (ait->name() == "id") {
|
|
||||||
id = ait->as_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Read attributes for node <object>.
|
|
||||||
|
|
||||||
// create and if needed - define new geometry object.
|
|
||||||
AMFNodeElementBase *ne = new AMFObject(mNodeElement_Cur);
|
|
||||||
|
|
||||||
AMFObject &als = *((AMFObject *)ne); // alias for convenience
|
|
||||||
|
|
||||||
if (!id.empty()) {
|
|
||||||
als.ID = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for child nodes
|
|
||||||
for (pugi::xml_node_iterator it = node.children().begin(); it != node.children->end(); ++it) {
|
|
||||||
bool col_read = false;
|
|
||||||
if (it->name() == "mesh") {
|
|
||||||
ParseNode_Mesh(*it);
|
|
||||||
} else if (it->name() == "metadata") {
|
|
||||||
ParseNode_Metadata(*it);
|
|
||||||
} else if (it->name() == "color") {
|
|
||||||
ParseNode_Color(*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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;
|
|
||||||
AMFNodeElementBase *ne(nullptr);
|
|
||||||
|
|
||||||
// read attribute
|
|
||||||
MACRO_ATTRREAD_LOOPBEG;
|
|
||||||
MACRO_ATTRREAD_CHECK_RET("type", type, mXmlParser->getAttributeValue);
|
|
||||||
MACRO_ATTRREAD_LOOPEND;
|
|
||||||
// and value of node.
|
|
||||||
value = mXmlParser->getNodeData();
|
|
||||||
// Create node element and assign read data.
|
|
||||||
ne = new AMFMetadata(mNodeElement_Cur);
|
|
||||||
((AMFMetadata *)ne)->Type = type;
|
|
||||||
((AMFMetadata *)ne)->Value = value;
|
|
||||||
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************************************************************/
|
|
||||||
/******************************************************** Functions: BaseImporter set ********************************************************/
|
|
||||||
/*********************************************************************************************************************************************/
|
|
||||||
|
|
||||||
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
|
|
||||||
const std::string extension = GetExtension(pFile);
|
|
||||||
|
|
||||||
if (extension == "amf") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extension.length() || pCheckSig) {
|
|
||||||
const char *tokens[] = { "<amf" };
|
|
||||||
|
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AMFImporter::GetExtensionList(std::set<std::string> &extensionList) {
|
|
||||||
extensionList.insert("amf");
|
|
||||||
}
|
|
||||||
|
|
||||||
const aiImporterDesc *AMFImporter::GetInfo() const {
|
|
||||||
return &Description;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AMFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
ParseFile(pFile, pIOHandler);
|
|
||||||
|
|
||||||
Postprocess_BuildScene(pScene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AMFImporter::ParseNode_Mesh(XmlNode &node) {
|
|
||||||
AMFNodeElementBase *ne;
|
|
||||||
|
|
||||||
if (node.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (pugi::xml_node &child : node.children()) {
|
|
||||||
if (child.name() == "vertices") {
|
|
||||||
ParseNode_Vertices(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// create new mesh object.
|
|
||||||
ne = new AMFMesh(mNodeElement_Cur);
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool vert_read = false;
|
|
||||||
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("mesh");
|
|
||||||
if (XML_CheckNode_NameEqual("vertices")) {
|
|
||||||
// Check if data already defined.
|
|
||||||
if (vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
|
|
||||||
// read data and set flag about it
|
|
||||||
vert_read = true;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (XML_CheckNode_NameEqual("volume")) {
|
|
||||||
ParseNode_Volume();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MACRO_NODECHECK_LOOPEND("mesh");
|
|
||||||
ParseHelper_Node_Exit();
|
|
||||||
} // if(!mReader->isEmptyElement())
|
|
||||||
else {
|
|
||||||
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
|
|
||||||
} // if(!mReader->isEmptyElement()) else
|
|
||||||
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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 = new AMFVertices(mNodeElement_Cur);
|
|
||||||
|
|
||||||
for (pugi::xml_node &child : node.children()) {
|
|
||||||
if (child.name() == "vertices") {
|
|
||||||
ParseNode_Vertex(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for child nodes
|
|
||||||
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <vertex>
|
|
||||||
// </vertex>
|
|
||||||
// A vertex to be referenced in triangles.
|
|
||||||
// Multi elements - Yes.
|
|
||||||
// Parent element - <vertices>.
|
|
||||||
void AMFImporter::ParseNode_Vertex() {
|
|
||||||
AMFNodeElementBase *ne;
|
|
||||||
|
|
||||||
// create new mesh object.
|
|
||||||
ne = new AMFVertex(mNodeElement_Cur);
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool col_read = false;
|
|
||||||
bool coord_read = false;
|
|
||||||
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("vertex");
|
|
||||||
if (XML_CheckNode_NameEqual("color")) {
|
|
||||||
// Check if data already defined.
|
|
||||||
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <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() {
|
|
||||||
AMFNodeElementBase *ne;
|
|
||||||
|
|
||||||
// create new color object.
|
|
||||||
ne = new AMFCoordinates(mNodeElement_Cur);
|
|
||||||
|
|
||||||
AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience
|
|
||||||
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool read_flag[3] = { false, false, false };
|
|
||||||
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("coordinates");
|
|
||||||
MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y);
|
|
||||||
MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z);
|
|
||||||
MACRO_NODECHECK_LOOPEND("coordinates");
|
|
||||||
ParseHelper_Node_Exit();
|
|
||||||
// check that all components was defined
|
|
||||||
if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined.");
|
|
||||||
|
|
||||||
} // if(!mReader->isEmptyElement())
|
|
||||||
else {
|
|
||||||
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
|
|
||||||
} // if(!mReader->isEmptyElement()) else
|
|
||||||
|
|
||||||
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
|
|
||||||
}
|
|
||||||
|
|
||||||
// <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;
|
|
||||||
AMFNodeElementBase *ne;
|
|
||||||
|
|
||||||
// Read attributes for node <color>.
|
|
||||||
MACRO_ATTRREAD_LOOPBEG;
|
|
||||||
MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mXmlParser->getAttributeValue);
|
|
||||||
MACRO_ATTRREAD_CHECK_RET("type", type, mXmlParser->getAttributeValue);
|
|
||||||
MACRO_ATTRREAD_LOOPEND;
|
|
||||||
|
|
||||||
// create new object.
|
|
||||||
ne = new AMFVolume(mNodeElement_Cur);
|
|
||||||
// and assign read data
|
|
||||||
((AMFVolume *)ne)->MaterialID = materialid;
|
|
||||||
((AMFVolume *)ne)->Type = type;
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool col_read = false;
|
|
||||||
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("volume");
|
|
||||||
if (XML_CheckNode_NameEqual("color")) {
|
|
||||||
// Check if data already defined.
|
|
||||||
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <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() {
|
|
||||||
AMFNodeElementBase *ne;
|
|
||||||
|
|
||||||
// create new color object.
|
|
||||||
ne = new AMFTriangle(mNodeElement_Cur);
|
|
||||||
|
|
||||||
AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience
|
|
||||||
|
|
||||||
// Check for child nodes
|
|
||||||
if (!mXmlParser->isEmptyElement()) {
|
|
||||||
bool col_read = false, tex_read = false;
|
|
||||||
bool read_flag[3] = { false, false, false };
|
|
||||||
|
|
||||||
ParseHelper_Node_Enter(ne);
|
|
||||||
MACRO_NODECHECK_LOOPBEGIN("triangle");
|
|
||||||
if (XML_CheckNode_NameEqual("color")) {
|
|
||||||
// Check if data already defined.
|
|
||||||
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <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
|
|
|
@ -1,847 +0,0 @@
|
||||||
/*
|
|
||||||
Open Asset Import Library (assimp)
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
|
||||||
with or without modification, are permitted provided that the
|
|
||||||
following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer in the documentation and/or other
|
|
||||||
materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of the assimp team, nor the names of its
|
|
||||||
contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior
|
|
||||||
written permission of the assimp team.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/** @file AssbinExporter.cpp
|
|
||||||
* ASSBIN exporter main code
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
|
||||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
|
||||||
|
|
||||||
#include "Common/assbin_chunks.h"
|
|
||||||
#include "PostProcessing/ProcessHelper.h"
|
|
||||||
|
|
||||||
#include <assimp/version.h>
|
|
||||||
#include <assimp/IOStream.hpp>
|
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/Exporter.hpp>
|
|
||||||
#include <assimp/Exceptional.h>
|
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
|
||||||
# include <zlib.h>
|
|
||||||
#else
|
|
||||||
# include "../contrib/zlib/zlib.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
namespace Assimp {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
size_t Write(IOStream * stream, const T& v) {
|
|
||||||
return stream->Write( &v, sizeof(T), 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize an aiString
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiString>(IOStream * stream, const aiString& s) {
|
|
||||||
const size_t s2 = (uint32_t)s.length;
|
|
||||||
stream->Write(&s,4,1);
|
|
||||||
stream->Write(s.data,s2,1);
|
|
||||||
|
|
||||||
return s2+4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize an unsigned int as uint32_t
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<unsigned int>(IOStream * stream, const unsigned int& w) {
|
|
||||||
const uint32_t t = (uint32_t)w;
|
|
||||||
if (w > t) {
|
|
||||||
// this shouldn't happen, integers in Assimp data structures never exceed 2^32
|
|
||||||
throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->Write(&t,4,1);
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize an unsigned int as uint16_t
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<uint16_t>(IOStream * stream, const uint16_t& w) {
|
|
||||||
static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2");
|
|
||||||
stream->Write(&w,2,1);
|
|
||||||
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a float
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<float>(IOStream * stream, const float& f) {
|
|
||||||
static_assert(sizeof(float)==4, "sizeof(float)==4");
|
|
||||||
stream->Write(&f,4,1);
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a double
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<double>(IOStream * stream, const double& f) {
|
|
||||||
static_assert(sizeof(double)==8, "sizeof(double)==8");
|
|
||||||
stream->Write(&f,8,1);
|
|
||||||
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a vec3
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v) {
|
|
||||||
size_t t = Write<float>(stream,v.x);
|
|
||||||
t += Write<float>(stream,v.y);
|
|
||||||
t += Write<float>(stream,v.z);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a color value
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiColor3D>(IOStream * stream, const aiColor3D& v) {
|
|
||||||
size_t t = Write<float>(stream,v.r);
|
|
||||||
t += Write<float>(stream,v.g);
|
|
||||||
t += Write<float>(stream,v.b);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a color value
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v) {
|
|
||||||
size_t t = Write<float>(stream,v.r);
|
|
||||||
t += Write<float>(stream,v.g);
|
|
||||||
t += Write<float>(stream,v.b);
|
|
||||||
t += Write<float>(stream,v.a);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a quaternion
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v) {
|
|
||||||
size_t t = Write<float>(stream,v.w);
|
|
||||||
t += Write<float>(stream,v.x);
|
|
||||||
t += Write<float>(stream,v.y);
|
|
||||||
t += Write<float>(stream,v.z);
|
|
||||||
ai_assert(t == 16);
|
|
||||||
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a vertex weight
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v) {
|
|
||||||
size_t t = Write<unsigned int>(stream,v.mVertexId);
|
|
||||||
|
|
||||||
return t+Write<float>(stream,v.mWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize a mat4x4
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m) {
|
|
||||||
for (unsigned int i = 0; i < 4;++i) {
|
|
||||||
for (unsigned int i2 = 0; i2 < 4;++i2) {
|
|
||||||
Write<float>(stream,m[i][i2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize an aiVectorKey
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v) {
|
|
||||||
const size_t t = Write<double>(stream,v.mTime);
|
|
||||||
return t + Write<aiVector3D>(stream,v.mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Serialize an aiQuatKey
|
|
||||||
template <>
|
|
||||||
inline
|
|
||||||
size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v) {
|
|
||||||
const size_t t = Write<double>(stream,v.mTime);
|
|
||||||
return t + Write<aiQuaternion>(stream,v.mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline
|
|
||||||
size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) {
|
|
||||||
T minc, maxc;
|
|
||||||
ArrayBounds(in,size,minc,maxc);
|
|
||||||
|
|
||||||
const size_t t = Write<T>(stream,minc);
|
|
||||||
return t + Write<T>(stream,maxc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use this to write out non-byte arrays so that we write using the specializations.
|
|
||||||
// This way we avoid writing out extra bytes that potentially come from struct alignment.
|
|
||||||
template <typename T>
|
|
||||||
inline
|
|
||||||
size_t WriteArray(IOStream * stream, const T* in, unsigned int size) {
|
|
||||||
size_t n = 0;
|
|
||||||
for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
|
||||||
/** @class AssbinChunkWriter
|
|
||||||
* @brief Chunk writer mechanism for the .assbin file structure
|
|
||||||
*
|
|
||||||
* This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
|
|
||||||
* the difference being that this takes another IOStream as a "container" in the
|
|
||||||
* constructor, and when it is destroyed, it appends the magic number, the chunk size,
|
|
||||||
* and the chunk contents to the container stream. This allows relatively easy chunk
|
|
||||||
* chunk construction, even recursively.
|
|
||||||
*/
|
|
||||||
class AssbinChunkWriter : public IOStream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
uint8_t* buffer;
|
|
||||||
uint32_t magic;
|
|
||||||
IOStream * container;
|
|
||||||
size_t cur_size, cursor, initial;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
void Grow(size_t need = 0)
|
|
||||||
{
|
|
||||||
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
|
|
||||||
|
|
||||||
const uint8_t* const old = buffer;
|
|
||||||
buffer = new uint8_t[new_size];
|
|
||||||
|
|
||||||
if (old) {
|
|
||||||
memcpy(buffer,old,cur_size);
|
|
||||||
delete[] old;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_size = new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
|
|
||||||
: buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~AssbinChunkWriter()
|
|
||||||
{
|
|
||||||
if (container) {
|
|
||||||
container->Write( &magic, sizeof(uint32_t), 1 );
|
|
||||||
container->Write( &cursor, sizeof(uint32_t), 1 );
|
|
||||||
container->Write( buffer, 1, cursor );
|
|
||||||
}
|
|
||||||
if (buffer) delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void * GetBufferPointer() { return buffer; }
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
|
|
||||||
return aiReturn_FAILURE;
|
|
||||||
}
|
|
||||||
virtual size_t Tell() const {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
virtual void Flush() {
|
|
||||||
// not implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t FileSize() const {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) {
|
|
||||||
pSize *= pCount;
|
|
||||||
if (cursor + pSize > cur_size) {
|
|
||||||
Grow(cursor + pSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer+cursor, pvBuffer, pSize);
|
|
||||||
cursor += pSize;
|
|
||||||
|
|
||||||
return pCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
|
||||||
/** @class AssbinExport
|
|
||||||
* @brief Assbin exporter class
|
|
||||||
*
|
|
||||||
* This class performs the .assbin exporting, and is responsible for the file layout.
|
|
||||||
*/
|
|
||||||
class AssbinExport
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
bool shortened;
|
|
||||||
bool compressed;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryNode( IOStream * container, const aiNode* node)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
|
|
||||||
|
|
||||||
unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,node->mName);
|
|
||||||
Write<aiMatrix4x4>(&chunk,node->mTransformation);
|
|
||||||
Write<unsigned int>(&chunk,node->mNumChildren);
|
|
||||||
Write<unsigned int>(&chunk,node->mNumMeshes);
|
|
||||||
Write<unsigned int>(&chunk,nb_metadata);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
|
|
||||||
Write<unsigned int>(&chunk,node->mMeshes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i) {
|
|
||||||
WriteBinaryNode( &chunk, node->mChildren[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < nb_metadata; ++i) {
|
|
||||||
const aiString& key = node->mMetaData->mKeys[i];
|
|
||||||
aiMetadataType type = node->mMetaData->mValues[i].mType;
|
|
||||||
void* value = node->mMetaData->mValues[i].mData;
|
|
||||||
|
|
||||||
Write<aiString>(&chunk, key);
|
|
||||||
Write<uint16_t>(&chunk, type);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case AI_BOOL:
|
|
||||||
Write<bool>(&chunk, *((bool*) value));
|
|
||||||
break;
|
|
||||||
case AI_INT32:
|
|
||||||
Write<int32_t>(&chunk, *((int32_t*) value));
|
|
||||||
break;
|
|
||||||
case AI_UINT64:
|
|
||||||
Write<uint64_t>(&chunk, *((uint64_t*) value));
|
|
||||||
break;
|
|
||||||
case AI_FLOAT:
|
|
||||||
Write<float>(&chunk, *((float*) value));
|
|
||||||
break;
|
|
||||||
case AI_DOUBLE:
|
|
||||||
Write<double>(&chunk, *((double*) value));
|
|
||||||
break;
|
|
||||||
case AI_AISTRING:
|
|
||||||
Write<aiString>(&chunk, *((aiString*) value));
|
|
||||||
break;
|
|
||||||
case AI_AIVECTOR3D:
|
|
||||||
Write<aiVector3D>(&chunk, *((aiVector3D*) value));
|
|
||||||
break;
|
|
||||||
#ifdef SWIG
|
|
||||||
case FORCE_32BIT:
|
|
||||||
#endif // SWIG
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
|
|
||||||
|
|
||||||
Write<unsigned int>(&chunk,tex->mWidth);
|
|
||||||
Write<unsigned int>(&chunk,tex->mHeight);
|
|
||||||
// Write the texture format, but don't include the null terminator.
|
|
||||||
chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 );
|
|
||||||
|
|
||||||
if(!shortened) {
|
|
||||||
if (!tex->mHeight) {
|
|
||||||
chunk.Write(tex->pcData,1,tex->mWidth);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryBone(IOStream * container, const aiBone* b)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,b->mName);
|
|
||||||
Write<unsigned int>(&chunk,b->mNumWeights);
|
|
||||||
Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
|
|
||||||
|
|
||||||
// for the moment we write dumb min/max values for the bones, too.
|
|
||||||
// maybe I'll add a better, hash-like solution later
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,b->mWeights,b->mNumWeights);
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
|
|
||||||
|
|
||||||
Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
|
|
||||||
Write<unsigned int>(&chunk,mesh->mNumVertices);
|
|
||||||
Write<unsigned int>(&chunk,mesh->mNumFaces);
|
|
||||||
Write<unsigned int>(&chunk,mesh->mNumBones);
|
|
||||||
Write<unsigned int>(&chunk,mesh->mMaterialIndex);
|
|
||||||
|
|
||||||
// first of all, write bits for all existent vertex components
|
|
||||||
unsigned int c = 0;
|
|
||||||
if (mesh->mVertices) {
|
|
||||||
c |= ASSBIN_MESH_HAS_POSITIONS;
|
|
||||||
}
|
|
||||||
if (mesh->mNormals) {
|
|
||||||
c |= ASSBIN_MESH_HAS_NORMALS;
|
|
||||||
}
|
|
||||||
if (mesh->mTangents && mesh->mBitangents) {
|
|
||||||
c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
|
|
||||||
}
|
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
|
|
||||||
if (!mesh->mTextureCoords[n]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c |= ASSBIN_MESH_HAS_TEXCOORD(n);
|
|
||||||
}
|
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
|
|
||||||
if (!mesh->mColors[n]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c |= ASSBIN_MESH_HAS_COLOR(n);
|
|
||||||
}
|
|
||||||
Write<unsigned int>(&chunk,c);
|
|
||||||
|
|
||||||
aiVector3D minVec, maxVec;
|
|
||||||
if (mesh->mVertices) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
|
|
||||||
}
|
|
||||||
if (mesh->mNormals) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
|
|
||||||
}
|
|
||||||
if (mesh->mTangents && mesh->mBitangents) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
|
|
||||||
WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
|
|
||||||
} // else write as usual
|
|
||||||
else {
|
|
||||||
WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
|
|
||||||
WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
|
|
||||||
if (!mesh->mColors[n])
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
|
|
||||||
}
|
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
|
|
||||||
if (!mesh->mTextureCoords[n])
|
|
||||||
break;
|
|
||||||
|
|
||||||
// write number of UV components
|
|
||||||
Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
|
|
||||||
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write faces. There are no floating-point calculations involved
|
|
||||||
// in these, so we can write a simple hash over the face data
|
|
||||||
// to the dump file. We generate a single 32 Bit hash for 512 faces
|
|
||||||
// using Assimp's standard hashing function.
|
|
||||||
if (shortened) {
|
|
||||||
unsigned int processed = 0;
|
|
||||||
for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
|
|
||||||
|
|
||||||
uint32_t hash = 0;
|
|
||||||
for (unsigned int a = 0; a < job;++a) {
|
|
||||||
|
|
||||||
const aiFace& f = mesh->mFaces[processed+a];
|
|
||||||
uint32_t tmp = f.mNumIndices;
|
|
||||||
hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
|
|
||||||
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
|
|
||||||
static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
|
|
||||||
tmp = static_cast<uint32_t>( f.mIndices[i] );
|
|
||||||
hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Write<unsigned int>(&chunk,hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // else write as usual
|
|
||||||
{
|
|
||||||
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
|
|
||||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
|
|
||||||
const aiFace& f = mesh->mFaces[i];
|
|
||||||
|
|
||||||
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
|
|
||||||
Write<uint16_t>(&chunk,f.mNumIndices);
|
|
||||||
|
|
||||||
for (unsigned int a = 0; a < f.mNumIndices;++a) {
|
|
||||||
if (mesh->mNumVertices < (1u<<16)) {
|
|
||||||
Write<uint16_t>(&chunk,f.mIndices[a]);
|
|
||||||
}
|
|
||||||
else Write<unsigned int>(&chunk,f.mIndices[a]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write bones
|
|
||||||
if (mesh->mNumBones) {
|
|
||||||
for (unsigned int a = 0; a < mesh->mNumBones;++a) {
|
|
||||||
const aiBone* b = mesh->mBones[a];
|
|
||||||
WriteBinaryBone(&chunk,b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,prop->mKey);
|
|
||||||
Write<unsigned int>(&chunk,prop->mSemantic);
|
|
||||||
Write<unsigned int>(&chunk,prop->mIndex);
|
|
||||||
|
|
||||||
Write<unsigned int>(&chunk,prop->mDataLength);
|
|
||||||
Write<unsigned int>(&chunk,(unsigned int)prop->mType);
|
|
||||||
chunk.Write(prop->mData,1,prop->mDataLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
|
|
||||||
|
|
||||||
Write<unsigned int>(&chunk,mat->mNumProperties);
|
|
||||||
for (unsigned int i = 0; i < mat->mNumProperties;++i) {
|
|
||||||
WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,nd->mNodeName);
|
|
||||||
Write<unsigned int>(&chunk,nd->mNumPositionKeys);
|
|
||||||
Write<unsigned int>(&chunk,nd->mNumRotationKeys);
|
|
||||||
Write<unsigned int>(&chunk,nd->mNumScalingKeys);
|
|
||||||
Write<unsigned int>(&chunk,nd->mPreState);
|
|
||||||
Write<unsigned int>(&chunk,nd->mPostState);
|
|
||||||
|
|
||||||
if (nd->mPositionKeys) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
|
|
||||||
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
|
|
||||||
}
|
|
||||||
if (nd->mRotationKeys) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
|
|
||||||
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
|
|
||||||
}
|
|
||||||
if (nd->mScalingKeys) {
|
|
||||||
if (shortened) {
|
|
||||||
WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
|
|
||||||
|
|
||||||
} // else write as usual
|
|
||||||
else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,anim->mName);
|
|
||||||
Write<double>(&chunk,anim->mDuration);
|
|
||||||
Write<double>(&chunk,anim->mTicksPerSecond);
|
|
||||||
Write<unsigned int>(&chunk,anim->mNumChannels);
|
|
||||||
|
|
||||||
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
|
|
||||||
const aiNodeAnim* nd = anim->mChannels[a];
|
|
||||||
WriteBinaryNodeAnim(&chunk,nd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryLight( IOStream * container, const aiLight* l )
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,l->mName);
|
|
||||||
Write<unsigned int>(&chunk,l->mType);
|
|
||||||
|
|
||||||
if (l->mType != aiLightSource_DIRECTIONAL) {
|
|
||||||
Write<float>(&chunk,l->mAttenuationConstant);
|
|
||||||
Write<float>(&chunk,l->mAttenuationLinear);
|
|
||||||
Write<float>(&chunk,l->mAttenuationQuadratic);
|
|
||||||
}
|
|
||||||
|
|
||||||
Write<aiColor3D>(&chunk,l->mColorDiffuse);
|
|
||||||
Write<aiColor3D>(&chunk,l->mColorSpecular);
|
|
||||||
Write<aiColor3D>(&chunk,l->mColorAmbient);
|
|
||||||
|
|
||||||
if (l->mType == aiLightSource_SPOT) {
|
|
||||||
Write<float>(&chunk,l->mAngleInnerCone);
|
|
||||||
Write<float>(&chunk,l->mAngleOuterCone);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
|
|
||||||
|
|
||||||
Write<aiString>(&chunk,cam->mName);
|
|
||||||
Write<aiVector3D>(&chunk,cam->mPosition);
|
|
||||||
Write<aiVector3D>(&chunk,cam->mLookAt);
|
|
||||||
Write<aiVector3D>(&chunk,cam->mUp);
|
|
||||||
Write<float>(&chunk,cam->mHorizontalFOV);
|
|
||||||
Write<float>(&chunk,cam->mClipPlaneNear);
|
|
||||||
Write<float>(&chunk,cam->mClipPlaneFar);
|
|
||||||
Write<float>(&chunk,cam->mAspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
void WriteBinaryScene( IOStream * container, const aiScene* scene)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
|
|
||||||
|
|
||||||
// basic scene information
|
|
||||||
Write<unsigned int>(&chunk,scene->mFlags);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumMeshes);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumMaterials);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumAnimations);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumTextures);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumLights);
|
|
||||||
Write<unsigned int>(&chunk,scene->mNumCameras);
|
|
||||||
|
|
||||||
// write node graph
|
|
||||||
WriteBinaryNode( &chunk, scene->mRootNode );
|
|
||||||
|
|
||||||
// write all meshes
|
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
|
|
||||||
const aiMesh* mesh = scene->mMeshes[i];
|
|
||||||
WriteBinaryMesh( &chunk,mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write materials
|
|
||||||
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
|
|
||||||
const aiMaterial* mat = scene->mMaterials[i];
|
|
||||||
WriteBinaryMaterial(&chunk,mat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write all animations
|
|
||||||
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
|
|
||||||
const aiAnimation* anim = scene->mAnimations[i];
|
|
||||||
WriteBinaryAnim(&chunk,anim);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// write all textures
|
|
||||||
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
|
|
||||||
const aiTexture* mesh = scene->mTextures[i];
|
|
||||||
WriteBinaryTexture(&chunk,mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write lights
|
|
||||||
for (unsigned int i = 0; i < scene->mNumLights;++i) {
|
|
||||||
const aiLight* l = scene->mLights[i];
|
|
||||||
WriteBinaryLight(&chunk,l);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write cameras
|
|
||||||
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
|
|
||||||
const aiCamera* cam = scene->mCameras[i];
|
|
||||||
WriteBinaryCamera(&chunk,cam);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AssbinExport()
|
|
||||||
: shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
|
||||||
// Write a binary model dump
|
|
||||||
void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
|
|
||||||
{
|
|
||||||
IOStream * out = pIOSystem->Open( pFile, "wb" );
|
|
||||||
if (!out) return;
|
|
||||||
|
|
||||||
time_t tt = time(NULL);
|
|
||||||
#if _WIN32
|
|
||||||
tm* p = gmtime(&tt);
|
|
||||||
#else
|
|
||||||
struct tm now;
|
|
||||||
tm* p = gmtime_r(&tt, &now);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// header
|
|
||||||
char s[64];
|
|
||||||
memset( s, 0, 64 );
|
|
||||||
#if _MSC_VER >= 1400
|
|
||||||
sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
|
|
||||||
#else
|
|
||||||
ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
|
|
||||||
#endif
|
|
||||||
out->Write( s, 44, 1 );
|
|
||||||
// == 44 bytes
|
|
||||||
|
|
||||||
Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
|
|
||||||
Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
|
|
||||||
Write<unsigned int>( out, aiGetVersionRevision() );
|
|
||||||
Write<unsigned int>( out, aiGetCompileFlags() );
|
|
||||||
Write<uint16_t>( out, shortened );
|
|
||||||
Write<uint16_t>( out, compressed );
|
|
||||||
// == 20 bytes
|
|
||||||
|
|
||||||
char buff[256];
|
|
||||||
strncpy(buff,pFile,256);
|
|
||||||
out->Write(buff,sizeof(char),256);
|
|
||||||
|
|
||||||
char cmd[] = "\0";
|
|
||||||
strncpy(buff,cmd,128);
|
|
||||||
out->Write(buff,sizeof(char),128);
|
|
||||||
|
|
||||||
// leave 64 bytes free for future extensions
|
|
||||||
memset(buff,0xcd,64);
|
|
||||||
out->Write(buff,sizeof(char),64);
|
|
||||||
// == 435 bytes
|
|
||||||
|
|
||||||
// ==== total header size: 512 bytes
|
|
||||||
ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
|
|
||||||
|
|
||||||
// Up to here the data is uncompressed. For compressed files, the rest
|
|
||||||
// is compressed using standard DEFLATE from zlib.
|
|
||||||
if (compressed)
|
|
||||||
{
|
|
||||||
AssbinChunkWriter uncompressedStream( NULL, 0 );
|
|
||||||
WriteBinaryScene( &uncompressedStream, pScene );
|
|
||||||
|
|
||||||
uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
|
|
||||||
uLongf compressedSize = (uLongf)compressBound(uncompressedSize);
|
|
||||||
uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
|
|
||||||
|
|
||||||
int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
|
|
||||||
if(res != Z_OK)
|
|
||||||
{
|
|
||||||
delete [] compressedBuffer;
|
|
||||||
pIOSystem->Close(out);
|
|
||||||
throw DeadlyExportError("Compression failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
|
|
||||||
out->Write( compressedBuffer, sizeof(char), compressedSize );
|
|
||||||
|
|
||||||
delete[] compressedBuffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteBinaryScene( out, pScene );
|
|
||||||
}
|
|
||||||
|
|
||||||
pIOSystem->Close( out );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
|
|
||||||
AssbinExport exporter;
|
|
||||||
exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
|
|
||||||
}
|
|
||||||
} // end of namespace Assimp
|
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
|
||||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
File diff suppressed because it is too large
Load Diff
|
@ -43,120 +43,117 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||||
|
|
||||||
#include "3DS/3DSExporter.h"
|
#include "AssetLib/3DS/3DSExporter.h"
|
||||||
#include "3DS/3DSLoader.h"
|
#include "AssetLib/3DS/3DSHelper.h"
|
||||||
#include "3DS/3DSHelper.h"
|
#include "AssetLib/3DS/3DSLoader.h"
|
||||||
#include "PostProcessing/SplitLargeMeshes.h"
|
#include "PostProcessing/SplitLargeMeshes.h"
|
||||||
|
|
||||||
#include <assimp/SceneCombiner.h>
|
#include <assimp/SceneCombiner.h>
|
||||||
#include <assimp/StringComparison.h>
|
#include <assimp/StringComparison.h>
|
||||||
#include <assimp/IOSystem.hpp>
|
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include <assimp/Exporter.hpp>
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
using namespace D3DS;
|
using namespace D3DS;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Scope utility to write a 3DS file chunk.
|
// Scope utility to write a 3DS file chunk.
|
||||||
//
|
//
|
||||||
// Upon construction, the chunk header is written with the chunk type (flags)
|
// Upon construction, the chunk header is written with the chunk type (flags)
|
||||||
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
||||||
// size based on the then-position of the output stream cursor is filled in.
|
// size based on the then-position of the output stream cursor is filled in.
|
||||||
class ChunkWriter {
|
class ChunkWriter {
|
||||||
enum {
|
enum {
|
||||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef
|
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
|
||||||
, SIZE_OFFSET = 2
|
SIZE_OFFSET = 2
|
||||||
};
|
|
||||||
public:
|
|
||||||
|
|
||||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
|
||||||
: writer(writer)
|
|
||||||
{
|
|
||||||
chunk_start_pos = writer.GetCurrentPos();
|
|
||||||
writer.PutU2(chunk_type);
|
|
||||||
writer.PutU4(CHUNK_SIZE_NOT_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
~ChunkWriter() {
|
|
||||||
std::size_t head_pos = writer.GetCurrentPos();
|
|
||||||
|
|
||||||
ai_assert(head_pos > chunk_start_pos);
|
|
||||||
const std::size_t chunk_size = head_pos - chunk_start_pos;
|
|
||||||
|
|
||||||
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
|
|
||||||
writer.PutU4(static_cast<uint32_t>(chunk_size));
|
|
||||||
writer.SetCurrentPos(head_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StreamWriterLE& writer;
|
|
||||||
std::size_t chunk_start_pos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
// Return an unique name for a given |mesh| attached to |node| that
|
ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
|
||||||
// preserves the mesh's given name if it has one. |index| is the index
|
writer(writer) {
|
||||||
// of the mesh in |aiScene::mMeshes|.
|
chunk_start_pos = writer.GetCurrentPos();
|
||||||
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
|
writer.PutU2(chunk_type);
|
||||||
static const std::string underscore = "_";
|
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
|
||||||
char postfix[10] = {0};
|
|
||||||
ASSIMP_itoa10(postfix, index);
|
|
||||||
|
|
||||||
std::string result = node.mName.C_Str();
|
|
||||||
if (mesh.mName.length > 0) {
|
|
||||||
result += underscore + mesh.mName.C_Str();
|
|
||||||
}
|
|
||||||
return result + underscore + postfix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return an unique name for a given |mat| with original position |index|
|
~ChunkWriter() {
|
||||||
// in |aiScene::mMaterials|. The name preserves the original material
|
std::size_t head_pos = writer.GetCurrentPos();
|
||||||
// name if possible.
|
|
||||||
std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
|
|
||||||
static const std::string underscore = "_";
|
|
||||||
char postfix[10] = {0};
|
|
||||||
ASSIMP_itoa10(postfix, index);
|
|
||||||
|
|
||||||
aiString mat_name;
|
ai_assert(head_pos > chunk_start_pos);
|
||||||
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
|
const std::size_t chunk_size = head_pos - chunk_start_pos;
|
||||||
return mat_name.C_Str() + underscore + postfix;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Material" + underscore + postfix;
|
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
|
||||||
|
writer.PutU4(static_cast<uint32_t>(chunk_size));
|
||||||
|
writer.SetCurrentPos(head_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect world transformations for each node
|
private:
|
||||||
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
|
StreamWriterLE &writer;
|
||||||
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
std::size_t chunk_start_pos;
|
||||||
trafos[node] = parent * node->mTransformation;
|
};
|
||||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
|
||||||
CollectTrafos(node->mChildren[i], trafos);
|
// Return an unique name for a given |mesh| attached to |node| that
|
||||||
}
|
// preserves the mesh's given name if it has one. |index| is the index
|
||||||
|
// of the mesh in |aiScene::mMeshes|.
|
||||||
|
std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) {
|
||||||
|
static const std::string underscore = "_";
|
||||||
|
char postfix[10] = { 0 };
|
||||||
|
ASSIMP_itoa10(postfix, index);
|
||||||
|
|
||||||
|
std::string result = node.mName.C_Str();
|
||||||
|
if (mesh.mName.length > 0) {
|
||||||
|
result += underscore + mesh.mName.C_Str();
|
||||||
|
}
|
||||||
|
return result + underscore + postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an unique name for a given |mat| with original position |index|
|
||||||
|
// in |aiScene::mMaterials|. The name preserves the original material
|
||||||
|
// name if possible.
|
||||||
|
std::string GetMaterialName(const aiMaterial &mat, unsigned int index) {
|
||||||
|
static const std::string underscore = "_";
|
||||||
|
char postfix[10] = { 0 };
|
||||||
|
ASSIMP_itoa10(postfix, index);
|
||||||
|
|
||||||
|
aiString mat_name;
|
||||||
|
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
|
||||||
|
return mat_name.C_Str() + underscore + postfix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a flat list of the meshes (by index) assigned to each node
|
return "Material" + underscore + postfix;
|
||||||
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
|
}
|
||||||
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
|
||||||
meshes.insert(std::make_pair(node, node->mMeshes[i]));
|
// Collect world transformations for each node
|
||||||
}
|
void CollectTrafos(const aiNode *node, std::map<const aiNode *, aiMatrix4x4> &trafos) {
|
||||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
const aiMatrix4x4 &parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
||||||
CollectMeshes(node->mChildren[i], meshes);
|
trafos[node] = parent * node->mTransformation;
|
||||||
}
|
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||||
|
CollectTrafos(node->mChildren[i], trafos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a flat list of the meshes (by index) assigned to each node
|
||||||
|
void CollectMeshes(const aiNode *node, std::multimap<const aiNode *, unsigned int> &meshes) {
|
||||||
|
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||||
|
meshes.insert(std::make_pair(node, node->mMeshes[i]));
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||||
|
CollectMeshes(node->mChildren[i], meshes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
|
// 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"));
|
||||||
std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
|
if (!outfile) {
|
||||||
if(!outfile) {
|
|
||||||
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +164,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
|
||||||
// SplitLargeMeshes can do this, but it requires the correct limit to be set
|
// SplitLargeMeshes can do this, but it requires the correct limit to be set
|
||||||
// which is not possible with the current way of specifying preprocess steps
|
// which is not possible with the current way of specifying preprocess steps
|
||||||
// in |Exporter::ExportFormatEntry|.
|
// in |Exporter::ExportFormatEntry|.
|
||||||
aiScene* scenecopy_tmp;
|
aiScene *scenecopy_tmp;
|
||||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
SceneCombiner::CopyScene(&scenecopy_tmp, pScene);
|
||||||
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
|
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||||
|
|
||||||
SplitLargeMeshesProcess_Triangle tri_splitter;
|
SplitLargeMeshesProcess_Triangle tri_splitter;
|
||||||
|
@ -186,28 +183,26 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
|
Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene *scene) :
|
||||||
: scene(scene)
|
scene(scene), writer(outfile) {
|
||||||
, writer(outfile)
|
|
||||||
{
|
|
||||||
CollectTrafos(scene->mRootNode, trafos);
|
CollectTrafos(scene->mRootNode, trafos);
|
||||||
CollectMeshes(scene->mRootNode, meshes);
|
CollectMeshes(scene->mRootNode, meshes);
|
||||||
|
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
|
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAIN);
|
||||||
|
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
||||||
WriteMaterials();
|
WriteMaterials();
|
||||||
WriteMeshes();
|
WriteMeshes();
|
||||||
|
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
ChunkWriter curChunk1(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
||||||
writer.PutF4(1.0f);
|
writer.PutF4(1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
||||||
WriteHierarchy(*scene->mRootNode, -1, -1);
|
WriteHierarchy(*scene->mRootNode, -1, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,15 +212,13 @@ Discreet3DSExporter::~Discreet3DSExporter() {
|
||||||
// empty
|
// 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
|
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||||
|
|
||||||
// Assimp node names are unique and distinct from all mesh-node
|
// Assimp node names are unique and distinct from all mesh-node
|
||||||
// names we generate; thus we can use them as-is
|
// names we generate; thus we can use them as-is
|
||||||
|
@ -237,7 +230,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
||||||
|
|
||||||
int16_t hierarchy_pos = static_cast<int16_t>(seq);
|
int16_t hierarchy_pos = static_cast<int16_t>(seq);
|
||||||
if (sibling_level != -1) {
|
if (sibling_level != -1) {
|
||||||
hierarchy_pos = sibling_level;
|
hierarchy_pos = (uint16_t)sibling_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the hierarchy position
|
// Write the hierarchy position
|
||||||
|
@ -260,9 +253,9 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
||||||
const bool first_child = node.mNumChildren == 0 && i == 0;
|
const bool first_child = node.mNumChildren == 0 && i == 0;
|
||||||
|
|
||||||
const unsigned int mesh_idx = node.mMeshes[i];
|
const unsigned int mesh_idx = node.mMeshes[i];
|
||||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
|
||||||
|
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||||
WriteString(GetMeshName(mesh, mesh_idx, node));
|
WriteString(GetMeshName(mesh, mesh_idx, node));
|
||||||
|
@ -276,36 +269,35 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteMaterials()
|
void Discreet3DSExporter::WriteMaterials() {
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||||
const aiMaterial& mat = *scene->mMaterials[i];
|
const aiMaterial &mat = *scene->mMaterials[i];
|
||||||
|
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
|
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
|
||||||
const std::string& name = GetMaterialName(mat, i);
|
const std::string &name = GetMaterialName(mat, i);
|
||||||
WriteString(name);
|
WriteString(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
aiColor3D color;
|
aiColor3D color;
|
||||||
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
|
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
||||||
WriteColor(color);
|
WriteColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
|
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
||||||
WriteColor(color);
|
WriteColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
|
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
||||||
WriteColor(color);
|
WriteColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
|
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
||||||
WriteColor(color);
|
WriteColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +306,7 @@ void Discreet3DSExporter::WriteMaterials()
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
|
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
|
||||||
|
|
||||||
Discreet3DS::shadetype3ds shading_mode_out;
|
Discreet3DS::shadetype3ds shading_mode_out;
|
||||||
switch(shading_mode) {
|
switch (shading_mode) {
|
||||||
case aiShadingMode_Flat:
|
case aiShadingMode_Flat:
|
||||||
case aiShadingMode_NoShading:
|
case aiShadingMode_NoShading:
|
||||||
shading_mode_out = Discreet3DS::Flat;
|
shading_mode_out = Discreet3DS::Flat;
|
||||||
|
@ -341,7 +333,6 @@ void Discreet3DSExporter::WriteMaterials()
|
||||||
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
|
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float f;
|
float f;
|
||||||
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
|
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
|
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
|
||||||
|
@ -370,8 +361,7 @@ void Discreet3DSExporter::WriteMaterials()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
|
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
||||||
{
|
|
||||||
aiString path;
|
aiString path;
|
||||||
aiTextureMapMode map_mode[2] = {
|
aiTextureMapMode map_mode[2] = {
|
||||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||||
|
@ -389,19 +379,18 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
|
||||||
|
|
||||||
ChunkWriter chunk(writer, chunk_flags);
|
ChunkWriter chunk(writer, chunk_flags);
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
||||||
WriteString(path);
|
WriteString(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
WritePercentChunk(blend);
|
WritePercentChunk(blend);
|
||||||
|
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
||||||
uint16_t val = 0; // WRAP
|
uint16_t val = 0; // WRAP
|
||||||
if (map_mode[0] == aiTextureMapMode_Mirror) {
|
if (map_mode[0] == aiTextureMapMode_Mirror) {
|
||||||
val = 0x2;
|
val = 0x2;
|
||||||
}
|
} else if (map_mode[0] == aiTextureMapMode_Decal) {
|
||||||
else if (map_mode[0] == aiTextureMapMode_Decal) {
|
|
||||||
val = 0x10;
|
val = 0x10;
|
||||||
}
|
}
|
||||||
writer.PutU2(val);
|
writer.PutU2(val);
|
||||||
|
@ -410,8 +399,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteMeshes()
|
void Discreet3DSExporter::WriteMeshes() {
|
||||||
{
|
|
||||||
// NOTE: 3DS allows for instances. However:
|
// NOTE: 3DS allows for instances. However:
|
||||||
// i) not all importers support reading them
|
// i) not all importers support reading them
|
||||||
// ii) instances are not as flexible as they are in assimp, in particular,
|
// ii) instances are not as flexible as they are in assimp, in particular,
|
||||||
|
@ -423,36 +411,35 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
// Furthermore, the TRIMESH is transformed into world space so that it will
|
// Furthermore, the TRIMESH is transformed into world space so that it will
|
||||||
// appear correctly if importers don't read the scene hierarchy at all.
|
// appear correctly if importers don't read the scene hierarchy at all.
|
||||||
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
|
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
|
||||||
const aiNode& node = *(*it).first;
|
const aiNode &node = *(*it).first;
|
||||||
const unsigned int mesh_idx = (*it).second;
|
const unsigned int mesh_idx = (*it).second;
|
||||||
|
|
||||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
|
||||||
|
|
||||||
// This should not happen if the SLM step is correctly executed
|
// This should not happen if the SLM step is correctly executed
|
||||||
// before the scene is handed to the exporter
|
// before the scene is handed to the exporter
|
||||||
ai_assert(mesh.mNumVertices <= 0xffff);
|
ai_assert(mesh.mNumVertices <= 0xffff);
|
||||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||||
|
|
||||||
const aiMatrix4x4& trafo = trafos[&node];
|
const aiMatrix4x4 &trafo = trafos[&node];
|
||||||
|
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
|
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
|
||||||
|
|
||||||
// Mesh name is tied to the node it is attached to so it can later be referenced
|
// Mesh name is tied to the node it is attached to so it can later be referenced
|
||||||
const std::string& name = GetMeshName(mesh, mesh_idx, node);
|
const std::string &name = GetMeshName(mesh, mesh_idx, node);
|
||||||
WriteString(name);
|
WriteString(name);
|
||||||
|
|
||||||
|
|
||||||
// TRIMESH chunk
|
// TRIMESH chunk
|
||||||
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
||||||
|
|
||||||
// Vertices in world space
|
// Vertices in world space
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
||||||
|
|
||||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||||
writer.PutU2(count);
|
writer.PutU2(count);
|
||||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||||
const aiVector3D& v = trafo * mesh.mVertices[i];
|
const aiVector3D &v = trafo * mesh.mVertices[i];
|
||||||
writer.PutF4(v.x);
|
writer.PutF4(v.x);
|
||||||
writer.PutF4(v.y);
|
writer.PutF4(v.y);
|
||||||
writer.PutF4(v.z);
|
writer.PutF4(v.z);
|
||||||
|
@ -461,12 +448,12 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
|
|
||||||
// UV coordinates
|
// UV coordinates
|
||||||
if (mesh.HasTextureCoords(0)) {
|
if (mesh.HasTextureCoords(0)) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
||||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||||
writer.PutU2(count);
|
writer.PutU2(count);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||||
const aiVector3D& v = mesh.mTextureCoords[0][i];
|
const aiVector3D &v = mesh.mTextureCoords[0][i];
|
||||||
writer.PutF4(v.x);
|
writer.PutF4(v.x);
|
||||||
writer.PutF4(v.y);
|
writer.PutF4(v.y);
|
||||||
}
|
}
|
||||||
|
@ -474,14 +461,14 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
|
|
||||||
// Faces (indices)
|
// Faces (indices)
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||||
|
|
||||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||||
|
|
||||||
// Count triangles, discard lines and points
|
// Count triangles, discard lines and points
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||||
const aiFace& f = mesh.mFaces[i];
|
const aiFace &f = mesh.mFaces[i];
|
||||||
if (f.mNumIndices < 3) {
|
if (f.mNumIndices < 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +479,7 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
|
|
||||||
writer.PutU2(count);
|
writer.PutU2(count);
|
||||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||||
const aiFace& f = mesh.mFaces[i];
|
const aiFace &f = mesh.mFaces[i];
|
||||||
if (f.mNumIndices < 3) {
|
if (f.mNumIndices < 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -513,7 +500,7 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
|
|
||||||
// Transformation matrix by which the mesh vertices have been pre-transformed with.
|
// Transformation matrix by which the mesh vertices have been pre-transformed with.
|
||||||
{
|
{
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
||||||
for (unsigned int r = 0; r < 4; ++r) {
|
for (unsigned int r = 0; r < 4; ++r) {
|
||||||
for (unsigned int c = 0; c < 3; ++c) {
|
for (unsigned int c = 0; c < 3; ++c) {
|
||||||
writer.PutF4(trafo[r][c]);
|
writer.PutF4(trafo[r][c]);
|
||||||
|
@ -524,10 +511,9 @@ void Discreet3DSExporter::WriteMeshes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) {
|
||||||
{
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
||||||
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
|
||||||
WriteString(name);
|
WriteString(name);
|
||||||
|
|
||||||
// Because assimp splits meshes by material, only a single
|
// Because assimp splits meshes by material, only a single
|
||||||
|
@ -542,7 +528,7 @@ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteString(const std::string& s) {
|
void Discreet3DSExporter::WriteString(const std::string &s) {
|
||||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||||
writer.PutI1(*it);
|
writer.PutI1(*it);
|
||||||
}
|
}
|
||||||
|
@ -550,7 +536,7 @@ void Discreet3DSExporter::WriteString(const std::string& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteString(const aiString& s) {
|
void Discreet3DSExporter::WriteString(const aiString &s) {
|
||||||
for (std::size_t i = 0; i < s.length; ++i) {
|
for (std::size_t i = 0; i < s.length; ++i) {
|
||||||
writer.PutI1(s.data[i]);
|
writer.PutI1(s.data[i]);
|
||||||
}
|
}
|
||||||
|
@ -558,8 +544,8 @@ void Discreet3DSExporter::WriteString(const aiString& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
|
void Discreet3DSExporter::WriteColor(const aiColor3D &color) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||||
writer.PutF4(color.r);
|
writer.PutF4(color.r);
|
||||||
writer.PutF4(color.g);
|
writer.PutF4(color.g);
|
||||||
writer.PutF4(color.b);
|
writer.PutF4(color.b);
|
||||||
|
@ -567,16 +553,15 @@ void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WritePercentChunk(float f) {
|
void Discreet3DSExporter::WritePercentChunk(float f) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
||||||
writer.PutF4(f);
|
writer.PutF4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Discreet3DSExporter::WritePercentChunk(double f) {
|
void Discreet3DSExporter::WritePercentChunk(double f) {
|
||||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTD);
|
ChunkWriter ccurChunkhunk(writer, Discreet3DS::CHUNK_PERCENTD);
|
||||||
writer.PutF8(f);
|
writer.PutF8(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
|
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -45,18 +45,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_3DSFILEHELPER_H_INC
|
#ifndef AI_3DSFILEHELPER_H_INC
|
||||||
#define AI_3DSFILEHELPER_H_INC
|
#define AI_3DSFILEHELPER_H_INC
|
||||||
|
|
||||||
#include <assimp/SpatialSort.h>
|
|
||||||
#include <assimp/SmoothingGroups.h>
|
#include <assimp/SmoothingGroups.h>
|
||||||
|
#include <assimp/SpatialSort.h>
|
||||||
#include <assimp/StringUtils.h>
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/qnan.h>
|
#include <assimp/anim.h>
|
||||||
#include <assimp/material.h>
|
|
||||||
#include <assimp/camera.h>
|
#include <assimp/camera.h>
|
||||||
#include <assimp/light.h>
|
#include <assimp/light.h>
|
||||||
#include <assimp/anim.h>
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/qnan.h>
|
||||||
#include <stdio.h> //sprintf
|
#include <stdio.h> //sprintf
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace D3DS {
|
namespace D3DS {
|
||||||
|
|
||||||
#include <assimp/Compiler/pushpack1.h>
|
#include <assimp/Compiler/pushpack1.h>
|
||||||
|
|
||||||
|
@ -77,15 +77,13 @@ private:
|
||||||
public:
|
public:
|
||||||
//! data structure for a single chunk in a .3ds file
|
//! data structure for a single chunk in a .3ds file
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
uint16_t Flag;
|
uint16_t Flag;
|
||||||
uint32_t Size;
|
uint32_t Size;
|
||||||
} PACK_STRUCT;
|
} PACK_STRUCT;
|
||||||
|
|
||||||
|
|
||||||
//! Used for shading field in material3ds structure
|
//! Used for shading field in material3ds structure
|
||||||
//! From AutoDesk 3ds SDK
|
//! From AutoDesk 3ds SDK
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
// translated to gouraud shading with wireframe active
|
// translated to gouraud shading with wireframe active
|
||||||
Wire = 0x0,
|
Wire = 0x0,
|
||||||
|
|
||||||
|
@ -109,59 +107,57 @@ public:
|
||||||
} shadetype3ds;
|
} shadetype3ds;
|
||||||
|
|
||||||
// Flags for animated keys
|
// Flags for animated keys
|
||||||
enum
|
enum {
|
||||||
{
|
KEY_USE_TENS = 0x1,
|
||||||
KEY_USE_TENS = 0x1,
|
KEY_USE_CONT = 0x2,
|
||||||
KEY_USE_CONT = 0x2,
|
KEY_USE_BIAS = 0x4,
|
||||||
KEY_USE_BIAS = 0x4,
|
KEY_USE_EASE_TO = 0x8,
|
||||||
KEY_USE_EASE_TO = 0x8,
|
KEY_USE_EASE_FROM = 0x10
|
||||||
KEY_USE_EASE_FROM = 0x10
|
};
|
||||||
} ;
|
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Basic chunks which can be found everywhere in the file
|
// Basic chunks which can be found everywhere in the file
|
||||||
CHUNK_VERSION = 0x0002,
|
CHUNK_VERSION = 0x0002,
|
||||||
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
|
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
|
||||||
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
|
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
|
||||||
|
|
||||||
// Linear color values (gamma = 2.2?)
|
// Linear color values (gamma = 2.2?)
|
||||||
CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B
|
CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B
|
||||||
CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B
|
CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B
|
||||||
|
|
||||||
CHUNK_PERCENTW = 0x0030, // int2 percentage
|
CHUNK_PERCENTW = 0x0030, // int2 percentage
|
||||||
CHUNK_PERCENTF = 0x0031, // float4 percentage
|
CHUNK_PERCENTF = 0x0031, // float4 percentage
|
||||||
CHUNK_PERCENTD = 0x0032, // float8 percentage
|
CHUNK_PERCENTD = 0x0032, // float8 percentage
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
// Prj master chunk
|
// Prj master chunk
|
||||||
CHUNK_PRJ = 0xC23D,
|
CHUNK_PRJ = 0xC23D,
|
||||||
|
|
||||||
// MDLI master chunk
|
// MDLI master chunk
|
||||||
CHUNK_MLI = 0x3DAA,
|
CHUNK_MLI = 0x3DAA,
|
||||||
|
|
||||||
// Primary main chunk of the .3ds file
|
// Primary main chunk of the .3ds file
|
||||||
CHUNK_MAIN = 0x4D4D,
|
CHUNK_MAIN = 0x4D4D,
|
||||||
|
|
||||||
// Mesh main chunk
|
// Mesh main chunk
|
||||||
CHUNK_OBJMESH = 0x3D3D,
|
CHUNK_OBJMESH = 0x3D3D,
|
||||||
|
|
||||||
// Specifies the background color of the .3ds file
|
// Specifies the background color of the .3ds file
|
||||||
// This is passed through the material system for
|
// This is passed through the material system for
|
||||||
// viewing purposes.
|
// viewing purposes.
|
||||||
CHUNK_BKGCOLOR = 0x1200,
|
CHUNK_BKGCOLOR = 0x1200,
|
||||||
|
|
||||||
// Specifies the ambient base color of the scene.
|
// Specifies the ambient base color of the scene.
|
||||||
// This is added to all materials in the file
|
// This is added to all materials in the file
|
||||||
CHUNK_AMBCOLOR = 0x2100,
|
CHUNK_AMBCOLOR = 0x2100,
|
||||||
|
|
||||||
// Specifies the background image for the whole scene
|
// Specifies the background image for the whole scene
|
||||||
// This value is passed through the material system
|
// This value is passed through the material system
|
||||||
// to the viewer
|
// to the viewer
|
||||||
CHUNK_BIT_MAP = 0x1100,
|
CHUNK_BIT_MAP = 0x1100,
|
||||||
CHUNK_BIT_MAP_EXISTS = 0x1101,
|
CHUNK_BIT_MAP_EXISTS = 0x1101,
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Viewport related stuff. Ignored
|
// Viewport related stuff. Ignored
|
||||||
|
@ -177,171 +173,222 @@ public:
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
// Mesh chunks
|
// Mesh chunks
|
||||||
CHUNK_OBJBLOCK = 0x4000,
|
CHUNK_OBJBLOCK = 0x4000,
|
||||||
CHUNK_TRIMESH = 0x4100,
|
CHUNK_TRIMESH = 0x4100,
|
||||||
CHUNK_VERTLIST = 0x4110,
|
CHUNK_VERTLIST = 0x4110,
|
||||||
CHUNK_VERTFLAGS = 0x4111,
|
CHUNK_VERTFLAGS = 0x4111,
|
||||||
CHUNK_FACELIST = 0x4120,
|
CHUNK_FACELIST = 0x4120,
|
||||||
CHUNK_FACEMAT = 0x4130,
|
CHUNK_FACEMAT = 0x4130,
|
||||||
CHUNK_MAPLIST = 0x4140,
|
CHUNK_MAPLIST = 0x4140,
|
||||||
CHUNK_SMOOLIST = 0x4150,
|
CHUNK_SMOOLIST = 0x4150,
|
||||||
CHUNK_TRMATRIX = 0x4160,
|
CHUNK_TRMATRIX = 0x4160,
|
||||||
CHUNK_MESHCOLOR = 0x4165,
|
CHUNK_MESHCOLOR = 0x4165,
|
||||||
CHUNK_TXTINFO = 0x4170,
|
CHUNK_TXTINFO = 0x4170,
|
||||||
CHUNK_LIGHT = 0x4600,
|
CHUNK_LIGHT = 0x4600,
|
||||||
CHUNK_CAMERA = 0x4700,
|
CHUNK_CAMERA = 0x4700,
|
||||||
CHUNK_HIERARCHY = 0x4F00,
|
CHUNK_HIERARCHY = 0x4F00,
|
||||||
|
|
||||||
// Specifies the global scaling factor. This is applied
|
// Specifies the global scaling factor. This is applied
|
||||||
// to the root node's transformation matrix
|
// to the root node's transformation matrix
|
||||||
CHUNK_MASTER_SCALE = 0x0100,
|
CHUNK_MASTER_SCALE = 0x0100,
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Material chunks
|
// Material chunks
|
||||||
CHUNK_MAT_MATERIAL = 0xAFFF,
|
CHUNK_MAT_MATERIAL = 0xAFFF,
|
||||||
|
|
||||||
// asciiz containing the name of the material
|
// asciiz containing the name of the material
|
||||||
CHUNK_MAT_MATNAME = 0xA000,
|
CHUNK_MAT_MATNAME = 0xA000,
|
||||||
CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk
|
CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk
|
||||||
CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk
|
CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk
|
||||||
CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk
|
CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk
|
||||||
|
|
||||||
// Specifies the shininess of the material
|
// Specifies the shininess of the material
|
||||||
// followed by percentage chunk
|
// followed by percentage chunk
|
||||||
CHUNK_MAT_SHININESS = 0xA040,
|
CHUNK_MAT_SHININESS = 0xA040,
|
||||||
CHUNK_MAT_SHININESS_PERCENT = 0xA041 ,
|
CHUNK_MAT_SHININESS_PERCENT = 0xA041,
|
||||||
|
|
||||||
// Specifies the shading mode to be used
|
// Specifies the shading mode to be used
|
||||||
// followed by a short
|
// followed by a short
|
||||||
CHUNK_MAT_SHADING = 0xA100,
|
CHUNK_MAT_SHADING = 0xA100,
|
||||||
|
|
||||||
// NOTE: Emissive color (self illumination) seems not
|
// NOTE: Emissive color (self illumination) seems not
|
||||||
// to be a color but a single value, type is unknown.
|
// to be a color but a single value, type is unknown.
|
||||||
// Make the parser accept both of them.
|
// Make the parser accept both of them.
|
||||||
// followed by percentage chunk (?)
|
// followed by percentage chunk (?)
|
||||||
CHUNK_MAT_SELF_ILLUM = 0xA080,
|
CHUNK_MAT_SELF_ILLUM = 0xA080,
|
||||||
|
|
||||||
// Always followed by percentage chunk (?)
|
// Always followed by percentage chunk (?)
|
||||||
CHUNK_MAT_SELF_ILPCT = 0xA084,
|
CHUNK_MAT_SELF_ILPCT = 0xA084,
|
||||||
|
|
||||||
// Always followed by percentage chunk
|
// Always followed by percentage chunk
|
||||||
CHUNK_MAT_TRANSPARENCY = 0xA050,
|
CHUNK_MAT_TRANSPARENCY = 0xA050,
|
||||||
|
|
||||||
// Diffuse texture channel 0
|
// Diffuse texture channel 0
|
||||||
CHUNK_MAT_TEXTURE = 0xA200,
|
CHUNK_MAT_TEXTURE = 0xA200,
|
||||||
|
|
||||||
// Contains opacity information for each texel
|
// Contains opacity information for each texel
|
||||||
CHUNK_MAT_OPACMAP = 0xA210,
|
CHUNK_MAT_OPACMAP = 0xA210,
|
||||||
|
|
||||||
// Contains a reflection map to be used to reflect
|
// Contains a reflection map to be used to reflect
|
||||||
// the environment. This is partially supported.
|
// the environment. This is partially supported.
|
||||||
CHUNK_MAT_REFLMAP = 0xA220,
|
CHUNK_MAT_REFLMAP = 0xA220,
|
||||||
|
|
||||||
// Self Illumination map (emissive colors)
|
// Self Illumination map (emissive colors)
|
||||||
CHUNK_MAT_SELFIMAP = 0xA33d,
|
CHUNK_MAT_SELFIMAP = 0xA33d,
|
||||||
|
|
||||||
// Bumpmap. Not specified whether it is a heightmap
|
// Bumpmap. Not specified whether it is a heightmap
|
||||||
// or a normal map. Assme it is a heightmap since
|
// or a normal map. Assme it is a heightmap since
|
||||||
// artist normally prefer this format.
|
// artist normally prefer this format.
|
||||||
CHUNK_MAT_BUMPMAP = 0xA230,
|
CHUNK_MAT_BUMPMAP = 0xA230,
|
||||||
|
|
||||||
// Specular map. Seems to influence the specular color
|
// Specular map. Seems to influence the specular color
|
||||||
CHUNK_MAT_SPECMAP = 0xA204,
|
CHUNK_MAT_SPECMAP = 0xA204,
|
||||||
|
|
||||||
// Holds shininess data.
|
// Holds shininess data.
|
||||||
CHUNK_MAT_MAT_SHINMAP = 0xA33C,
|
CHUNK_MAT_MAT_SHINMAP = 0xA33C,
|
||||||
|
|
||||||
// Scaling in U/V direction.
|
// Scaling in U/V direction.
|
||||||
// (need to gen separate UV coordinate set
|
// (need to gen separate UV coordinate set
|
||||||
// and do this by hand)
|
// and do this by hand)
|
||||||
CHUNK_MAT_MAP_USCALE = 0xA354,
|
CHUNK_MAT_MAP_USCALE = 0xA354,
|
||||||
CHUNK_MAT_MAP_VSCALE = 0xA356,
|
CHUNK_MAT_MAP_VSCALE = 0xA356,
|
||||||
|
|
||||||
// Translation in U/V direction.
|
// Translation in U/V direction.
|
||||||
// (need to gen separate UV coordinate set
|
// (need to gen separate UV coordinate set
|
||||||
// and do this by hand)
|
// and do this by hand)
|
||||||
CHUNK_MAT_MAP_UOFFSET = 0xA358,
|
CHUNK_MAT_MAP_UOFFSET = 0xA358,
|
||||||
CHUNK_MAT_MAP_VOFFSET = 0xA35a,
|
CHUNK_MAT_MAP_VOFFSET = 0xA35a,
|
||||||
|
|
||||||
// UV-coordinates rotation around the z-axis
|
// UV-coordinates rotation around the z-axis
|
||||||
// Assumed to be in radians.
|
// Assumed to be in radians.
|
||||||
CHUNK_MAT_MAP_ANG = 0xA35C,
|
CHUNK_MAT_MAP_ANG = 0xA35C,
|
||||||
|
|
||||||
// Tiling flags for 3DS files
|
// Tiling flags for 3DS files
|
||||||
CHUNK_MAT_MAP_TILING = 0xa351,
|
CHUNK_MAT_MAP_TILING = 0xa351,
|
||||||
|
|
||||||
// Specifies the file name of a texture
|
// Specifies the file name of a texture
|
||||||
CHUNK_MAPFILE = 0xA300,
|
CHUNK_MAPFILE = 0xA300,
|
||||||
|
|
||||||
// Specifies whether a materail requires two-sided rendering
|
// Specifies whether a materail requires two-sided rendering
|
||||||
CHUNK_MAT_TWO_SIDE = 0xA081,
|
CHUNK_MAT_TWO_SIDE = 0xA081,
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
// Main keyframer chunk. Contains translation/rotation/scaling data
|
// Main keyframer chunk. Contains translation/rotation/scaling data
|
||||||
CHUNK_KEYFRAMER = 0xB000,
|
CHUNK_KEYFRAMER = 0xB000,
|
||||||
|
|
||||||
// Supported sub chunks
|
// Supported sub chunks
|
||||||
CHUNK_TRACKINFO = 0xB002,
|
CHUNK_TRACKINFO = 0xB002,
|
||||||
CHUNK_TRACKOBJNAME = 0xB010,
|
CHUNK_TRACKOBJNAME = 0xB010,
|
||||||
CHUNK_TRACKDUMMYOBJNAME = 0xB011,
|
CHUNK_TRACKDUMMYOBJNAME = 0xB011,
|
||||||
CHUNK_TRACKPIVOT = 0xB013,
|
CHUNK_TRACKPIVOT = 0xB013,
|
||||||
CHUNK_TRACKPOS = 0xB020,
|
CHUNK_TRACKPOS = 0xB020,
|
||||||
CHUNK_TRACKROTATE = 0xB021,
|
CHUNK_TRACKROTATE = 0xB021,
|
||||||
CHUNK_TRACKSCALE = 0xB022,
|
CHUNK_TRACKSCALE = 0xB022,
|
||||||
|
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
// Keyframes for various other stuff in the file
|
// Keyframes for various other stuff in the file
|
||||||
// Partially ignored
|
// Partially ignored
|
||||||
CHUNK_AMBIENTKEY = 0xB001,
|
CHUNK_AMBIENTKEY = 0xB001,
|
||||||
CHUNK_TRACKMORPH = 0xB026,
|
CHUNK_TRACKMORPH = 0xB026,
|
||||||
CHUNK_TRACKHIDE = 0xB029,
|
CHUNK_TRACKHIDE = 0xB029,
|
||||||
CHUNK_OBJNUMBER = 0xB030,
|
CHUNK_OBJNUMBER = 0xB030,
|
||||||
CHUNK_TRACKCAMERA = 0xB003,
|
CHUNK_TRACKCAMERA = 0xB003,
|
||||||
CHUNK_TRACKFOV = 0xB023,
|
CHUNK_TRACKFOV = 0xB023,
|
||||||
CHUNK_TRACKROLL = 0xB024,
|
CHUNK_TRACKROLL = 0xB024,
|
||||||
CHUNK_TRACKCAMTGT = 0xB004,
|
CHUNK_TRACKCAMTGT = 0xB004,
|
||||||
CHUNK_TRACKLIGHT = 0xB005,
|
CHUNK_TRACKLIGHT = 0xB005,
|
||||||
CHUNK_TRACKLIGTGT = 0xB006,
|
CHUNK_TRACKLIGTGT = 0xB006,
|
||||||
CHUNK_TRACKSPOTL = 0xB007,
|
CHUNK_TRACKSPOTL = 0xB007,
|
||||||
CHUNK_FRAMES = 0xB008,
|
CHUNK_FRAMES = 0xB008,
|
||||||
// ********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
// light sub-chunks
|
// light sub-chunks
|
||||||
CHUNK_DL_OFF = 0x4620,
|
CHUNK_DL_OFF = 0x4620,
|
||||||
CHUNK_DL_OUTER_RANGE = 0x465A,
|
CHUNK_DL_OUTER_RANGE = 0x465A,
|
||||||
CHUNK_DL_INNER_RANGE = 0x4659,
|
CHUNK_DL_INNER_RANGE = 0x4659,
|
||||||
CHUNK_DL_MULTIPLIER = 0x465B,
|
CHUNK_DL_MULTIPLIER = 0x465B,
|
||||||
CHUNK_DL_EXCLUDE = 0x4654,
|
CHUNK_DL_EXCLUDE = 0x4654,
|
||||||
CHUNK_DL_ATTENUATE = 0x4625,
|
CHUNK_DL_ATTENUATE = 0x4625,
|
||||||
CHUNK_DL_SPOTLIGHT = 0x4610,
|
CHUNK_DL_SPOTLIGHT = 0x4610,
|
||||||
|
|
||||||
// camera sub-chunks
|
// camera sub-chunks
|
||||||
CHUNK_CAM_RANGES = 0x4720
|
CHUNK_CAM_RANGES = 0x4720
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure representing a 3ds mesh face */
|
/** Helper structure representing a 3ds mesh face */
|
||||||
struct Face : public FaceWithSmoothingGroup
|
struct Face : public FaceWithSmoothingGroup {
|
||||||
{
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(disable : 4315)
|
||||||
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure representing a texture */
|
/** Helper structure representing a texture */
|
||||||
struct Texture {
|
struct Texture {
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
Texture() AI_NO_EXCEPT
|
Texture() AI_NO_EXCEPT
|
||||||
: mOffsetU (0.0)
|
: mTextureBlend(0.0f),
|
||||||
, mOffsetV (0.0)
|
mMapName(),
|
||||||
, mScaleU (1.0)
|
mOffsetU(0.0),
|
||||||
, mScaleV (1.0)
|
mOffsetV(0.0),
|
||||||
, mRotation (0.0)
|
mScaleU(1.0),
|
||||||
, mMapMode (aiTextureMapMode_Wrap)
|
mScaleV(1.0),
|
||||||
, bPrivate()
|
mRotation(0.0),
|
||||||
, iUVSrc (0) {
|
mMapMode(aiTextureMapMode_Wrap),
|
||||||
|
bPrivate(),
|
||||||
|
iUVSrc(0) {
|
||||||
mTextureBlend = get_qnan();
|
mTextureBlend = get_qnan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture(const Texture &other) :
|
||||||
|
mTextureBlend(other.mTextureBlend),
|
||||||
|
mMapName(other.mMapName),
|
||||||
|
mOffsetU(other.mOffsetU),
|
||||||
|
mOffsetV(other.mOffsetV),
|
||||||
|
mScaleU(other.mScaleU),
|
||||||
|
mScaleV(other.mScaleV),
|
||||||
|
mRotation(other.mRotation),
|
||||||
|
mMapMode(other.mMapMode),
|
||||||
|
bPrivate(other.bPrivate),
|
||||||
|
iUVSrc(other.iUVSrc) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)),
|
||||||
|
mMapName(std::move(other.mMapName)),
|
||||||
|
mOffsetU(std::move(other.mOffsetU)),
|
||||||
|
mOffsetV(std::move(other.mOffsetV)),
|
||||||
|
mScaleU(std::move(other.mScaleU)),
|
||||||
|
mScaleV(std::move(other.mScaleV)),
|
||||||
|
mRotation(std::move(other.mRotation)),
|
||||||
|
mMapMode(std::move(other.mMapMode)),
|
||||||
|
bPrivate(std::move(other.bPrivate)),
|
||||||
|
iUVSrc(std::move(other.iUVSrc)) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture &operator=(Texture &&other) AI_NO_EXCEPT {
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTextureBlend = std::move(other.mTextureBlend);
|
||||||
|
mMapName = std::move(other.mMapName);
|
||||||
|
mOffsetU = std::move(other.mOffsetU);
|
||||||
|
mOffsetV = std::move(other.mOffsetV);
|
||||||
|
mScaleU = std::move(other.mScaleU);
|
||||||
|
mScaleV = std::move(other.mScaleV);
|
||||||
|
mRotation = std::move(other.mRotation);
|
||||||
|
mMapMode = std::move(other.mMapMode);
|
||||||
|
bPrivate = std::move(other.bPrivate);
|
||||||
|
iUVSrc = std::move(other.iUVSrc);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! Specifies the blend factor for the texture
|
//! Specifies the blend factor for the texture
|
||||||
ai_real mTextureBlend;
|
ai_real mTextureBlend;
|
||||||
|
|
||||||
|
@ -367,55 +414,81 @@ struct Texture {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure representing a 3ds material */
|
/** Helper structure representing a 3ds material */
|
||||||
struct Material
|
struct Material {
|
||||||
{
|
|
||||||
//! Default constructor has been deleted
|
//! Default constructor has been deleted
|
||||||
Material() = delete;
|
Material() :
|
||||||
|
mName(),
|
||||||
|
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||||
|
mSpecularExponent(ai_real(0.0)),
|
||||||
|
mShininessStrength(ai_real(1.0)),
|
||||||
|
mShading(Discreet3DS::Gouraud),
|
||||||
|
mTransparency(ai_real(1.0)),
|
||||||
|
mBumpHeight(ai_real(1.0)),
|
||||||
|
mTwoSided(false) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
//! Constructor with explicit name
|
//! Constructor with explicit name
|
||||||
explicit Material(const std::string &name)
|
explicit Material(const std::string &name) :
|
||||||
: mName(name)
|
mName(name),
|
||||||
, mDiffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black
|
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||||
, mSpecularExponent ( ai_real( 0.0 ) )
|
mSpecularExponent(ai_real(0.0)),
|
||||||
, mShininessStrength ( ai_real( 1.0 ) )
|
mShininessStrength(ai_real(1.0)),
|
||||||
, mShading(Discreet3DS::Gouraud)
|
mShading(Discreet3DS::Gouraud),
|
||||||
, mTransparency ( ai_real( 1.0 ) )
|
mTransparency(ai_real(1.0)),
|
||||||
, mBumpHeight ( ai_real( 1.0 ) )
|
mBumpHeight(ai_real(1.0)),
|
||||||
, mTwoSided (false)
|
mTwoSided(false) {
|
||||||
{
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material(const Material &other) :
|
||||||
|
mName(other.mName),
|
||||||
|
mDiffuse(other.mDiffuse),
|
||||||
|
mSpecularExponent(other.mSpecularExponent),
|
||||||
|
mShininessStrength(other.mShininessStrength),
|
||||||
|
mSpecular(other.mSpecular),
|
||||||
|
mAmbient(other.mAmbient),
|
||||||
|
mShading(other.mShading),
|
||||||
|
mTransparency(other.mTransparency),
|
||||||
|
sTexDiffuse(other.sTexDiffuse),
|
||||||
|
sTexOpacity(other.sTexOpacity),
|
||||||
|
sTexSpecular(other.sTexSpecular),
|
||||||
|
sTexReflective(other.sTexReflective),
|
||||||
|
sTexBump(other.sTexBump),
|
||||||
|
sTexEmissive(other.sTexEmissive),
|
||||||
|
sTexShininess(other.sTexShininess),
|
||||||
|
mBumpHeight(other.mBumpHeight),
|
||||||
|
mEmissive(other.mEmissive),
|
||||||
|
sTexAmbient(other.sTexAmbient),
|
||||||
|
mTwoSided(other.mTwoSided) {
|
||||||
|
// empty
|
||||||
|
|
||||||
Material(const Material &other) = default;
|
}
|
||||||
Material &operator=(const Material &other) = default;
|
|
||||||
|
|
||||||
|
|
||||||
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
||||||
Material(Material &&other) AI_NO_EXCEPT
|
Material(Material &&other) AI_NO_EXCEPT :
|
||||||
: mName(std::move(other.mName))
|
mName(std::move(other.mName)),
|
||||||
, mDiffuse(std::move(other.mDiffuse))
|
mDiffuse(std::move(other.mDiffuse)),
|
||||||
, mSpecularExponent(std::move(other.mSpecularExponent))
|
mSpecularExponent(std::move(other.mSpecularExponent)),
|
||||||
, mShininessStrength(std::move(other.mShininessStrength))
|
mShininessStrength(std::move(other.mShininessStrength)),
|
||||||
, mSpecular(std::move(other.mSpecular))
|
mSpecular(std::move(other.mSpecular)),
|
||||||
, mAmbient(std::move(other.mAmbient))
|
mAmbient(std::move(other.mAmbient)),
|
||||||
, mShading(std::move(other.mShading))
|
mShading(std::move(other.mShading)),
|
||||||
, mTransparency(std::move(other.mTransparency))
|
mTransparency(std::move(other.mTransparency)),
|
||||||
, sTexDiffuse(std::move(other.sTexDiffuse))
|
sTexDiffuse(std::move(other.sTexDiffuse)),
|
||||||
, sTexOpacity(std::move(other.sTexOpacity))
|
sTexOpacity(std::move(other.sTexOpacity)),
|
||||||
, sTexSpecular(std::move(other.sTexSpecular))
|
sTexSpecular(std::move(other.sTexSpecular)),
|
||||||
, sTexReflective(std::move(other.sTexReflective))
|
sTexReflective(std::move(other.sTexReflective)),
|
||||||
, sTexBump(std::move(other.sTexBump))
|
sTexBump(std::move(other.sTexBump)),
|
||||||
, sTexEmissive(std::move(other.sTexEmissive))
|
sTexEmissive(std::move(other.sTexEmissive)),
|
||||||
, sTexShininess(std::move(other.sTexShininess))
|
sTexShininess(std::move(other.sTexShininess)),
|
||||||
, mBumpHeight(std::move(other.mBumpHeight))
|
mBumpHeight(std::move(other.mBumpHeight)),
|
||||||
, mEmissive(std::move(other.mEmissive))
|
mEmissive(std::move(other.mEmissive)),
|
||||||
, sTexAmbient(std::move(other.sTexAmbient))
|
sTexAmbient(std::move(other.sTexAmbient)),
|
||||||
, mTwoSided(std::move(other.mTwoSided))
|
mTwoSided(std::move(other.mTwoSided)) {
|
||||||
{
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Material &operator=(Material &&other) AI_NO_EXCEPT {
|
Material &operator=(Material &&other) AI_NO_EXCEPT {
|
||||||
if (this == &other) {
|
if (this == &other) {
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -444,9 +517,9 @@ struct Material
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~Material() {
|
||||||
virtual ~Material() {}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
//! Name of the material
|
//! Name of the material
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
@ -491,18 +564,15 @@ struct Material
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure to represent a 3ds file mesh */
|
/** Helper structure to represent a 3ds file mesh */
|
||||||
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face> {
|
||||||
{
|
|
||||||
//! Default constructor has been deleted
|
//! Default constructor has been deleted
|
||||||
Mesh() = delete;
|
Mesh() = delete;
|
||||||
|
|
||||||
//! Constructor with explicit name
|
//! Constructor with explicit name
|
||||||
explicit Mesh(const std::string &name)
|
explicit Mesh(const std::string &name) :
|
||||||
: mName(name)
|
mName(name) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Name of the mesh
|
//! Name of the mesh
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
|
@ -519,62 +589,48 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the
|
/** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the
|
||||||
C-API, so it would be difficult to make them a template. */
|
C-API, so it would be difficult to make them a template. */
|
||||||
struct aiFloatKey
|
struct aiFloatKey {
|
||||||
{
|
double mTime; ///< The time of this key
|
||||||
double mTime; ///< The time of this key
|
ai_real mValue; ///< The value of this key
|
||||||
ai_real mValue; ///< The value of this key
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
// time is not compared
|
// time is not compared
|
||||||
bool operator == (const aiFloatKey& o) const
|
bool operator==(const aiFloatKey &o) const { return o.mValue == this->mValue; }
|
||||||
{return o.mValue == this->mValue;}
|
|
||||||
|
|
||||||
bool operator != (const aiFloatKey& o) const
|
bool operator!=(const aiFloatKey &o) const { return o.mValue != this->mValue; }
|
||||||
{return o.mValue != this->mValue;}
|
|
||||||
|
|
||||||
// Only time is compared. This operator is defined
|
// Only time is compared. This operator is defined
|
||||||
// for use with std::sort
|
// for use with std::sort
|
||||||
bool operator < (const aiFloatKey& o) const
|
bool operator<(const aiFloatKey &o) const { return mTime < o.mTime; }
|
||||||
{return mTime < o.mTime;}
|
|
||||||
|
|
||||||
bool operator > (const aiFloatKey& o) const
|
bool operator>(const aiFloatKey &o) const { return mTime > o.mTime; }
|
||||||
{return mTime > o.mTime;}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure to represent a 3ds file node */
|
/** Helper structure to represent a 3ds file node */
|
||||||
struct Node
|
struct Node {
|
||||||
{
|
|
||||||
Node() = delete;
|
Node() = delete;
|
||||||
|
|
||||||
explicit Node(const std::string &name)
|
explicit Node(const std::string &name) :
|
||||||
: mParent(NULL)
|
mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) {
|
||||||
, mName(name)
|
aRotationKeys.reserve(20);
|
||||||
, mInstanceNumber(0)
|
aPositionKeys.reserve(20);
|
||||||
, mHierarchyPos (0)
|
aScalingKeys.reserve(20);
|
||||||
, mHierarchyIndex (0)
|
|
||||||
, mInstanceCount (1)
|
|
||||||
{
|
|
||||||
aRotationKeys.reserve (20);
|
|
||||||
aPositionKeys.reserve (20);
|
|
||||||
aScalingKeys.reserve (20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Node() {
|
||||||
~Node()
|
for (unsigned int i = 0; i < mChildren.size(); ++i)
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < mChildren.size();++i)
|
|
||||||
delete mChildren[i];
|
delete mChildren[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Pointer to the parent node
|
//! Pointer to the parent node
|
||||||
Node* mParent;
|
Node *mParent;
|
||||||
|
|
||||||
//! Holds all child nodes
|
//! Holds all child nodes
|
||||||
std::vector<Node*> mChildren;
|
std::vector<Node *> mChildren;
|
||||||
|
|
||||||
//! Name of the node
|
//! Name of the node
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
@ -600,13 +656,12 @@ struct Node
|
||||||
//! Scaling keys loaded from the file
|
//! Scaling keys loaded from the file
|
||||||
std::vector<aiVectorKey> aScalingKeys;
|
std::vector<aiVectorKey> aScalingKeys;
|
||||||
|
|
||||||
|
|
||||||
// For target lights (spot lights and directional lights):
|
// For target lights (spot lights and directional lights):
|
||||||
// The position of the target
|
// The position of the target
|
||||||
std::vector< aiVectorKey > aTargetPositionKeys;
|
std::vector<aiVectorKey> aTargetPositionKeys;
|
||||||
|
|
||||||
// For cameras: the camera roll angle
|
// For cameras: the camera roll angle
|
||||||
std::vector< aiFloatKey > aCameraRollKeys;
|
std::vector<aiFloatKey> aCameraRollKeys;
|
||||||
|
|
||||||
//! Pivot position loaded from the file
|
//! Pivot position loaded from the file
|
||||||
aiVector3D vPivot;
|
aiVector3D vPivot;
|
||||||
|
@ -616,8 +671,7 @@ struct Node
|
||||||
|
|
||||||
//! Add a child node, setup the right parent node for it
|
//! Add a child node, setup the right parent node for it
|
||||||
//! \param pc Node to be 'adopted'
|
//! \param pc Node to be 'adopted'
|
||||||
inline Node& push_back(Node* pc)
|
inline Node &push_back(Node *pc) {
|
||||||
{
|
|
||||||
mChildren.push_back(pc);
|
mChildren.push_back(pc);
|
||||||
pc->mParent = this;
|
pc->mParent = this;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -625,8 +679,7 @@ struct Node
|
||||||
};
|
};
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure analogue to aiScene */
|
/** Helper structure analogue to aiScene */
|
||||||
struct Scene
|
struct Scene {
|
||||||
{
|
|
||||||
//! List of all materials loaded
|
//! List of all materials loaded
|
||||||
//! NOTE: 3ds references materials globally
|
//! NOTE: 3ds references materials globally
|
||||||
std::vector<Material> mMaterials;
|
std::vector<Material> mMaterials;
|
||||||
|
@ -635,17 +688,16 @@ struct Scene
|
||||||
std::vector<Mesh> mMeshes;
|
std::vector<Mesh> mMeshes;
|
||||||
|
|
||||||
//! List of all cameras loaded
|
//! List of all cameras loaded
|
||||||
std::vector<aiCamera*> mCameras;
|
std::vector<aiCamera *> mCameras;
|
||||||
|
|
||||||
//! List of all lights loaded
|
//! List of all lights loaded
|
||||||
std::vector<aiLight*> mLights;
|
std::vector<aiLight *> mLights;
|
||||||
|
|
||||||
//! Pointer to the root node of the scene
|
//! Pointer to the root node of the scene
|
||||||
// --- moved to main class
|
// --- moved to main class
|
||||||
// Node* pcRootNode;
|
// Node* pcRootNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace D3DS
|
} // end of namespace D3DS
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -65,15 +65,11 @@ using namespace D3DS;
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
/** Importer class for 3D Studio r3 and r4 3DS files
|
/** Importer class for 3D Studio r3 and r4 3DS files
|
||||||
*/
|
*/
|
||||||
class Discreet3DSImporter : public BaseImporter
|
class Discreet3DSImporter : public BaseImporter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Discreet3DSImporter();
|
Discreet3DSImporter();
|
||||||
~Discreet3DSImporter();
|
~Discreet3DSImporter();
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
* See BaseImporter::CanRead() for details.
|
|
@ -44,81 +44,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "D3MFExporter.h"
|
#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/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 "3MFXmlTags.h"
|
||||||
#include "D3MFOpcPackage.h"
|
#include "D3MFOpcPackage.h"
|
||||||
|
|
||||||
#ifdef ASSIMP_USE_HUNTER
|
#ifdef ASSIMP_USE_HUNTER
|
||||||
# include <zip/zip.h>
|
#include <zip/zip.h>
|
||||||
#else
|
#else
|
||||||
# include <contrib/zip/src/zip.h>
|
#include <contrib/zip/src/zip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) {
|
void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
|
||||||
if ( nullptr == pIOSystem ) {
|
if (nullptr == pIOSystem) {
|
||||||
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
|
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
|
||||||
}
|
}
|
||||||
D3MF::D3MFExporter myExporter( pFile, pScene );
|
D3MF::D3MFExporter myExporter(pFile, pScene);
|
||||||
if ( myExporter.validate() ) {
|
if (myExporter.validate()) {
|
||||||
if ( pIOSystem->Exists( pFile ) ) {
|
if (pIOSystem->Exists(pFile)) {
|
||||||
if ( !pIOSystem->DeleteFile( pFile ) ) {
|
if (!pIOSystem->DeleteFile(pFile)) {
|
||||||
throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) );
|
throw DeadlyExportError("File exists, cannot override : " + std::string(pFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool ok = myExporter.exportArchive(pFile);
|
bool ok = myExporter.exportArchive(pFile);
|
||||||
if ( !ok ) {
|
if (!ok) {
|
||||||
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
|
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace D3MF {
|
namespace D3MF {
|
||||||
|
|
||||||
D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
|
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
|
||||||
: mArchiveName( pFile )
|
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
|
||||||
, m_zipArchive( nullptr )
|
|
||||||
, mScene( pScene )
|
|
||||||
, mModelOutput()
|
|
||||||
, mRelOutput()
|
|
||||||
, mContentOutput()
|
|
||||||
, mBuildItems()
|
|
||||||
, mRelations() {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
D3MFExporter::~D3MFExporter() {
|
D3MFExporter::~D3MFExporter() {
|
||||||
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
for (size_t i = 0; i < mRelations.size(); ++i) {
|
||||||
delete mRelations[ i ];
|
delete mRelations[i];
|
||||||
}
|
}
|
||||||
mRelations.clear();
|
mRelations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3MFExporter::validate() {
|
bool D3MFExporter::validate() {
|
||||||
if ( mArchiveName.empty() ) {
|
if (mArchiveName.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nullptr == mScene ) {
|
if (nullptr == mScene) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3MFExporter::exportArchive( const char *file ) {
|
bool D3MFExporter::exportArchive(const char *file) {
|
||||||
bool ok( true );
|
bool ok(true);
|
||||||
|
|
||||||
m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' );
|
m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
if ( nullptr == m_zipArchive ) {
|
if (nullptr == m_zipArchive) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +119,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
|
||||||
ok |= export3DModel();
|
ok |= export3DModel();
|
||||||
ok |= exportRelations();
|
ok |= exportRelations();
|
||||||
|
|
||||||
zip_close( m_zipArchive );
|
zip_close(m_zipArchive);
|
||||||
m_zipArchive = nullptr;
|
m_zipArchive = nullptr;
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -145,7 +138,7 @@ bool D3MFExporter::exportContentTypes() {
|
||||||
mContentOutput << std::endl;
|
mContentOutput << std::endl;
|
||||||
mContentOutput << "</Types>";
|
mContentOutput << "</Types>";
|
||||||
mContentOutput << std::endl;
|
mContentOutput << std::endl;
|
||||||
exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
|
exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -157,20 +150,20 @@ bool D3MFExporter::exportRelations() {
|
||||||
mRelOutput << std::endl;
|
mRelOutput << std::endl;
|
||||||
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
||||||
|
|
||||||
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
for (size_t i = 0; i < mRelations.size(); ++i) {
|
||||||
if ( mRelations[ i ]->target[ 0 ] == '/' ) {
|
if (mRelations[i]->target[0] == '/') {
|
||||||
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
|
mRelOutput << "<Relationship Target=\"" << mRelations[i]->target << "\" ";
|
||||||
} else {
|
} else {
|
||||||
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
|
mRelOutput << "<Relationship Target=\"/" << mRelations[i]->target << "\" ";
|
||||||
}
|
}
|
||||||
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
|
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
|
||||||
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
|
mRelOutput << "Type=\"" << mRelations[i]->type << "\" />";
|
||||||
mRelOutput << std::endl;
|
mRelOutput << std::endl;
|
||||||
}
|
}
|
||||||
mRelOutput << "</Relationships>";
|
mRelOutput << "</Relationships>";
|
||||||
mRelOutput << std::endl;
|
mRelOutput << std::endl;
|
||||||
|
|
||||||
writeRelInfoToFile( "_rels", ".rels" );
|
writeRelInfoToFile("_rels", ".rels");
|
||||||
mRelOutput.flush();
|
mRelOutput.flush();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -181,8 +174,8 @@ bool D3MFExporter::export3DModel() {
|
||||||
|
|
||||||
writeHeader();
|
writeHeader();
|
||||||
mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\""
|
mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\""
|
||||||
<< "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
|
<< " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
mModelOutput << "<" << XmlTag::resources << ">";
|
mModelOutput << "<" << XmlTag::resources << ">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
|
|
||||||
|
@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
|
||||||
|
|
||||||
writeObjects();
|
writeObjects();
|
||||||
|
|
||||||
|
|
||||||
mModelOutput << "</" << XmlTag::resources << ">";
|
mModelOutput << "</" << XmlTag::resources << ">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
writeBuild();
|
writeBuild();
|
||||||
|
@ -203,36 +195,36 @@ bool D3MFExporter::export3DModel() {
|
||||||
info->id = "rel0";
|
info->id = "rel0";
|
||||||
info->target = "/3D/3DModel.model";
|
info->target = "/3D/3DModel.model";
|
||||||
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
|
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
|
||||||
mRelations.push_back( info );
|
mRelations.push_back(info);
|
||||||
|
|
||||||
writeModelToArchive( "3D", "3DModel.model" );
|
writeModelToArchive("3D", "3DModel.model");
|
||||||
mModelOutput.flush();
|
mModelOutput.flush();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeHeader() {
|
void D3MFExporter::writeHeader() {
|
||||||
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
|
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeMetaData() {
|
void D3MFExporter::writeMetaData() {
|
||||||
if ( nullptr == mScene->mMetaData ) {
|
if (nullptr == mScene->mMetaData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
|
const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties);
|
||||||
if ( 0 == numMetaEntries ) {
|
if (0 == numMetaEntries) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiString *key = nullptr;
|
const aiString *key = nullptr;
|
||||||
const aiMetadataEntry *entry(nullptr);
|
const aiMetadataEntry *entry(nullptr);
|
||||||
for ( size_t i = 0; i < numMetaEntries; ++i ) {
|
for (size_t i = 0; i < numMetaEntries; ++i) {
|
||||||
mScene->mMetaData->Get( i, key, entry );
|
mScene->mMetaData->Get(i, key, entry);
|
||||||
std::string k( key->C_Str() );
|
std::string k(key->C_Str());
|
||||||
aiString value;
|
aiString value;
|
||||||
mScene->mMetaData->Get( k, value );
|
mScene->mMetaData->Get(k, value);
|
||||||
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
|
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
|
||||||
mModelOutput << value.C_Str();
|
mModelOutput << value.C_Str();
|
||||||
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
|
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
|
||||||
|
@ -241,103 +233,114 @@ void D3MFExporter::writeMetaData() {
|
||||||
|
|
||||||
void D3MFExporter::writeBaseMaterials() {
|
void D3MFExporter::writeBaseMaterials() {
|
||||||
mModelOutput << "<basematerials id=\"1\">\n";
|
mModelOutput << "<basematerials id=\"1\">\n";
|
||||||
std::string strName, hexDiffuseColor , tmp;
|
std::string strName, hexDiffuseColor, tmp;
|
||||||
for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
|
for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
|
||||||
aiMaterial *mat = mScene->mMaterials[ i ];
|
aiMaterial *mat = mScene->mMaterials[i];
|
||||||
aiString name;
|
aiString name;
|
||||||
if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
|
if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
|
||||||
strName = "basemat_" + to_string( i );
|
strName = "basemat_" + to_string(i);
|
||||||
} else {
|
} else {
|
||||||
strName = name.C_Str();
|
strName = name.C_Str();
|
||||||
}
|
}
|
||||||
aiColor4D color;
|
aiColor4D color;
|
||||||
if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
|
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
|
||||||
hexDiffuseColor.clear();
|
hexDiffuseColor.clear();
|
||||||
tmp.clear();
|
tmp.clear();
|
||||||
hexDiffuseColor = "#";
|
// rgbs %
|
||||||
|
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
|
||||||
tmp = DecimalToHexa( color.r );
|
|
||||||
hexDiffuseColor += tmp;
|
hexDiffuseColor = Rgba2Hex(
|
||||||
tmp = DecimalToHexa( color.g );
|
(int)((ai_real)color.r) * 255,
|
||||||
hexDiffuseColor += tmp;
|
(int)((ai_real)color.g) * 255,
|
||||||
tmp = DecimalToHexa( color.b );
|
(int)((ai_real)color.b) * 255,
|
||||||
hexDiffuseColor += tmp;
|
(int)((ai_real)color.a) * 255,
|
||||||
tmp = DecimalToHexa( color.a );
|
true);
|
||||||
hexDiffuseColor += tmp;
|
|
||||||
|
} else {
|
||||||
|
hexDiffuseColor = "#";
|
||||||
|
tmp = DecimalToHexa((ai_real)color.r);
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa((ai_real)color.g);
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa((ai_real)color.b);
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa((ai_real)color.a);
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hexDiffuseColor = "#FFFFFFFF";
|
hexDiffuseColor = "#FFFFFFFF";
|
||||||
}
|
}
|
||||||
|
|
||||||
mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
|
mModelOutput << "<base name=\"" + strName + "\" " + " displaycolor=\"" + hexDiffuseColor + "\" />\n";
|
||||||
}
|
}
|
||||||
mModelOutput << "</basematerials>\n";
|
mModelOutput << "</basematerials>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeObjects() {
|
void D3MFExporter::writeObjects() {
|
||||||
if ( nullptr == mScene->mRootNode ) {
|
if (nullptr == mScene->mRootNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aiNode *root = mScene->mRootNode;
|
aiNode *root = mScene->mRootNode;
|
||||||
for ( unsigned int i = 0; i < root->mNumChildren; ++i ) {
|
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||||
aiNode *currentNode( root->mChildren[ i ] );
|
aiNode *currentNode(root->mChildren[i]);
|
||||||
if ( nullptr == currentNode ) {
|
if (nullptr == currentNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
|
mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) {
|
for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
|
||||||
aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ];
|
aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
|
||||||
if ( nullptr == currentMesh ) {
|
if (nullptr == currentMesh) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
writeMesh( currentMesh );
|
writeMesh(currentMesh);
|
||||||
}
|
}
|
||||||
mBuildItems.push_back( i );
|
mBuildItems.push_back(i);
|
||||||
|
|
||||||
mModelOutput << "</" << XmlTag::object << ">";
|
mModelOutput << "</" << XmlTag::object << ">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeMesh( aiMesh *mesh ) {
|
void D3MFExporter::writeMesh(aiMesh *mesh) {
|
||||||
if ( nullptr == mesh ) {
|
if (nullptr == mesh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
|
mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
|
||||||
mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
|
mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
|
||||||
for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) {
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
writeVertex( mesh->mVertices[ i ] );
|
writeVertex(mesh->mVertices[i]);
|
||||||
}
|
}
|
||||||
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
|
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
|
||||||
|
|
||||||
const unsigned int matIdx( mesh->mMaterialIndex );
|
const unsigned int matIdx(mesh->mMaterialIndex);
|
||||||
|
|
||||||
writeFaces( mesh, matIdx );
|
writeFaces(mesh, matIdx);
|
||||||
|
|
||||||
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
|
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeVertex( const aiVector3D &pos ) {
|
void D3MFExporter::writeVertex(const aiVector3D &pos) {
|
||||||
mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
|
mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
|
void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
|
||||||
if ( nullptr == mesh ) {
|
if (nullptr == mesh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !mesh->HasFaces() ) {
|
if (!mesh->HasFaces()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
|
mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
|
||||||
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
|
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||||
aiFace ¤tFace = mesh->mFaces[ i ];
|
aiFace ¤tFace = mesh->mFaces[i];
|
||||||
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
|
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
|
||||||
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
|
<< currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
|
||||||
<< "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
|
<< "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
mModelOutput << "</" << XmlTag::triangles << ">";
|
mModelOutput << "</" << XmlTag::triangles << ">";
|
||||||
|
@ -347,54 +350,53 @@ void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
|
||||||
void D3MFExporter::writeBuild() {
|
void D3MFExporter::writeBuild() {
|
||||||
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
|
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
|
||||||
|
|
||||||
for ( size_t i = 0; i < mBuildItems.size(); ++i ) {
|
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 << std::endl;
|
||||||
}
|
}
|
||||||
mModelOutput << "</" << XmlTag::build << ">";
|
mModelOutput << "</" << XmlTag::build << ">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::exportContentTyp( const std::string &filename ) {
|
void D3MFExporter::exportContentTyp(const std::string &filename) {
|
||||||
if ( nullptr == m_zipArchive ) {
|
if (nullptr == m_zipArchive) {
|
||||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||||
}
|
}
|
||||||
const std::string entry = filename;
|
const std::string entry = filename;
|
||||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
zip_entry_open(m_zipArchive, entry.c_str());
|
||||||
|
|
||||||
const std::string &exportTxt( mContentOutput.str() );
|
const std::string &exportTxt(mContentOutput.str());
|
||||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||||
|
|
||||||
zip_entry_close( m_zipArchive );
|
zip_entry_close(m_zipArchive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeModelToArchive( const std::string &folder, const std::string &modelName ) {
|
void D3MFExporter::writeModelToArchive(const std::string &folder, const std::string &modelName) {
|
||||||
if ( nullptr == m_zipArchive ) {
|
if (nullptr == m_zipArchive) {
|
||||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||||
}
|
}
|
||||||
const std::string entry = folder + "/" + modelName;
|
const std::string entry = folder + "/" + modelName;
|
||||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
zip_entry_open(m_zipArchive, entry.c_str());
|
||||||
|
|
||||||
const std::string &exportTxt( mModelOutput.str() );
|
const std::string &exportTxt(mModelOutput.str());
|
||||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||||
|
|
||||||
zip_entry_close( m_zipArchive );
|
zip_entry_close(m_zipArchive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) {
|
void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) {
|
||||||
if ( nullptr == m_zipArchive ) {
|
if (nullptr == m_zipArchive) {
|
||||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||||
}
|
}
|
||||||
const std::string entry = folder + "/" + relName;
|
const std::string entry = folder + "/" + relName;
|
||||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
zip_entry_open(m_zipArchive, entry.c_str());
|
||||||
|
|
||||||
const std::string &exportTxt( mRelOutput.str() );
|
const std::string &exportTxt(mRelOutput.str());
|
||||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||||
|
|
||||||
zip_entry_close( m_zipArchive );
|
zip_entry_close(m_zipArchive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // Namespace D3MF
|
} // Namespace D3MF
|
||||||
} // Namespace Assimp
|
} // Namespace Assimp
|
||||||
|
|
|
@ -44,24 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "D3MFImporter.h"
|
#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/StringComparison.h>
|
||||||
#include <assimp/StringUtils.h>
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/ZipArchiveIOSystem.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 <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
#include <cassert>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "D3MFOpcPackage.h"
|
|
||||||
#include <assimp/irrXMLWrapper.h>
|
|
||||||
#include "3MFXmlTags.h"
|
#include "3MFXmlTags.h"
|
||||||
|
#include "D3MFOpcPackage.h"
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
|
#include <assimp/irrXMLWrapper.h>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
@ -70,90 +70,90 @@ namespace D3MF {
|
||||||
|
|
||||||
class XmlSerializer {
|
class XmlSerializer {
|
||||||
public:
|
public:
|
||||||
using MatArray = std::vector<aiMaterial*>;
|
using MatArray = std::vector<aiMaterial *>;
|
||||||
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
|
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
|
||||||
|
|
||||||
XmlSerializer(XmlReader* xmlReader)
|
XmlSerializer(XmlReader *xmlReader) :
|
||||||
: mMeshes()
|
mMeshes(),
|
||||||
, mMatArray()
|
mMatArray(),
|
||||||
, mActiveMatGroup( 99999999 )
|
mActiveMatGroup(99999999),
|
||||||
, mMatId2MatArray()
|
mMatId2MatArray(),
|
||||||
, xmlReader(xmlReader){
|
xmlReader(xmlReader) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
~XmlSerializer() {
|
~XmlSerializer() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportXml(aiScene* scene) {
|
void ImportXml(aiScene *scene) {
|
||||||
if ( nullptr == scene ) {
|
if (nullptr == scene) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene->mRootNode = new aiNode();
|
scene->mRootNode = new aiNode();
|
||||||
std::vector<aiNode*> children;
|
std::vector<aiNode *> children;
|
||||||
|
|
||||||
std::string nodeName;
|
std::string nodeName;
|
||||||
while(ReadToEndElement(D3MF::XmlTag::model)) {
|
while (ReadToEndElement(D3MF::XmlTag::model)) {
|
||||||
nodeName = xmlReader->getNodeName();
|
nodeName = xmlReader->getNodeName();
|
||||||
if( nodeName == D3MF::XmlTag::object) {
|
if (nodeName == D3MF::XmlTag::object) {
|
||||||
children.push_back(ReadObject(scene));
|
children.push_back(ReadObject(scene));
|
||||||
} else if( nodeName == D3MF::XmlTag::build) {
|
} else if (nodeName == D3MF::XmlTag::build) {
|
||||||
//
|
//
|
||||||
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
|
} else if (nodeName == D3MF::XmlTag::basematerials) {
|
||||||
ReadBaseMaterials();
|
ReadBaseMaterials();
|
||||||
} else if ( nodeName == D3MF::XmlTag::meta ) {
|
} else if (nodeName == D3MF::XmlTag::meta) {
|
||||||
ReadMetadata();
|
ReadMetadata();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( scene->mRootNode->mName.length == 0 ) {
|
if (scene->mRootNode->mName.length == 0) {
|
||||||
scene->mRootNode->mName.Set( "3MF" );
|
scene->mRootNode->mName.Set("3MF");
|
||||||
}
|
}
|
||||||
|
|
||||||
// import the metadata
|
// import the metadata
|
||||||
if ( !mMetaData.empty() ) {
|
if (!mMetaData.empty()) {
|
||||||
const size_t numMeta( mMetaData.size() );
|
const size_t numMeta(mMetaData.size());
|
||||||
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>( numMeta ) );
|
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
|
||||||
for ( size_t i = 0; i < numMeta; ++i ) {
|
for (size_t i = 0; i < numMeta; ++i) {
|
||||||
aiString val( mMetaData[ i ].value );
|
aiString val(mMetaData[i].value);
|
||||||
scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
|
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// import the meshes
|
// import the meshes
|
||||||
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
|
scene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
|
||||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
|
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
|
||||||
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
|
std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes);
|
||||||
|
|
||||||
// import the materials
|
// import the materials
|
||||||
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
|
scene->mNumMaterials = static_cast<unsigned int>(mMatArray.size());
|
||||||
if ( 0 != scene->mNumMaterials ) {
|
if (0 != scene->mNumMaterials) {
|
||||||
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
|
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
|
||||||
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
|
std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the scenegraph
|
// create the scenegraph
|
||||||
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
||||||
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
|
scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
|
||||||
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aiNode* ReadObject(aiScene* scene) {
|
aiNode *ReadObject(aiScene *scene) {
|
||||||
std::unique_ptr<aiNode> node(new aiNode());
|
std::unique_ptr<aiNode> node(new aiNode());
|
||||||
|
|
||||||
std::vector<unsigned long> meshIds;
|
std::vector<unsigned long> meshIds;
|
||||||
|
|
||||||
const char *attrib( nullptr );
|
const char *attrib(nullptr);
|
||||||
std::string name, type;
|
std::string name, type;
|
||||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
|
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
|
||||||
if ( nullptr != attrib ) {
|
if (nullptr != attrib) {
|
||||||
name = attrib;
|
name = attrib;
|
||||||
}
|
}
|
||||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
|
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
|
||||||
if ( nullptr != attrib ) {
|
if (nullptr != attrib) {
|
||||||
type = attrib;
|
type = attrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +162,8 @@ private:
|
||||||
|
|
||||||
size_t meshIdx = mMeshes.size();
|
size_t meshIdx = mMeshes.size();
|
||||||
|
|
||||||
while(ReadToEndElement(D3MF::XmlTag::object)) {
|
while (ReadToEndElement(D3MF::XmlTag::object)) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
|
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
|
||||||
auto mesh = ReadMesh();
|
auto mesh = ReadMesh();
|
||||||
|
|
||||||
mesh->mName.Set(name);
|
mesh->mName.Set(name);
|
||||||
|
@ -183,11 +183,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
aiMesh *ReadMesh() {
|
aiMesh *ReadMesh() {
|
||||||
aiMesh* mesh = new aiMesh();
|
aiMesh *mesh = new aiMesh();
|
||||||
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
|
while (ReadToEndElement(D3MF::XmlTag::mesh)) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
|
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
|
||||||
ImportVertices(mesh);
|
ImportVertices(mesh);
|
||||||
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
|
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
|
||||||
ImportTriangles(mesh);
|
ImportTriangles(mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,24 +196,24 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadMetadata() {
|
void ReadMetadata() {
|
||||||
const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
|
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
|
||||||
xmlReader->read();
|
xmlReader->read();
|
||||||
const std::string value = xmlReader->getNodeData();
|
const std::string value = xmlReader->getNodeData();
|
||||||
|
|
||||||
if ( name.empty() ) {
|
if (name.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaEntry entry;
|
MetaEntry entry;
|
||||||
entry.name = name;
|
entry.name = name;
|
||||||
entry.value = value;
|
entry.value = value;
|
||||||
mMetaData.push_back( entry );
|
mMetaData.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportVertices(aiMesh* mesh) {
|
void ImportVertices(aiMesh *mesh) {
|
||||||
std::vector<aiVector3D> vertices;
|
std::vector<aiVector3D> vertices;
|
||||||
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
|
while (ReadToEndElement(D3MF::XmlTag::vertices)) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
|
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
|
||||||
vertices.push_back(ReadVertex());
|
vertices.push_back(ReadVertex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,20 +233,20 @@ private:
|
||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportTriangles(aiMesh* mesh) {
|
void ImportTriangles(aiMesh *mesh) {
|
||||||
std::vector<aiFace> faces;
|
std::vector<aiFace> faces;
|
||||||
|
|
||||||
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
|
while (ReadToEndElement(D3MF::XmlTag::triangles)) {
|
||||||
const std::string nodeName( xmlReader->getNodeName() );
|
const std::string nodeName(xmlReader->getNodeName());
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
|
if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
|
||||||
faces.push_back(ReadTriangle());
|
faces.push_back(ReadTriangle());
|
||||||
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
|
const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
|
||||||
if ( nullptr != pidToken ) {
|
if (nullptr != pidToken) {
|
||||||
int matIdx( std::atoi( pidToken ) );
|
int matIdx(std::atoi(pidToken));
|
||||||
mesh->mMaterialIndex = matIdx;
|
mesh->mMaterialIndex = matIdx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
|
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
|
||||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
|
@ -269,117 +269,115 @@ private:
|
||||||
|
|
||||||
void ReadBaseMaterials() {
|
void ReadBaseMaterials() {
|
||||||
std::vector<unsigned int> MatIdArray;
|
std::vector<unsigned int> MatIdArray;
|
||||||
const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
|
const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str()));
|
||||||
if ( nullptr != baseMaterialId ) {
|
if (nullptr != baseMaterialId) {
|
||||||
unsigned int id = std::atoi( baseMaterialId );
|
unsigned int id = std::atoi(baseMaterialId);
|
||||||
const size_t newMatIdx( mMatArray.size() );
|
const size_t newMatIdx(mMatArray.size());
|
||||||
if ( id != mActiveMatGroup ) {
|
if (id != mActiveMatGroup) {
|
||||||
mActiveMatGroup = id;
|
mActiveMatGroup = id;
|
||||||
MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
|
MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
|
||||||
if ( mMatId2MatArray.end() == it ) {
|
if (mMatId2MatArray.end() == it) {
|
||||||
MatIdArray.clear();
|
MatIdArray.clear();
|
||||||
mMatId2MatArray[ id ] = MatIdArray;
|
mMatId2MatArray[id] = MatIdArray;
|
||||||
} else {
|
} else {
|
||||||
MatIdArray = it->second;
|
MatIdArray = it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
|
MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
|
||||||
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
|
mMatId2MatArray[mActiveMatGroup] = MatIdArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
|
while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
|
||||||
mMatArray.push_back( readMaterialDef() );
|
mMatArray.push_back(readMaterialDef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseColor( const char *color, aiColor4D &diffuse ) {
|
bool parseColor(const char *color, aiColor4D &diffuse) {
|
||||||
if ( nullptr == color ) {
|
if (nullptr == color) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
|
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
|
||||||
const size_t len( strlen( color ) );
|
const size_t len(strlen(color));
|
||||||
if ( 9 != len && 7 != len) {
|
if (9 != len && 7 != len) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *buf( color );
|
const char *buf(color);
|
||||||
if ( '#' != *buf ) {
|
if ('#' != *buf) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
++buf;
|
++buf;
|
||||||
char comp[ 3 ] = { 0,0,'\0' };
|
char comp[3] = { 0, 0, '\0' };
|
||||||
|
|
||||||
comp[ 0 ] = *buf;
|
comp[0] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
comp[ 1 ] = *buf;
|
comp[1] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
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;
|
comp[0] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
comp[ 1 ] = *buf;
|
comp[1] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
diffuse.b = static_cast<ai_real>(strtol(comp, NULL, 16)) / ai_real(255.0);
|
||||||
|
|
||||||
comp[ 0 ] = *buf;
|
if (7 == len)
|
||||||
++buf;
|
|
||||||
comp[ 1 ] = *buf;
|
|
||||||
++buf;
|
|
||||||
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
|
||||||
|
|
||||||
if(7 == len)
|
|
||||||
return true;
|
return true;
|
||||||
comp[ 0 ] = *buf;
|
comp[0] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
comp[ 1 ] = *buf;
|
comp[1] = *buf;
|
||||||
++buf;
|
++buf;
|
||||||
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
diffuse.a = static_cast<ai_real>(strtol(comp, NULL, 16)) / ai_real(255.0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignDiffuseColor( aiMaterial *mat ) {
|
void assignDiffuseColor(aiMaterial *mat) {
|
||||||
const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
|
const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
|
||||||
aiColor4D diffuse;
|
aiColor4D diffuse;
|
||||||
if ( parseColor( color, diffuse ) ) {
|
if (parseColor(color, diffuse)) {
|
||||||
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
|
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
aiMaterial *readMaterialDef() {
|
aiMaterial *readMaterialDef() {
|
||||||
aiMaterial *mat( nullptr );
|
aiMaterial *mat(nullptr);
|
||||||
const char *name( nullptr );
|
const char *name(nullptr);
|
||||||
const std::string nodeName( xmlReader->getNodeName() );
|
const std::string nodeName(xmlReader->getNodeName());
|
||||||
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
|
if (nodeName == D3MF::XmlTag::basematerials_base) {
|
||||||
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
|
name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str());
|
||||||
std::string stdMatName;
|
std::string stdMatName;
|
||||||
aiString matName;
|
aiString matName;
|
||||||
std::string strId( to_string( mActiveMatGroup ) );
|
std::string strId(to_string(mActiveMatGroup));
|
||||||
stdMatName += "id";
|
stdMatName += "id";
|
||||||
stdMatName += strId;
|
stdMatName += strId;
|
||||||
stdMatName += "_";
|
stdMatName += "_";
|
||||||
if ( nullptr != name ) {
|
if (nullptr != name) {
|
||||||
stdMatName += std::string( name );
|
stdMatName += std::string(name);
|
||||||
} else {
|
} else {
|
||||||
stdMatName += "basemat";
|
stdMatName += "basemat";
|
||||||
}
|
}
|
||||||
matName.Set( stdMatName );
|
matName.Set(stdMatName);
|
||||||
|
|
||||||
mat = new aiMaterial;
|
mat = new aiMaterial;
|
||||||
mat->AddProperty( &matName, AI_MATKEY_NAME );
|
mat->AddProperty(&matName, AI_MATKEY_NAME);
|
||||||
|
|
||||||
assignDiffuseColor( mat );
|
assignDiffuseColor(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadToStartElement(const std::string& startTag) {
|
bool ReadToStartElement(const std::string &startTag) {
|
||||||
while(xmlReader->read()) {
|
while (xmlReader->read()) {
|
||||||
const std::string &nodeName( xmlReader->getNodeName() );
|
const std::string &nodeName(xmlReader->getNodeName());
|
||||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
|
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
|
||||||
return true;
|
return true;
|
||||||
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
|
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
|
||||||
|
@ -390,9 +388,9 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadToEndElement(const std::string& closeTag) {
|
bool ReadToEndElement(const std::string &closeTag) {
|
||||||
while(xmlReader->read()) {
|
while (xmlReader->read()) {
|
||||||
const std::string &nodeName( xmlReader->getNodeName() );
|
const std::string &nodeName(xmlReader->getNodeName());
|
||||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
||||||
return true;
|
return true;
|
||||||
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
|
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
|
||||||
|
@ -410,11 +408,11 @@ private:
|
||||||
std::string value;
|
std::string value;
|
||||||
};
|
};
|
||||||
std::vector<MetaEntry> mMetaData;
|
std::vector<MetaEntry> mMetaData;
|
||||||
std::vector<aiMesh*> mMeshes;
|
std::vector<aiMesh *> mMeshes;
|
||||||
MatArray mMatArray;
|
MatArray mMatArray;
|
||||||
unsigned int mActiveMatGroup;
|
unsigned int mActiveMatGroup;
|
||||||
MatId2MatArray mMatId2MatArray;
|
MatId2MatArray mMatId2MatArray;
|
||||||
XmlReader* xmlReader;
|
XmlReader *xmlReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace D3MF
|
} //namespace D3MF
|
||||||
|
@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
|
||||||
"3mf"
|
"3mf"
|
||||||
};
|
};
|
||||||
|
|
||||||
D3MFImporter::D3MFImporter()
|
D3MFImporter::D3MFImporter() :
|
||||||
: BaseImporter() {
|
BaseImporter() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,17 +440,17 @@ D3MFImporter::~D3MFImporter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
const std::string extension( GetExtension( filename ) );
|
const std::string extension(GetExtension(filename));
|
||||||
if(extension == desc.mFileExtensions ) {
|
if (extension == desc.mFileExtensions) {
|
||||||
return true;
|
return true;
|
||||||
} else if ( !extension.length() || checkSig ) {
|
} else if (!extension.length() || checkSig) {
|
||||||
if ( nullptr == pIOHandler ) {
|
if (nullptr == pIOHandler) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
|
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
|
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
||||||
return opcPackage.validate();
|
return opcPackage.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +465,7 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
|
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
||||||
|
|
||||||
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
|
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
|
|
@ -147,7 +147,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG(rootFile);
|
ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
|
||||||
|
|
||||||
mZipArchive->Close(fileStream);
|
mZipArchive->Close(fileStream);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -56,29 +56,20 @@ struct aiMesh;
|
||||||
struct aiMaterial;
|
struct aiMaterial;
|
||||||
struct aiLight;
|
struct aiLight;
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
namespace Assimp {
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** AC3D (*.ac) importer class
|
/** AC3D (*.ac) importer class
|
||||||
*/
|
*/
|
||||||
class AC3DImporter : public BaseImporter
|
class AC3DImporter : public BaseImporter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
AC3DImporter();
|
AC3DImporter();
|
||||||
~AC3DImporter();
|
~AC3DImporter();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Represents an AC3D material
|
// Represents an AC3D material
|
||||||
struct Material
|
struct Material {
|
||||||
{
|
Material() :
|
||||||
Material()
|
rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {}
|
||||||
: rgb (0.6f,0.6f,0.6f)
|
|
||||||
, spec (1.f,1.f,1.f)
|
|
||||||
, shin (0.f)
|
|
||||||
, trans (0.f)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// base color of the material
|
// base color of the material
|
||||||
aiColor3D rgb;
|
aiColor3D rgb;
|
||||||
|
@ -103,43 +94,25 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents an AC3D surface
|
// Represents an AC3D surface
|
||||||
struct Surface
|
struct Surface {
|
||||||
{
|
Surface() :
|
||||||
Surface()
|
mat(0), flags(0) {}
|
||||||
: mat (0)
|
|
||||||
, flags (0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
unsigned int mat,flags;
|
unsigned int mat, flags;
|
||||||
|
|
||||||
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
|
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
|
||||||
std::vector< SurfaceEntry > entries;
|
std::vector<SurfaceEntry> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents an AC3D object
|
// Represents an AC3D object
|
||||||
struct Object
|
struct Object {
|
||||||
{
|
Object() :
|
||||||
Object()
|
type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {}
|
||||||
: type (World)
|
|
||||||
, name( "" )
|
|
||||||
, children()
|
|
||||||
, texture( "" )
|
|
||||||
, texRepeat( 1.f, 1.f )
|
|
||||||
, texOffset( 0.0f, 0.0f )
|
|
||||||
, rotation()
|
|
||||||
, translation()
|
|
||||||
, vertices()
|
|
||||||
, surfaces()
|
|
||||||
, numRefs (0)
|
|
||||||
, subDiv (0)
|
|
||||||
, crease()
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Type description
|
// Type description
|
||||||
enum Type
|
enum Type {
|
||||||
{
|
|
||||||
World = 0x0,
|
World = 0x0,
|
||||||
Poly = 0x1,
|
Poly = 0x1,
|
||||||
Group = 0x2,
|
Group = 0x2,
|
||||||
Light = 0x4
|
Light = 0x4
|
||||||
} type;
|
} type;
|
||||||
|
@ -179,37 +152,33 @@ public:
|
||||||
float crease;
|
float crease;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
* See BaseImporter::CanRead() for details.
|
||||||
*/
|
*/
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
|
||||||
bool checkSig) const;
|
bool checkSig) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Return importer meta information.
|
/** Return importer meta information.
|
||||||
* See #BaseImporter::GetInfo for the details */
|
* See #BaseImporter::GetInfo for the details */
|
||||||
const aiImporterDesc* GetInfo () const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Imports the given file into the given scene structure.
|
/** Imports the given file into the given scene structure.
|
||||||
* See BaseImporter::InternReadFile() for details*/
|
* See BaseImporter::InternReadFile() for details*/
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||||
IOSystem* pIOHandler);
|
IOSystem *pIOHandler);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Called prior to ReadFile().
|
/** Called prior to ReadFile().
|
||||||
* The function is a request to the importer to update its configuration
|
* The function is a request to the importer to update its configuration
|
||||||
* basing on the Importer's configuration property list.*/
|
* basing on the Importer's configuration property list.*/
|
||||||
void SetupProperties(const Importer* pImp);
|
void SetupProperties(const Importer *pImp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Get the next line from the file.
|
/** Get the next line from the file.
|
||||||
* @return false if the end of the file was reached*/
|
* @return false if the end of the file was reached*/
|
||||||
|
@ -220,7 +189,7 @@ private:
|
||||||
* load subobjects, the method returns after a 'kids 0' was
|
* load subobjects, the method returns after a 'kids 0' was
|
||||||
* encountered.
|
* encountered.
|
||||||
* @objects List of output objects*/
|
* @objects List of output objects*/
|
||||||
void LoadObjectSection(std::vector<Object>& objects);
|
void LoadObjectSection(std::vector<Object> &objects);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Convert all objects into meshes and nodes.
|
/** Convert all objects into meshes and nodes.
|
||||||
|
@ -229,26 +198,24 @@ private:
|
||||||
* @param outMaterials List of output materials
|
* @param outMaterials List of output materials
|
||||||
* @param materials Material list
|
* @param materials Material list
|
||||||
* @param Scenegraph node for the object */
|
* @param Scenegraph node for the object */
|
||||||
aiNode* ConvertObjectSection(Object& object,
|
aiNode *ConvertObjectSection(Object &object,
|
||||||
std::vector<aiMesh*>& meshes,
|
std::vector<aiMesh *> &meshes,
|
||||||
std::vector<aiMaterial*>& outMaterials,
|
std::vector<aiMaterial *> &outMaterials,
|
||||||
const std::vector<Material>& materials,
|
const std::vector<Material> &materials,
|
||||||
aiNode* parent = NULL);
|
aiNode *parent = nullptr);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Convert a material
|
/** Convert a material
|
||||||
* @param object Current object
|
* @param object Current object
|
||||||
* @param matSrc Source material description
|
* @param matSrc Source material description
|
||||||
* @param matDest Destination material to be filled */
|
* @param matDest Destination material to be filled */
|
||||||
void ConvertMaterial(const Object& object,
|
void ConvertMaterial(const Object &object,
|
||||||
const Material& matSrc,
|
const Material &matSrc,
|
||||||
aiMaterial& matDest);
|
aiMaterial &matDest);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
// points to the next data line
|
// points to the next data line
|
||||||
const char* buffer;
|
const char *buffer;
|
||||||
|
|
||||||
// Configuration option: if enabled, up to two meshes
|
// Configuration option: if enabled, up to two meshes
|
||||||
// are generated per material: those faces who have
|
// are generated per material: those faces who have
|
||||||
|
@ -265,10 +232,10 @@ private:
|
||||||
unsigned int mNumMeshes;
|
unsigned int mNumMeshes;
|
||||||
|
|
||||||
// current list of light sources
|
// current list of light sources
|
||||||
std::vector<aiLight*>* mLights;
|
std::vector<aiLight *> *mLights;
|
||||||
|
|
||||||
// name counters
|
// name counters
|
||||||
unsigned int lights, groups, polys, worlds;
|
unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
|
@ -0,0 +1,672 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// \file AMFImporter.cpp
|
||||||
|
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
|
||||||
|
/// \date 2016
|
||||||
|
/// \author smal.root@gmail.com
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||||
|
|
||||||
|
// Header files, Assimp.
|
||||||
|
#include "AMFImporter.hpp"
|
||||||
|
#include "AMFImporter_Macro.hpp"
|
||||||
|
|
||||||
|
#include <assimp/DefaultIOSystem.h>
|
||||||
|
#include <assimp/fast_atof.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
|
|
@ -0,0 +1,357 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// \file AMFImporter_Geometry.cpp
|
||||||
|
/// \brief Parsing data from geometry nodes.
|
||||||
|
/// \date 2016
|
||||||
|
/// \author smal.root@gmail.com
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||||
|
|
||||||
|
#include "AMFImporter.hpp"
|
||||||
|
#include "AMFImporter_Macro.hpp"
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
|
||||||
|
// <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
|
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// \file AMFImporter_Macro.hpp
|
||||||
|
/// \brief Useful macrodefines.
|
||||||
|
/// \date 2016
|
||||||
|
/// \author smal.root@gmail.com
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef AMFIMPORTER_MACRO_HPP_INCLUDED
|
||||||
|
#define AMFIMPORTER_MACRO_HPP_INCLUDED
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_LOOPBEG
|
||||||
|
/// Begin of loop that read attributes values.
|
||||||
|
#define MACRO_ATTRREAD_LOOPBEG \
|
||||||
|
for(int idx = 0, idx_end = mReader->getAttributeCount(); idx < idx_end; idx++) \
|
||||||
|
{ \
|
||||||
|
std::string an(mReader->getAttributeName(idx));
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_LOOPEND
|
||||||
|
/// End of loop that read attributes values.
|
||||||
|
#define MACRO_ATTRREAD_LOOPEND \
|
||||||
|
Throw_IncorrectAttr(an); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_LOOPEND_WSKIP
|
||||||
|
/// End of loop that read attributes values. Difference from \ref MACRO_ATTRREAD_LOOPEND in that: current macro skip unknown attributes, but
|
||||||
|
/// \ref MACRO_ATTRREAD_LOOPEND throw an exception.
|
||||||
|
#define MACRO_ATTRREAD_LOOPEND_WSKIP \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_CHECK_REF
|
||||||
|
/// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
|
||||||
|
/// "continue" will called.
|
||||||
|
/// \param [in] pAttrName - attribute name.
|
||||||
|
/// \param [out] pVarName - output variable name.
|
||||||
|
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
|
||||||
|
#define MACRO_ATTRREAD_CHECK_REF(pAttrName, pVarName, pFunction) \
|
||||||
|
if(an == pAttrName) \
|
||||||
|
{ \
|
||||||
|
pFunction(idx, pVarName); \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_ATTRREAD_CHECK_RET
|
||||||
|
/// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
|
||||||
|
/// If result was read then "continue" will called.
|
||||||
|
/// \param [in] pAttrName - attribute name.
|
||||||
|
/// \param [out] pVarName - output variable name.
|
||||||
|
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
|
||||||
|
#define MACRO_ATTRREAD_CHECK_RET(pAttrName, pVarName, pFunction) \
|
||||||
|
if(an == pAttrName) \
|
||||||
|
{ \
|
||||||
|
pVarName = pFunction(idx); \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_NODECHECK_LOOPBEGIN(pNodeName)
|
||||||
|
/// Begin of loop of parsing child nodes. Do not add ';' at end.
|
||||||
|
/// \param [in] pNodeName - current node name.
|
||||||
|
#define MACRO_NODECHECK_LOOPBEGIN(pNodeName) \
|
||||||
|
do { \
|
||||||
|
bool close_found = false; \
|
||||||
|
\
|
||||||
|
while(mReader->read()) \
|
||||||
|
{ \
|
||||||
|
if(mReader->getNodeType() == irr::io::EXN_ELEMENT) \
|
||||||
|
{
|
||||||
|
|
||||||
|
/// \def MACRO_NODECHECK_LOOPEND(pNodeName)
|
||||||
|
/// End of loop of parsing child nodes.
|
||||||
|
/// \param [in] pNodeName - current node name.
|
||||||
|
#define MACRO_NODECHECK_LOOPEND(pNodeName) \
|
||||||
|
XML_CheckNode_SkipUnsupported(pNodeName); \
|
||||||
|
}/* if(mReader->getNodeType() == irr::io::EXN_ELEMENT) */ \
|
||||||
|
else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) \
|
||||||
|
{ \
|
||||||
|
if(XML_CheckNode_NameEqual(pNodeName)) \
|
||||||
|
{ \
|
||||||
|
close_found = true; \
|
||||||
|
\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}/* else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) */ \
|
||||||
|
}/* while(mReader->read()) */ \
|
||||||
|
\
|
||||||
|
if(!close_found) Throw_CloseNotFound(pNodeName); \
|
||||||
|
\
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
/// \def MACRO_NODECHECK_READCOMP_F
|
||||||
|
/// Check current node name and if it equal to requested then read value. Result write to output variable of type "float".
|
||||||
|
/// If result was read then "continue" will called. Also check if node data already read then raise exception.
|
||||||
|
/// \param [in] pNodeName - node name.
|
||||||
|
/// \param [in, out] pReadFlag - read flag.
|
||||||
|
/// \param [out] pVarName - output variable name.
|
||||||
|
#define MACRO_NODECHECK_READCOMP_F(pNodeName, pReadFlag, pVarName) \
|
||||||
|
if(XML_CheckNode_NameEqual(pNodeName)) \
|
||||||
|
{ \
|
||||||
|
/* Check if field already read before. */ \
|
||||||
|
if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \
|
||||||
|
/* Read color component and assign it to object. */ \
|
||||||
|
pVarName = XML_ReadNode_GetVal_AsFloat(); \
|
||||||
|
pReadFlag = true; \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \def MACRO_NODECHECK_READCOMP_U32
|
||||||
|
/// Check current node name and if it equal to requested then read value. Result write to output variable of type "uint32_t".
|
||||||
|
/// If result was read then "continue" will called. Also check if node data already read then raise exception.
|
||||||
|
/// \param [in] pNodeName - node name.
|
||||||
|
/// \param [in, out] pReadFlag - read flag.
|
||||||
|
/// \param [out] pVarName - output variable name.
|
||||||
|
#define MACRO_NODECHECK_READCOMP_U32(pNodeName, pReadFlag, pVarName) \
|
||||||
|
if(XML_CheckNode_NameEqual(pNodeName)) \
|
||||||
|
{ \
|
||||||
|
/* Check if field already read before. */ \
|
||||||
|
if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \
|
||||||
|
/* Read color component and assign it to object. */ \
|
||||||
|
pVarName = XML_ReadNode_GetVal_AsU32(); \
|
||||||
|
pReadFlag = true; \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AMFIMPORTER_MACRO_HPP_INCLUDED
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
|
@ -0,0 +1,872 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// \file AMFImporter_Postprocess.cpp
|
||||||
|
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
|
||||||
|
/// \date 2016
|
||||||
|
/// \author smal.root@gmail.com
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||||
|
|
||||||
|
#include "AMFImporter.hpp"
|
||||||
|
|
||||||
|
// Header files, Assimp.
|
||||||
|
#include <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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/qnan.h>
|
#include <assimp/qnan.h>
|
||||||
|
|
||||||
// ASE is quite similar to 3ds. We can reuse some structures
|
// ASE is quite similar to 3ds. We can reuse some structures
|
||||||
#include "3DS/3DSLoader.h"
|
#include "AssetLib/3DS/3DSLoader.h"
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace ASE {
|
namespace ASE {
|
||||||
|
@ -80,7 +80,18 @@ struct Material : public D3DS::Material
|
||||||
}
|
}
|
||||||
|
|
||||||
Material(const Material &other) = default;
|
Material(const Material &other) = default;
|
||||||
Material &operator=(const Material &other) = default;
|
|
||||||
|
Material &operator=(const Material &other) {
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
avSubMaterials = other.avSubMaterials;
|
||||||
|
pcInstance = other.pcInstance;
|
||||||
|
bNeed = other.bNeed;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
||||||
|
@ -94,12 +105,12 @@ struct Material : public D3DS::Material
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Material &operator=(Material &&other) AI_NO_EXCEPT {
|
Material &operator=( Material &&other) AI_NO_EXCEPT {
|
||||||
if (this == &other) {
|
if (this == &other) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DS::Material::operator=(std::move(other));
|
//D3DS::Material::operator=(std::move(other));
|
||||||
|
|
||||||
avSubMaterials = std::move(other.avSubMaterials);
|
avSubMaterials = std::move(other.avSubMaterials);
|
||||||
pcInstance = std::move(other.pcInstance);
|
pcInstance = std::move(other.pcInstance);
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
/** @file AssbinExporter.cpp
|
||||||
|
* ASSBIN exporter main code
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||||
|
|
||||||
|
#include "AssbinFileWriter.h"
|
||||||
|
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
void ExportSceneAssbin(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
|
||||||
|
DumpSceneToAssbin(
|
||||||
|
pFile,
|
||||||
|
"\0", // no command(s).
|
||||||
|
pIOSystem,
|
||||||
|
pScene,
|
||||||
|
false, // shortened?
|
||||||
|
false); // compressed?
|
||||||
|
}
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||||
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,832 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
/** @file AssbinFileWriter.cpp
|
||||||
|
* @brief Implementation of Assbin file writer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AssbinFileWriter.h"
|
||||||
|
|
||||||
|
#include "Common/assbin_chunks.h"
|
||||||
|
#include "PostProcessing/ProcessHelper.h"
|
||||||
|
|
||||||
|
#include <assimp/Exceptional.h>
|
||||||
|
#include <assimp/version.h>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/IOStream.hpp>
|
||||||
|
|
||||||
|
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
||||||
|
#include <zlib.h>
|
||||||
|
#else
|
||||||
|
#include "../contrib/zlib/zlib.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4706)
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
size_t Write(IOStream *stream, const T &v) {
|
||||||
|
return stream->Write(&v, sizeof(T), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize an aiString
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiString>(IOStream *stream, const aiString &s) {
|
||||||
|
const size_t s2 = (uint32_t)s.length;
|
||||||
|
stream->Write(&s, 4, 1);
|
||||||
|
stream->Write(s.data, s2, 1);
|
||||||
|
|
||||||
|
return s2 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize an unsigned int as uint32_t
|
||||||
|
template <>
|
||||||
|
inline size_t Write<unsigned int>(IOStream *stream, const unsigned int &w) {
|
||||||
|
const uint32_t t = (uint32_t)w;
|
||||||
|
if (w > t) {
|
||||||
|
// this shouldn't happen, integers in Assimp data structures never exceed 2^32
|
||||||
|
throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->Write(&t, 4, 1);
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize an unsigned int as uint16_t
|
||||||
|
template <>
|
||||||
|
inline size_t Write<uint16_t>(IOStream *stream, const uint16_t &w) {
|
||||||
|
static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t)==2");
|
||||||
|
stream->Write(&w, 2, 1);
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a float
|
||||||
|
template <>
|
||||||
|
inline size_t Write<float>(IOStream *stream, const float &f) {
|
||||||
|
static_assert(sizeof(float) == 4, "sizeof(float)==4");
|
||||||
|
stream->Write(&f, 4, 1);
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a double
|
||||||
|
template <>
|
||||||
|
inline size_t Write<double>(IOStream *stream, const double &f) {
|
||||||
|
static_assert(sizeof(double) == 8, "sizeof(double)==8");
|
||||||
|
stream->Write(&f, 8, 1);
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a vec3
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiVector3D>(IOStream *stream, const aiVector3D &v) {
|
||||||
|
size_t t = Write<float>(stream, v.x);
|
||||||
|
t += Write<float>(stream, v.y);
|
||||||
|
t += Write<float>(stream, v.z);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a color value
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiColor3D>(IOStream *stream, const aiColor3D &v) {
|
||||||
|
size_t t = Write<float>(stream, v.r);
|
||||||
|
t += Write<float>(stream, v.g);
|
||||||
|
t += Write<float>(stream, v.b);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a color value
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiColor4D>(IOStream *stream, const aiColor4D &v) {
|
||||||
|
size_t t = Write<float>(stream, v.r);
|
||||||
|
t += Write<float>(stream, v.g);
|
||||||
|
t += Write<float>(stream, v.b);
|
||||||
|
t += Write<float>(stream, v.a);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a quaternion
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiQuaternion>(IOStream *stream, const aiQuaternion &v) {
|
||||||
|
size_t t = Write<float>(stream, v.w);
|
||||||
|
t += Write<float>(stream, v.x);
|
||||||
|
t += Write<float>(stream, v.y);
|
||||||
|
t += Write<float>(stream, v.z);
|
||||||
|
ai_assert(t == 16);
|
||||||
|
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a vertex weight
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiVertexWeight>(IOStream *stream, const aiVertexWeight &v) {
|
||||||
|
size_t t = Write<unsigned int>(stream, v.mVertexId);
|
||||||
|
|
||||||
|
return t + Write<float>(stream, v.mWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize a mat4x4
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiMatrix4x4>(IOStream *stream, const aiMatrix4x4 &m) {
|
||||||
|
for (unsigned int i = 0; i < 4; ++i) {
|
||||||
|
for (unsigned int i2 = 0; i2 < 4; ++i2) {
|
||||||
|
Write<float>(stream, m[i][i2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize an aiVectorKey
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiVectorKey>(IOStream *stream, const aiVectorKey &v) {
|
||||||
|
const size_t t = Write<double>(stream, v.mTime);
|
||||||
|
return t + Write<aiVector3D>(stream, v.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Serialize an aiQuatKey
|
||||||
|
template <>
|
||||||
|
inline size_t Write<aiQuatKey>(IOStream *stream, const aiQuatKey &v) {
|
||||||
|
const size_t t = Write<double>(stream, v.mTime);
|
||||||
|
return t + Write<aiQuaternion>(stream, v.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline size_t WriteBounds(IOStream *stream, const T *in, unsigned int size) {
|
||||||
|
T minc, maxc;
|
||||||
|
ArrayBounds(in, size, minc, maxc);
|
||||||
|
|
||||||
|
const size_t t = Write<T>(stream, minc);
|
||||||
|
return t + Write<T>(stream, maxc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use this to write out non-byte arrays so that we write using the specializations.
|
||||||
|
// This way we avoid writing out extra bytes that potentially come from struct alignment.
|
||||||
|
template <typename T>
|
||||||
|
inline size_t WriteArray(IOStream *stream, const T *in, unsigned int size) {
|
||||||
|
size_t n = 0;
|
||||||
|
for (unsigned int i = 0; i < size; i++)
|
||||||
|
n += Write<T>(stream, in[i]);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------
|
||||||
|
/** @class AssbinChunkWriter
|
||||||
|
* @brief Chunk writer mechanism for the .assbin file structure
|
||||||
|
*
|
||||||
|
* This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
|
||||||
|
* the difference being that this takes another IOStream as a "container" in the
|
||||||
|
* constructor, and when it is destroyed, it appends the magic number, the chunk size,
|
||||||
|
* and the chunk contents to the container stream. This allows relatively easy chunk
|
||||||
|
* chunk construction, even recursively.
|
||||||
|
*/
|
||||||
|
class AssbinChunkWriter : public IOStream {
|
||||||
|
private:
|
||||||
|
uint8_t *buffer;
|
||||||
|
uint32_t magic;
|
||||||
|
IOStream *container;
|
||||||
|
size_t cur_size, cursor, initial;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
void Grow(size_t need = 0) {
|
||||||
|
size_t new_size = std::max(initial, std::max(need, cur_size + (cur_size >> 1)));
|
||||||
|
|
||||||
|
const uint8_t *const old = buffer;
|
||||||
|
buffer = new uint8_t[new_size];
|
||||||
|
|
||||||
|
if (old) {
|
||||||
|
memcpy(buffer, old, cur_size);
|
||||||
|
delete[] old;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) :
|
||||||
|
buffer(nullptr),
|
||||||
|
magic(magic),
|
||||||
|
container(container),
|
||||||
|
cur_size(0),
|
||||||
|
cursor(0),
|
||||||
|
initial(initial) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~AssbinChunkWriter() {
|
||||||
|
if (container) {
|
||||||
|
container->Write(&magic, sizeof(uint32_t), 1);
|
||||||
|
container->Write(&cursor, sizeof(uint32_t), 1);
|
||||||
|
container->Write(buffer, 1, cursor);
|
||||||
|
}
|
||||||
|
if (buffer) delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *GetBufferPointer() { return buffer; }
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
virtual size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
|
||||||
|
return aiReturn_FAILURE;
|
||||||
|
}
|
||||||
|
virtual size_t Tell() const {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
virtual void Flush() {
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t FileSize() const {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
virtual size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) {
|
||||||
|
pSize *= pCount;
|
||||||
|
if (cursor + pSize > cur_size) {
|
||||||
|
Grow(cursor + pSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer + cursor, pvBuffer, pSize);
|
||||||
|
cursor += pSize;
|
||||||
|
|
||||||
|
return pCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------
|
||||||
|
/** @class AssbinFileWriter
|
||||||
|
* @brief Assbin file writer class
|
||||||
|
*
|
||||||
|
* This class writes an .assbin file, and is responsible for the file layout.
|
||||||
|
*/
|
||||||
|
class AssbinFileWriter {
|
||||||
|
private:
|
||||||
|
bool shortened;
|
||||||
|
bool compressed;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryNode(IOStream *container, const aiNode *node) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE);
|
||||||
|
|
||||||
|
unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, node->mName);
|
||||||
|
Write<aiMatrix4x4>(&chunk, node->mTransformation);
|
||||||
|
Write<unsigned int>(&chunk, node->mNumChildren);
|
||||||
|
Write<unsigned int>(&chunk, node->mNumMeshes);
|
||||||
|
Write<unsigned int>(&chunk, nb_metadata);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||||
|
Write<unsigned int>(&chunk, node->mMeshes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||||
|
WriteBinaryNode(&chunk, node->mChildren[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < nb_metadata; ++i) {
|
||||||
|
const aiString &key = node->mMetaData->mKeys[i];
|
||||||
|
aiMetadataType type = node->mMetaData->mValues[i].mType;
|
||||||
|
void *value = node->mMetaData->mValues[i].mData;
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, key);
|
||||||
|
Write<uint16_t>(&chunk, (uint16_t)type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AI_BOOL:
|
||||||
|
Write<bool>(&chunk, *((bool *)value));
|
||||||
|
break;
|
||||||
|
case AI_INT32:
|
||||||
|
Write<int32_t>(&chunk, *((int32_t *)value));
|
||||||
|
break;
|
||||||
|
case AI_UINT64:
|
||||||
|
Write<uint64_t>(&chunk, *((uint64_t *)value));
|
||||||
|
break;
|
||||||
|
case AI_FLOAT:
|
||||||
|
Write<float>(&chunk, *((float *)value));
|
||||||
|
break;
|
||||||
|
case AI_DOUBLE:
|
||||||
|
Write<double>(&chunk, *((double *)value));
|
||||||
|
break;
|
||||||
|
case AI_AISTRING:
|
||||||
|
Write<aiString>(&chunk, *((aiString *)value));
|
||||||
|
break;
|
||||||
|
case AI_AIVECTOR3D:
|
||||||
|
Write<aiVector3D>(&chunk, *((aiVector3D *)value));
|
||||||
|
break;
|
||||||
|
#ifdef SWIG
|
||||||
|
case FORCE_32BIT:
|
||||||
|
#endif // SWIG
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryTexture(IOStream *container, const aiTexture *tex) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AITEXTURE);
|
||||||
|
|
||||||
|
Write<unsigned int>(&chunk, tex->mWidth);
|
||||||
|
Write<unsigned int>(&chunk, tex->mHeight);
|
||||||
|
// Write the texture format, but don't include the null terminator.
|
||||||
|
chunk.Write(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1);
|
||||||
|
|
||||||
|
if (!shortened) {
|
||||||
|
if (!tex->mHeight) {
|
||||||
|
chunk.Write(tex->pcData, 1, tex->mWidth);
|
||||||
|
} else {
|
||||||
|
chunk.Write(tex->pcData, 1, tex->mWidth * tex->mHeight * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryBone(IOStream *container, const aiBone *b) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIBONE);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, b->mName);
|
||||||
|
Write<unsigned int>(&chunk, b->mNumWeights);
|
||||||
|
Write<aiMatrix4x4>(&chunk, b->mOffsetMatrix);
|
||||||
|
|
||||||
|
// for the moment we write dumb min/max values for the bones, too.
|
||||||
|
// maybe I'll add a better, hash-like solution later
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, b->mWeights, b->mNumWeights);
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVertexWeight>(&chunk, b->mWeights, b->mNumWeights);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryMesh(IOStream *container, const aiMesh *mesh) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMESH);
|
||||||
|
|
||||||
|
Write<unsigned int>(&chunk, mesh->mPrimitiveTypes);
|
||||||
|
Write<unsigned int>(&chunk, mesh->mNumVertices);
|
||||||
|
Write<unsigned int>(&chunk, mesh->mNumFaces);
|
||||||
|
Write<unsigned int>(&chunk, mesh->mNumBones);
|
||||||
|
Write<unsigned int>(&chunk, mesh->mMaterialIndex);
|
||||||
|
|
||||||
|
// first of all, write bits for all existent vertex components
|
||||||
|
unsigned int c = 0;
|
||||||
|
if (mesh->mVertices) {
|
||||||
|
c |= ASSBIN_MESH_HAS_POSITIONS;
|
||||||
|
}
|
||||||
|
if (mesh->mNormals) {
|
||||||
|
c |= ASSBIN_MESH_HAS_NORMALS;
|
||||||
|
}
|
||||||
|
if (mesh->mTangents && mesh->mBitangents) {
|
||||||
|
c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
|
||||||
|
}
|
||||||
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) {
|
||||||
|
if (!mesh->mTextureCoords[n]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c |= ASSBIN_MESH_HAS_TEXCOORD(n);
|
||||||
|
}
|
||||||
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) {
|
||||||
|
if (!mesh->mColors[n]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c |= ASSBIN_MESH_HAS_COLOR(n);
|
||||||
|
}
|
||||||
|
Write<unsigned int>(&chunk, c);
|
||||||
|
|
||||||
|
aiVector3D minVec, maxVec;
|
||||||
|
if (mesh->mVertices) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, mesh->mVertices, mesh->mNumVertices);
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVector3D>(&chunk, mesh->mVertices, mesh->mNumVertices);
|
||||||
|
}
|
||||||
|
if (mesh->mNormals) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, mesh->mNormals, mesh->mNumVertices);
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVector3D>(&chunk, mesh->mNormals, mesh->mNumVertices);
|
||||||
|
}
|
||||||
|
if (mesh->mTangents && mesh->mBitangents) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, mesh->mTangents, mesh->mNumVertices);
|
||||||
|
WriteBounds(&chunk, mesh->mBitangents, mesh->mNumVertices);
|
||||||
|
} // else write as usual
|
||||||
|
else {
|
||||||
|
WriteArray<aiVector3D>(&chunk, mesh->mTangents, mesh->mNumVertices);
|
||||||
|
WriteArray<aiVector3D>(&chunk, mesh->mBitangents, mesh->mNumVertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) {
|
||||||
|
if (!mesh->mColors[n])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, mesh->mColors[n], mesh->mNumVertices);
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiColor4D>(&chunk, mesh->mColors[n], mesh->mNumVertices);
|
||||||
|
}
|
||||||
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) {
|
||||||
|
if (!mesh->mTextureCoords[n])
|
||||||
|
break;
|
||||||
|
|
||||||
|
// write number of UV components
|
||||||
|
Write<unsigned int>(&chunk, mesh->mNumUVComponents[n]);
|
||||||
|
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVector3D>(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write faces. There are no floating-point calculations involved
|
||||||
|
// in these, so we can write a simple hash over the face data
|
||||||
|
// to the dump file. We generate a single 32 Bit hash for 512 faces
|
||||||
|
// using Assimp's standard hashing function.
|
||||||
|
if (shortened) {
|
||||||
|
unsigned int processed = 0;
|
||||||
|
for (unsigned int job; (job = std::min(mesh->mNumFaces - processed, 512u)); processed += job) {
|
||||||
|
uint32_t hash = 0;
|
||||||
|
for (unsigned int a = 0; a < job; ++a) {
|
||||||
|
|
||||||
|
const aiFace &f = mesh->mFaces[processed + a];
|
||||||
|
uint32_t tmp = f.mNumIndices;
|
||||||
|
hash = SuperFastHash(reinterpret_cast<const char *>(&tmp), sizeof tmp, hash);
|
||||||
|
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
|
||||||
|
static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
|
||||||
|
tmp = static_cast<uint32_t>(f.mIndices[i]);
|
||||||
|
hash = SuperFastHash(reinterpret_cast<const char *>(&tmp), sizeof tmp, hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write<unsigned int>(&chunk, hash);
|
||||||
|
}
|
||||||
|
} else // else write as usual
|
||||||
|
{
|
||||||
|
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||||
|
const aiFace &f = mesh->mFaces[i];
|
||||||
|
|
||||||
|
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
|
||||||
|
Write<uint16_t>(&chunk, static_cast<uint16_t>(f.mNumIndices));
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||||
|
if (mesh->mNumVertices < (1u << 16)) {
|
||||||
|
Write<uint16_t>(&chunk, static_cast<uint16_t>(f.mIndices[a]));
|
||||||
|
} else {
|
||||||
|
Write<unsigned int>(&chunk, f.mIndices[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write bones
|
||||||
|
if (mesh->mNumBones) {
|
||||||
|
for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
|
||||||
|
const aiBone *b = mesh->mBones[a];
|
||||||
|
WriteBinaryBone(&chunk, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryMaterialProperty(IOStream *container, const aiMaterialProperty *prop) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIALPROPERTY);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, prop->mKey);
|
||||||
|
Write<unsigned int>(&chunk, prop->mSemantic);
|
||||||
|
Write<unsigned int>(&chunk, prop->mIndex);
|
||||||
|
|
||||||
|
Write<unsigned int>(&chunk, prop->mDataLength);
|
||||||
|
Write<unsigned int>(&chunk, (unsigned int)prop->mType);
|
||||||
|
chunk.Write(prop->mData, 1, prop->mDataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryMaterial(IOStream *container, const aiMaterial *mat) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIAL);
|
||||||
|
|
||||||
|
Write<unsigned int>(&chunk, mat->mNumProperties);
|
||||||
|
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
||||||
|
WriteBinaryMaterialProperty(&chunk, mat->mProperties[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryNodeAnim(IOStream *container, const aiNodeAnim *nd) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODEANIM);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, nd->mNodeName);
|
||||||
|
Write<unsigned int>(&chunk, nd->mNumPositionKeys);
|
||||||
|
Write<unsigned int>(&chunk, nd->mNumRotationKeys);
|
||||||
|
Write<unsigned int>(&chunk, nd->mNumScalingKeys);
|
||||||
|
Write<unsigned int>(&chunk, nd->mPreState);
|
||||||
|
Write<unsigned int>(&chunk, nd->mPostState);
|
||||||
|
|
||||||
|
if (nd->mPositionKeys) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||||
|
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVectorKey>(&chunk, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||||
|
}
|
||||||
|
if (nd->mRotationKeys) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||||
|
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiQuatKey>(&chunk, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||||
|
}
|
||||||
|
if (nd->mScalingKeys) {
|
||||||
|
if (shortened) {
|
||||||
|
WriteBounds(&chunk, nd->mScalingKeys, nd->mNumScalingKeys);
|
||||||
|
|
||||||
|
} // else write as usual
|
||||||
|
else
|
||||||
|
WriteArray<aiVectorKey>(&chunk, nd->mScalingKeys, nd->mNumScalingKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryAnim(IOStream *container, const aiAnimation *anim) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIANIMATION);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, anim->mName);
|
||||||
|
Write<double>(&chunk, anim->mDuration);
|
||||||
|
Write<double>(&chunk, anim->mTicksPerSecond);
|
||||||
|
Write<unsigned int>(&chunk, anim->mNumChannels);
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
|
||||||
|
const aiNodeAnim *nd = anim->mChannels[a];
|
||||||
|
WriteBinaryNodeAnim(&chunk, nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryLight(IOStream *container, const aiLight *l) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AILIGHT);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, l->mName);
|
||||||
|
Write<unsigned int>(&chunk, l->mType);
|
||||||
|
|
||||||
|
if (l->mType != aiLightSource_DIRECTIONAL) {
|
||||||
|
Write<float>(&chunk, l->mAttenuationConstant);
|
||||||
|
Write<float>(&chunk, l->mAttenuationLinear);
|
||||||
|
Write<float>(&chunk, l->mAttenuationQuadratic);
|
||||||
|
}
|
||||||
|
|
||||||
|
Write<aiColor3D>(&chunk, l->mColorDiffuse);
|
||||||
|
Write<aiColor3D>(&chunk, l->mColorSpecular);
|
||||||
|
Write<aiColor3D>(&chunk, l->mColorAmbient);
|
||||||
|
|
||||||
|
if (l->mType == aiLightSource_SPOT) {
|
||||||
|
Write<float>(&chunk, l->mAngleInnerCone);
|
||||||
|
Write<float>(&chunk, l->mAngleOuterCone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryCamera(IOStream *container, const aiCamera *cam) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AICAMERA);
|
||||||
|
|
||||||
|
Write<aiString>(&chunk, cam->mName);
|
||||||
|
Write<aiVector3D>(&chunk, cam->mPosition);
|
||||||
|
Write<aiVector3D>(&chunk, cam->mLookAt);
|
||||||
|
Write<aiVector3D>(&chunk, cam->mUp);
|
||||||
|
Write<float>(&chunk, cam->mHorizontalFOV);
|
||||||
|
Write<float>(&chunk, cam->mClipPlaneNear);
|
||||||
|
Write<float>(&chunk, cam->mClipPlaneFar);
|
||||||
|
Write<float>(&chunk, cam->mAspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
void WriteBinaryScene(IOStream *container, const aiScene *scene) {
|
||||||
|
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AISCENE);
|
||||||
|
|
||||||
|
// basic scene information
|
||||||
|
Write<unsigned int>(&chunk, scene->mFlags);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumMeshes);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumMaterials);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumAnimations);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumTextures);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumLights);
|
||||||
|
Write<unsigned int>(&chunk, scene->mNumCameras);
|
||||||
|
|
||||||
|
// write node graph
|
||||||
|
WriteBinaryNode(&chunk, scene->mRootNode);
|
||||||
|
|
||||||
|
// write all meshes
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||||
|
const aiMesh *mesh = scene->mMeshes[i];
|
||||||
|
WriteBinaryMesh(&chunk, mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write materials
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||||
|
const aiMaterial *mat = scene->mMaterials[i];
|
||||||
|
WriteBinaryMaterial(&chunk, mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write all animations
|
||||||
|
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||||
|
const aiAnimation *anim = scene->mAnimations[i];
|
||||||
|
WriteBinaryAnim(&chunk, anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write all textures
|
||||||
|
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
|
||||||
|
const aiTexture *mesh = scene->mTextures[i];
|
||||||
|
WriteBinaryTexture(&chunk, mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write lights
|
||||||
|
for (unsigned int i = 0; i < scene->mNumLights; ++i) {
|
||||||
|
const aiLight *l = scene->mLights[i];
|
||||||
|
WriteBinaryLight(&chunk, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write cameras
|
||||||
|
for (unsigned int i = 0; i < scene->mNumCameras; ++i) {
|
||||||
|
const aiCamera *cam = scene->mCameras[i];
|
||||||
|
WriteBinaryCamera(&chunk, cam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
AssbinFileWriter(bool shortened, bool compressed) :
|
||||||
|
shortened(shortened), compressed(compressed) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Write a binary model dump
|
||||||
|
void WriteBinaryDump(const char *pFile, const char *cmd, IOSystem *pIOSystem, const aiScene *pScene) {
|
||||||
|
IOStream *out = pIOSystem->Open(pFile, "wb");
|
||||||
|
if (!out)
|
||||||
|
throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
|
||||||
|
|
||||||
|
auto CloseIOStream = [&]() {
|
||||||
|
if (out) {
|
||||||
|
pIOSystem->Close(out);
|
||||||
|
out = nullptr; // Ensure this is only done once.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
time_t tt = time(NULL);
|
||||||
|
#if _WIN32
|
||||||
|
tm *p = gmtime(&tt);
|
||||||
|
#else
|
||||||
|
struct tm now;
|
||||||
|
tm *p = gmtime_r(&tt, &now);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// header
|
||||||
|
char s[64];
|
||||||
|
memset(s, 0, 64);
|
||||||
|
#if _MSC_VER >= 1400
|
||||||
|
sprintf_s(s, "ASSIMP.binary-dump.%s", asctime(p));
|
||||||
|
#else
|
||||||
|
ai_snprintf(s, 64, "ASSIMP.binary-dump.%s", asctime(p));
|
||||||
|
#endif
|
||||||
|
out->Write(s, 44, 1);
|
||||||
|
// == 44 bytes
|
||||||
|
|
||||||
|
Write<unsigned int>(out, ASSBIN_VERSION_MAJOR);
|
||||||
|
Write<unsigned int>(out, ASSBIN_VERSION_MINOR);
|
||||||
|
Write<unsigned int>(out, aiGetVersionRevision());
|
||||||
|
Write<unsigned int>(out, aiGetCompileFlags());
|
||||||
|
Write<uint16_t>(out, shortened);
|
||||||
|
Write<uint16_t>(out, compressed);
|
||||||
|
// == 20 bytes
|
||||||
|
|
||||||
|
char buff[256] = { 0 };
|
||||||
|
ai_snprintf(buff, 256, "%s", pFile);
|
||||||
|
out->Write(buff, sizeof(char), 256);
|
||||||
|
|
||||||
|
memset(buff, 0, sizeof(buff));
|
||||||
|
ai_snprintf(buff, 128, "%s", cmd);
|
||||||
|
out->Write(buff, sizeof(char), 128);
|
||||||
|
|
||||||
|
// leave 64 bytes free for future extensions
|
||||||
|
memset(buff, 0xcd, 64);
|
||||||
|
out->Write(buff, sizeof(char), 64);
|
||||||
|
// == 435 bytes
|
||||||
|
|
||||||
|
// ==== total header size: 512 bytes
|
||||||
|
ai_assert(out->Tell() == ASSBIN_HEADER_LENGTH);
|
||||||
|
|
||||||
|
// Up to here the data is uncompressed. For compressed files, the rest
|
||||||
|
// is compressed using standard DEFLATE from zlib.
|
||||||
|
if (compressed) {
|
||||||
|
AssbinChunkWriter uncompressedStream(NULL, 0);
|
||||||
|
WriteBinaryScene(&uncompressedStream, pScene);
|
||||||
|
|
||||||
|
uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
|
||||||
|
uLongf compressedSize = (uLongf)compressBound(uncompressedSize);
|
||||||
|
uint8_t *compressedBuffer = new uint8_t[compressedSize];
|
||||||
|
|
||||||
|
int res = compress2(compressedBuffer, &compressedSize, (const Bytef *)uncompressedStream.GetBufferPointer(), uncompressedSize, 9);
|
||||||
|
if (res != Z_OK) {
|
||||||
|
delete[] compressedBuffer;
|
||||||
|
throw DeadlyExportError("Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Write(&uncompressedSize, sizeof(uint32_t), 1);
|
||||||
|
out->Write(compressedBuffer, sizeof(char), compressedSize);
|
||||||
|
|
||||||
|
delete[] compressedBuffer;
|
||||||
|
} else {
|
||||||
|
WriteBinaryScene(out, pScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseIOStream();
|
||||||
|
} catch (...) {
|
||||||
|
CloseIOStream();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void DumpSceneToAssbin(
|
||||||
|
const char *pFile, const char *cmd, IOSystem *pIOSystem,
|
||||||
|
const aiScene *pScene, bool shortened, bool compressed) {
|
||||||
|
AssbinFileWriter fileWriter(shortened, compressed);
|
||||||
|
fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file AssbinFileWriter.h
|
||||||
|
* @brief Declaration of Assbin file writer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AI_ASSBINFILEWRITER_H_INC
|
||||||
|
#define AI_ASSBINFILEWRITER_H_INC
|
||||||
|
|
||||||
|
#include <assimp/defs.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
void ASSIMP_API DumpSceneToAssbin(
|
||||||
|
const char *pFile,
|
||||||
|
const char *cmd,
|
||||||
|
IOSystem *pIOSystem,
|
||||||
|
const aiScene *pScene,
|
||||||
|
bool shortened,
|
||||||
|
bool compressed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AI_ASSBINFILEWRITER_H_INC
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -50,19 +48,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||||
|
|
||||||
// internal headers
|
// internal headers
|
||||||
#include "Assbin/AssbinLoader.h"
|
#include "AssetLib/Assbin/AssbinLoader.h"
|
||||||
#include "Common/assbin_chunks.h"
|
#include "Common/assbin_chunks.h"
|
||||||
#include <assimp/MemoryIOWrapper.h>
|
#include <assimp/MemoryIOWrapper.h>
|
||||||
#include <assimp/mesh.h>
|
|
||||||
#include <assimp/anim.h>
|
#include <assimp/anim.h>
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
||||||
# include <zlib.h>
|
#include <zlib.h>
|
||||||
#else
|
#else
|
||||||
# include <contrib/zlib/zlib.h>
|
#include <contrib/zlib/zlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -81,94 +79,97 @@ static const aiImporterDesc desc = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
const aiImporterDesc* AssbinImporter::GetInfo() const {
|
const aiImporterDesc *AssbinImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
|
bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||||
IOStream * in = pIOHandler->Open(pFile);
|
IOStream *in = pIOHandler->Open(pFile);
|
||||||
if (nullptr == in) {
|
if (nullptr == in) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char s[32];
|
char s[32];
|
||||||
in->Read( s, sizeof(char), 32 );
|
in->Read(s, sizeof(char), 32);
|
||||||
|
|
||||||
pIOHandler->Close(in);
|
pIOHandler->Close(in);
|
||||||
|
|
||||||
return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
|
return strncmp(s, "ASSIMP.binary-dump.", 19) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Read(IOStream * stream) {
|
T Read(IOStream *stream) {
|
||||||
T t;
|
T t;
|
||||||
size_t res = stream->Read( &t, sizeof(T), 1 );
|
size_t res = stream->Read(&t, sizeof(T), 1);
|
||||||
if(res != 1)
|
if (res != 1) {
|
||||||
throw DeadlyImportError("Unexpected EOF");
|
throw DeadlyImportError("Unexpected EOF");
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiVector3D Read<aiVector3D>(IOStream * stream) {
|
aiVector3D Read<aiVector3D>(IOStream *stream) {
|
||||||
aiVector3D v;
|
aiVector3D v;
|
||||||
v.x = Read<float>(stream);
|
v.x = Read<ai_real>(stream);
|
||||||
v.y = Read<float>(stream);
|
v.y = Read<ai_real>(stream);
|
||||||
v.z = Read<float>(stream);
|
v.z = Read<ai_real>(stream);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiColor4D Read<aiColor4D>(IOStream * stream) {
|
aiColor4D Read<aiColor4D>(IOStream *stream) {
|
||||||
aiColor4D c;
|
aiColor4D c;
|
||||||
c.r = Read<float>(stream);
|
c.r = Read<ai_real>(stream);
|
||||||
c.g = Read<float>(stream);
|
c.g = Read<ai_real>(stream);
|
||||||
c.b = Read<float>(stream);
|
c.b = Read<ai_real>(stream);
|
||||||
c.a = Read<float>(stream);
|
c.a = Read<ai_real>(stream);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiQuaternion Read<aiQuaternion>(IOStream * stream) {
|
aiQuaternion Read<aiQuaternion>(IOStream *stream) {
|
||||||
aiQuaternion v;
|
aiQuaternion v;
|
||||||
v.w = Read<float>(stream);
|
v.w = Read<ai_real>(stream);
|
||||||
v.x = Read<float>(stream);
|
v.x = Read<ai_real>(stream);
|
||||||
v.y = Read<float>(stream);
|
v.y = Read<ai_real>(stream);
|
||||||
v.z = Read<float>(stream);
|
v.z = Read<ai_real>(stream);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiString Read<aiString>(IOStream * stream) {
|
aiString Read<aiString>(IOStream *stream) {
|
||||||
aiString s;
|
aiString s;
|
||||||
stream->Read(&s.length,4,1);
|
stream->Read(&s.length, 4, 1);
|
||||||
if(s.length)
|
if (s.length) {
|
||||||
stream->Read(s.data,s.length,1);
|
stream->Read(s.data, s.length, 1);
|
||||||
|
}
|
||||||
s.data[s.length] = 0;
|
s.data[s.length] = 0;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiVertexWeight Read<aiVertexWeight>(IOStream * stream) {
|
aiVertexWeight Read<aiVertexWeight>(IOStream *stream) {
|
||||||
aiVertexWeight w;
|
aiVertexWeight w;
|
||||||
w.mVertexId = Read<unsigned int>(stream);
|
w.mVertexId = Read<unsigned int>(stream);
|
||||||
w.mWeight = Read<float>(stream);
|
w.mWeight = Read<ai_real>(stream);
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
|
aiMatrix4x4 Read<aiMatrix4x4>(IOStream *stream) {
|
||||||
aiMatrix4x4 m;
|
aiMatrix4x4 m;
|
||||||
for (unsigned int i = 0; i < 4;++i) {
|
for (unsigned int i = 0; i < 4; ++i) {
|
||||||
for (unsigned int i2 = 0; i2 < 4;++i2) {
|
for (unsigned int i2 = 0; i2 < 4; ++i2) {
|
||||||
m[i][i2] = Read<float>(stream);
|
m[i][i2] = Read<ai_real>(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
|
@ -176,7 +177,7 @@ aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiVectorKey Read<aiVectorKey>(IOStream * stream) {
|
aiVectorKey Read<aiVectorKey>(IOStream *stream) {
|
||||||
aiVectorKey v;
|
aiVectorKey v;
|
||||||
v.mTime = Read<double>(stream);
|
v.mTime = Read<double>(stream);
|
||||||
v.mValue = Read<aiVector3D>(stream);
|
v.mValue = Read<aiVector3D>(stream);
|
||||||
|
@ -185,7 +186,7 @@ aiVectorKey Read<aiVectorKey>(IOStream * stream) {
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
aiQuatKey Read<aiQuatKey>(IOStream * stream) {
|
aiQuatKey Read<aiQuatKey>(IOStream *stream) {
|
||||||
aiQuatKey v;
|
aiQuatKey v;
|
||||||
v.mTime = Read<double>(stream);
|
v.mTime = Read<double>(stream);
|
||||||
v.mValue = Read<aiQuaternion>(stream);
|
v.mValue = Read<aiQuaternion>(stream);
|
||||||
|
@ -194,27 +195,27 @@ aiQuatKey Read<aiQuatKey>(IOStream * stream) {
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ReadArray( IOStream *stream, T * out, unsigned int size) {
|
void ReadArray(IOStream *stream, T *out, unsigned int size) {
|
||||||
ai_assert( nullptr != stream );
|
ai_assert(nullptr != stream);
|
||||||
ai_assert( nullptr != out );
|
ai_assert(nullptr != out);
|
||||||
|
|
||||||
for (unsigned int i=0; i<size; i++) {
|
for (unsigned int i = 0; i < size; i++) {
|
||||||
out[i] = Read<T>(stream);
|
out[i] = Read<T>(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) {
|
void ReadBounds(IOStream *stream, T * /*p*/, unsigned int n) {
|
||||||
// not sure what to do here, the data isn't really useful.
|
// not sure what to do here, the data isn't really useful.
|
||||||
stream->Seek( sizeof(T) * n, aiOrigin_CUR );
|
stream->Seek(sizeof(T) * n, aiOrigin_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* parent ) {
|
void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
std::unique_ptr<aiNode> node(new aiNode());
|
std::unique_ptr<aiNode> node(new aiNode());
|
||||||
|
|
||||||
|
@ -222,14 +223,13 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
||||||
node->mTransformation = Read<aiMatrix4x4>(stream);
|
node->mTransformation = Read<aiMatrix4x4>(stream);
|
||||||
unsigned numChildren = Read<unsigned int>(stream);
|
unsigned numChildren = Read<unsigned int>(stream);
|
||||||
unsigned numMeshes = Read<unsigned int>(stream);
|
unsigned numMeshes = Read<unsigned int>(stream);
|
||||||
unsigned int nb_metadata = Read<unsigned int>(stream);
|
unsigned int nb_metadata = Read<unsigned int>(stream);
|
||||||
|
|
||||||
if(parent) {
|
if (parent) {
|
||||||
node->mParent = parent;
|
node->mParent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numMeshes)
|
if (numMeshes) {
|
||||||
{
|
|
||||||
node->mMeshes = new unsigned int[numMeshes];
|
node->mMeshes = new unsigned int[numMeshes];
|
||||||
for (unsigned int i = 0; i < numMeshes; ++i) {
|
for (unsigned int i = 0; i < numMeshes; ++i) {
|
||||||
node->mMeshes[i] = Read<unsigned int>(stream);
|
node->mMeshes[i] = Read<unsigned int>(stream);
|
||||||
|
@ -238,60 +238,60 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numChildren) {
|
if (numChildren) {
|
||||||
node->mChildren = new aiNode*[numChildren];
|
node->mChildren = new aiNode *[numChildren];
|
||||||
for (unsigned int i = 0; i < numChildren; ++i) {
|
for (unsigned int i = 0; i < numChildren; ++i) {
|
||||||
ReadBinaryNode( stream, &node->mChildren[i], node.get() );
|
ReadBinaryNode(stream, &node->mChildren[i], node.get());
|
||||||
node->mNumChildren++;
|
node->mNumChildren++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nb_metadata > 0 ) {
|
if (nb_metadata > 0) {
|
||||||
node->mMetaData = aiMetadata::Alloc(nb_metadata);
|
node->mMetaData = aiMetadata::Alloc(nb_metadata);
|
||||||
for (unsigned int i = 0; i < nb_metadata; ++i) {
|
for (unsigned int i = 0; i < nb_metadata; ++i) {
|
||||||
node->mMetaData->mKeys[i] = Read<aiString>(stream);
|
node->mMetaData->mKeys[i] = Read<aiString>(stream);
|
||||||
node->mMetaData->mValues[i].mType = (aiMetadataType) Read<uint16_t>(stream);
|
node->mMetaData->mValues[i].mType = (aiMetadataType)Read<uint16_t>(stream);
|
||||||
void* data = nullptr;
|
void *data = nullptr;
|
||||||
|
|
||||||
switch (node->mMetaData->mValues[i].mType) {
|
switch (node->mMetaData->mValues[i].mType) {
|
||||||
case AI_BOOL:
|
case AI_BOOL:
|
||||||
data = new bool(Read<bool>(stream));
|
data = new bool(Read<bool>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_INT32:
|
case AI_INT32:
|
||||||
data = new int32_t(Read<int32_t>(stream));
|
data = new int32_t(Read<int32_t>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_UINT64:
|
case AI_UINT64:
|
||||||
data = new uint64_t(Read<uint64_t>(stream));
|
data = new uint64_t(Read<uint64_t>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_FLOAT:
|
case AI_FLOAT:
|
||||||
data = new float(Read<float>(stream));
|
data = new ai_real(Read<ai_real>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_DOUBLE:
|
case AI_DOUBLE:
|
||||||
data = new double(Read<double>(stream));
|
data = new double(Read<double>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_AISTRING:
|
case AI_AISTRING:
|
||||||
data = new aiString(Read<aiString>(stream));
|
data = new aiString(Read<aiString>(stream));
|
||||||
break;
|
break;
|
||||||
case AI_AIVECTOR3D:
|
case AI_AIVECTOR3D:
|
||||||
data = new aiVector3D(Read<aiVector3D>(stream));
|
data = new aiVector3D(Read<aiVector3D>(stream));
|
||||||
break;
|
break;
|
||||||
#ifndef SWIG
|
#ifndef SWIG
|
||||||
case FORCE_32BIT:
|
case FORCE_32BIT:
|
||||||
#endif // SWIG
|
#endif // SWIG
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->mMetaData->mValues[i].mData = data;
|
node->mMetaData->mValues[i].mData = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*onode = node.release();
|
*onode = node.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) {
|
void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
b->mName = Read<aiString>(stream);
|
b->mName = Read<aiString>(stream);
|
||||||
b->mNumWeights = Read<unsigned int>(stream);
|
b->mNumWeights = Read<unsigned int>(stream);
|
||||||
|
@ -300,23 +300,24 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) {
|
||||||
// for the moment we write dumb min/max values for the bones, too.
|
// for the moment we write dumb min/max values for the bones, too.
|
||||||
// maybe I'll add a better, hash-like solution later
|
// maybe I'll add a better, hash-like solution later
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,b->mWeights,b->mNumWeights);
|
ReadBounds(stream, b->mWeights, b->mNumWeights);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
b->mWeights = new aiVertexWeight[b->mNumWeights];
|
b->mWeights = new aiVertexWeight[b->mNumWeights];
|
||||||
ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
|
ReadArray<aiVertexWeight>(stream, b->mWeights, b->mNumWeights);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
static bool fitsIntoUI16(unsigned int mNumVertices) {
|
static bool fitsIntoUI16(unsigned int mNumVertices) {
|
||||||
return ( mNumVertices < (1u<<16) );
|
return (mNumVertices < (1u << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
mesh->mPrimitiveTypes = Read<unsigned int>(stream);
|
mesh->mPrimitiveTypes = Read<unsigned int>(stream);
|
||||||
mesh->mNumVertices = Read<unsigned int>(stream);
|
mesh->mNumVertices = Read<unsigned int>(stream);
|
||||||
|
@ -329,48 +330,48 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
||||||
|
|
||||||
if (c & ASSBIN_MESH_HAS_POSITIONS) {
|
if (c & ASSBIN_MESH_HAS_POSITIONS) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
|
ReadBounds(stream, mesh->mVertices, mesh->mNumVertices);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||||
ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
|
ReadArray<aiVector3D>(stream, mesh->mVertices, mesh->mNumVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c & ASSBIN_MESH_HAS_NORMALS) {
|
if (c & ASSBIN_MESH_HAS_NORMALS) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
|
ReadBounds(stream, mesh->mNormals, mesh->mNumVertices);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||||
ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
|
ReadArray<aiVector3D>(stream, mesh->mNormals, mesh->mNumVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
|
if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
|
ReadBounds(stream, mesh->mTangents, mesh->mNumVertices);
|
||||||
ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
|
ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
mesh->mTangents = new aiVector3D[mesh->mNumVertices];
|
mesh->mTangents = new aiVector3D[mesh->mNumVertices];
|
||||||
ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
|
ReadArray<aiVector3D>(stream, mesh->mTangents, mesh->mNumVertices);
|
||||||
mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
|
mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
|
||||||
ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
|
ReadArray<aiVector3D>(stream, mesh->mBitangents, mesh->mNumVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) {
|
||||||
if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
|
if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
|
ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
|
mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
|
||||||
ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
|
ReadArray<aiColor4D>(stream, mesh->mColors[n], mesh->mNumVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
|
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) {
|
||||||
if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
|
if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -379,11 +380,11 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
||||||
mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
|
mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
|
||||||
|
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
|
ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
|
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
|
||||||
ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
|
ReadArray<aiVector3D>(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,20 +394,20 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
||||||
// using Assimp's standard hashing function.
|
// using Assimp's standard hashing function.
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
Read<unsigned int>(stream);
|
Read<unsigned int>(stream);
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
|
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
|
||||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
|
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||||
aiFace& f = mesh->mFaces[i];
|
aiFace &f = mesh->mFaces[i];
|
||||||
|
|
||||||
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
|
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
|
||||||
f.mNumIndices = Read<uint16_t>(stream);
|
f.mNumIndices = Read<uint16_t>(stream);
|
||||||
f.mIndices = new unsigned int[f.mNumIndices];
|
f.mIndices = new unsigned int[f.mNumIndices];
|
||||||
|
|
||||||
for (unsigned int a = 0; a < f.mNumIndices;++a) {
|
for (unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||||
// Check if unsigned short ( 16 bit ) are big enought for the indices
|
// Check if unsigned short ( 16 bit ) are big enought for the indices
|
||||||
if ( fitsIntoUI16( mesh->mNumVertices ) ) {
|
if (fitsIntoUI16(mesh->mNumVertices)) {
|
||||||
f.mIndices[a] = Read<uint16_t>(stream);
|
f.mIndices[a] = Read<uint16_t>(stream);
|
||||||
} else {
|
} else {
|
||||||
f.mIndices[a] = Read<unsigned int>(stream);
|
f.mIndices[a] = Read<unsigned int>(stream);
|
||||||
|
@ -417,19 +418,19 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
||||||
|
|
||||||
// write bones
|
// write bones
|
||||||
if (mesh->mNumBones) {
|
if (mesh->mNumBones) {
|
||||||
mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
|
mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones];
|
||||||
for (unsigned int a = 0; a < mesh->mNumBones;++a) {
|
for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
|
||||||
mesh->mBones[a] = new aiBone();
|
mesh->mBones[a] = new aiBone();
|
||||||
ReadBinaryBone(stream,mesh->mBones[a]);
|
ReadBinaryBone(stream, mesh->mBones[a]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) {
|
void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
prop->mKey = Read<aiString>(stream);
|
prop->mKey = Read<aiString>(stream);
|
||||||
prop->mSemantic = Read<unsigned int>(stream);
|
prop->mSemantic = Read<unsigned int>(stream);
|
||||||
|
@ -437,36 +438,34 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro
|
||||||
|
|
||||||
prop->mDataLength = Read<unsigned int>(stream);
|
prop->mDataLength = Read<unsigned int>(stream);
|
||||||
prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
|
prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
|
||||||
prop->mData = new char [ prop->mDataLength ];
|
prop->mData = new char[prop->mDataLength];
|
||||||
stream->Read(prop->mData,1,prop->mDataLength);
|
stream->Read(prop->mData, 1, prop->mDataLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) {
|
void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
|
mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
|
||||||
if (mat->mNumProperties)
|
if (mat->mNumProperties) {
|
||||||
{
|
if (mat->mProperties) {
|
||||||
if (mat->mProperties)
|
|
||||||
{
|
|
||||||
delete[] mat->mProperties;
|
delete[] mat->mProperties;
|
||||||
}
|
}
|
||||||
mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
|
mat->mProperties = new aiMaterialProperty *[mat->mNumProperties];
|
||||||
for (unsigned int i = 0; i < mat->mNumProperties;++i) {
|
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
||||||
mat->mProperties[i] = new aiMaterialProperty();
|
mat->mProperties[i] = new aiMaterialProperty();
|
||||||
ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
|
ReadBinaryMaterialProperty(stream, mat->mProperties[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) {
|
void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
nd->mNodeName = Read<aiString>(stream);
|
nd->mNodeName = Read<aiString>(stream);
|
||||||
nd->mNumPositionKeys = Read<unsigned int>(stream);
|
nd->mNumPositionKeys = Read<unsigned int>(stream);
|
||||||
|
@ -477,82 +476,82 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) {
|
||||||
|
|
||||||
if (nd->mNumPositionKeys) {
|
if (nd->mNumPositionKeys) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
|
ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||||
|
|
||||||
} // else write as usual
|
} // else write as usual
|
||||||
else {
|
else {
|
||||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||||
ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
|
ReadArray<aiVectorKey>(stream, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nd->mNumRotationKeys) {
|
if (nd->mNumRotationKeys) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
|
ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
|
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
|
||||||
ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
|
ReadArray<aiQuatKey>(stream, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nd->mNumScalingKeys) {
|
if (nd->mNumScalingKeys) {
|
||||||
if (shortened) {
|
if (shortened) {
|
||||||
ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
|
ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// else write as usual
|
// else write as usual
|
||||||
nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
|
nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
|
||||||
ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
|
ReadArray<aiVectorKey>(stream, nd->mScalingKeys, nd->mNumScalingKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) {
|
void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
anim->mName = Read<aiString> (stream);
|
anim->mName = Read<aiString>(stream);
|
||||||
anim->mDuration = Read<double> (stream);
|
anim->mDuration = Read<double>(stream);
|
||||||
anim->mTicksPerSecond = Read<double> (stream);
|
anim->mTicksPerSecond = Read<double>(stream);
|
||||||
anim->mNumChannels = Read<unsigned int>(stream);
|
anim->mNumChannels = Read<unsigned int>(stream);
|
||||||
|
|
||||||
if (anim->mNumChannels) {
|
if (anim->mNumChannels) {
|
||||||
anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
|
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
|
||||||
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
|
for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
|
||||||
anim->mChannels[a] = new aiNodeAnim();
|
anim->mChannels[a] = new aiNodeAnim();
|
||||||
ReadBinaryNodeAnim(stream,anim->mChannels[a]);
|
ReadBinaryNodeAnim(stream, anim->mChannels[a]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) {
|
void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
tex->mWidth = Read<unsigned int>(stream);
|
tex->mWidth = Read<unsigned int>(stream);
|
||||||
tex->mHeight = Read<unsigned int>(stream);
|
tex->mHeight = Read<unsigned int>(stream);
|
||||||
stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 );
|
stream->Read(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1);
|
||||||
|
|
||||||
if(!shortened) {
|
if (!shortened) {
|
||||||
if (!tex->mHeight) {
|
if (!tex->mHeight) {
|
||||||
tex->pcData = new aiTexel[ tex->mWidth ];
|
tex->pcData = new aiTexel[tex->mWidth];
|
||||||
stream->Read(tex->pcData,1,tex->mWidth);
|
stream->Read(tex->pcData, 1, tex->mWidth);
|
||||||
} else {
|
} else {
|
||||||
tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
|
tex->pcData = new aiTexel[tex->mWidth * tex->mHeight];
|
||||||
stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
|
stream->Read(tex->pcData, 1, tex->mWidth * tex->mHeight * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
|
void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
l->mName = Read<aiString>(stream);
|
l->mName = Read<aiString>(stream);
|
||||||
l->mType = (aiLightSourceType)Read<unsigned int>(stream);
|
l->mType = (aiLightSourceType)Read<unsigned int>(stream);
|
||||||
|
@ -574,10 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
|
void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
cam->mName = Read<aiString>(stream);
|
cam->mName = Read<aiString>(stream);
|
||||||
cam->mPosition = Read<aiVector3D>(stream);
|
cam->mPosition = Read<aiVector3D>(stream);
|
||||||
|
@ -590,141 +589,139 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
|
void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
|
||||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
|
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
|
||||||
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
throw DeadlyImportError("Magic chunk identifiers are wrong!");
|
||||||
/*uint32_t size =*/ Read<uint32_t>(stream);
|
/*uint32_t size =*/Read<uint32_t>(stream);
|
||||||
|
|
||||||
scene->mFlags = Read<unsigned int>(stream);
|
scene->mFlags = Read<unsigned int>(stream);
|
||||||
scene->mNumMeshes = Read<unsigned int>(stream);
|
scene->mNumMeshes = Read<unsigned int>(stream);
|
||||||
scene->mNumMaterials = Read<unsigned int>(stream);
|
scene->mNumMaterials = Read<unsigned int>(stream);
|
||||||
scene->mNumAnimations = Read<unsigned int>(stream);
|
scene->mNumAnimations = Read<unsigned int>(stream);
|
||||||
scene->mNumTextures = Read<unsigned int>(stream);
|
scene->mNumTextures = Read<unsigned int>(stream);
|
||||||
scene->mNumLights = Read<unsigned int>(stream);
|
scene->mNumLights = Read<unsigned int>(stream);
|
||||||
scene->mNumCameras = Read<unsigned int>(stream);
|
scene->mNumCameras = Read<unsigned int>(stream);
|
||||||
|
|
||||||
// Read node graph
|
// Read node graph
|
||||||
//scene->mRootNode = new aiNode[1];
|
//scene->mRootNode = new aiNode[1];
|
||||||
ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL );
|
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL);
|
||||||
|
|
||||||
// Read all meshes
|
// Read all meshes
|
||||||
if (scene->mNumMeshes) {
|
if (scene->mNumMeshes) {
|
||||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes];
|
scene->mMeshes = new aiMesh *[scene->mNumMeshes];
|
||||||
memset(scene->mMeshes, 0, scene->mNumMeshes*sizeof(aiMesh*));
|
memset(scene->mMeshes, 0, scene->mNumMeshes * sizeof(aiMesh *));
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||||
scene->mMeshes[i] = new aiMesh();
|
scene->mMeshes[i] = new aiMesh();
|
||||||
ReadBinaryMesh( stream,scene->mMeshes[i]);
|
ReadBinaryMesh(stream, scene->mMeshes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read materials
|
// Read materials
|
||||||
if (scene->mNumMaterials) {
|
if (scene->mNumMaterials) {
|
||||||
scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
|
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
|
||||||
memset(scene->mMaterials, 0, scene->mNumMaterials*sizeof(aiMaterial*));
|
memset(scene->mMaterials, 0, scene->mNumMaterials * sizeof(aiMaterial *));
|
||||||
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
|
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||||
scene->mMaterials[i] = new aiMaterial();
|
scene->mMaterials[i] = new aiMaterial();
|
||||||
ReadBinaryMaterial(stream,scene->mMaterials[i]);
|
ReadBinaryMaterial(stream, scene->mMaterials[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read all animations
|
// Read all animations
|
||||||
if (scene->mNumAnimations) {
|
if (scene->mNumAnimations) {
|
||||||
scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
|
scene->mAnimations = new aiAnimation *[scene->mNumAnimations];
|
||||||
memset(scene->mAnimations, 0, scene->mNumAnimations*sizeof(aiAnimation*));
|
memset(scene->mAnimations, 0, scene->mNumAnimations * sizeof(aiAnimation *));
|
||||||
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
|
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||||
scene->mAnimations[i] = new aiAnimation();
|
scene->mAnimations[i] = new aiAnimation();
|
||||||
ReadBinaryAnim(stream,scene->mAnimations[i]);
|
ReadBinaryAnim(stream, scene->mAnimations[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read all textures
|
// Read all textures
|
||||||
if (scene->mNumTextures) {
|
if (scene->mNumTextures) {
|
||||||
scene->mTextures = new aiTexture*[scene->mNumTextures];
|
scene->mTextures = new aiTexture *[scene->mNumTextures];
|
||||||
memset(scene->mTextures, 0, scene->mNumTextures*sizeof(aiTexture*));
|
memset(scene->mTextures, 0, scene->mNumTextures * sizeof(aiTexture *));
|
||||||
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
|
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
|
||||||
scene->mTextures[i] = new aiTexture();
|
scene->mTextures[i] = new aiTexture();
|
||||||
ReadBinaryTexture(stream,scene->mTextures[i]);
|
ReadBinaryTexture(stream, scene->mTextures[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read lights
|
// Read lights
|
||||||
if (scene->mNumLights) {
|
if (scene->mNumLights) {
|
||||||
scene->mLights = new aiLight*[scene->mNumLights];
|
scene->mLights = new aiLight *[scene->mNumLights];
|
||||||
memset(scene->mLights, 0, scene->mNumLights*sizeof(aiLight*));
|
memset(scene->mLights, 0, scene->mNumLights * sizeof(aiLight *));
|
||||||
for (unsigned int i = 0; i < scene->mNumLights;++i) {
|
for (unsigned int i = 0; i < scene->mNumLights; ++i) {
|
||||||
scene->mLights[i] = new aiLight();
|
scene->mLights[i] = new aiLight();
|
||||||
ReadBinaryLight(stream,scene->mLights[i]);
|
ReadBinaryLight(stream, scene->mLights[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read cameras
|
// Read cameras
|
||||||
if (scene->mNumCameras) {
|
if (scene->mNumCameras) {
|
||||||
scene->mCameras = new aiCamera*[scene->mNumCameras];
|
scene->mCameras = new aiCamera *[scene->mNumCameras];
|
||||||
memset(scene->mCameras, 0, scene->mNumCameras*sizeof(aiCamera*));
|
memset(scene->mCameras, 0, scene->mNumCameras * sizeof(aiCamera *));
|
||||||
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
|
for (unsigned int i = 0; i < scene->mNumCameras; ++i) {
|
||||||
scene->mCameras[i] = new aiCamera();
|
scene->mCameras[i] = new aiCamera();
|
||||||
ReadBinaryCamera(stream,scene->mCameras[i]);
|
ReadBinaryCamera(stream, scene->mCameras[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) {
|
void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
IOStream * stream = pIOHandler->Open(pFile,"rb");
|
IOStream *stream = pIOHandler->Open(pFile, "rb");
|
||||||
if (nullptr == stream) {
|
if (nullptr == stream) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// signature
|
// signature
|
||||||
stream->Seek( 44, aiOrigin_CUR );
|
stream->Seek(44, aiOrigin_CUR);
|
||||||
|
|
||||||
unsigned int versionMajor = Read<unsigned int>(stream);
|
unsigned int versionMajor = Read<unsigned int>(stream);
|
||||||
unsigned int versionMinor = Read<unsigned int>(stream);
|
unsigned int versionMinor = Read<unsigned int>(stream);
|
||||||
if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
|
if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
|
||||||
throw DeadlyImportError( "Invalid version, data format not compatible!" );
|
throw DeadlyImportError("Invalid version, data format not compatible!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*unsigned int versionRevision =*/ Read<unsigned int>(stream);
|
/*unsigned int versionRevision =*/Read<unsigned int>(stream);
|
||||||
/*unsigned int compileFlags =*/ Read<unsigned int>(stream);
|
/*unsigned int compileFlags =*/Read<unsigned int>(stream);
|
||||||
|
|
||||||
shortened = Read<uint16_t>(stream) > 0;
|
shortened = Read<uint16_t>(stream) > 0;
|
||||||
compressed = Read<uint16_t>(stream) > 0;
|
compressed = Read<uint16_t>(stream) > 0;
|
||||||
|
|
||||||
if (shortened)
|
if (shortened)
|
||||||
throw DeadlyImportError( "Shortened binaries are not supported!" );
|
throw DeadlyImportError("Shortened binaries are not supported!");
|
||||||
|
|
||||||
stream->Seek( 256, aiOrigin_CUR ); // original filename
|
stream->Seek(256, aiOrigin_CUR); // original filename
|
||||||
stream->Seek( 128, aiOrigin_CUR ); // options
|
stream->Seek(128, aiOrigin_CUR); // options
|
||||||
stream->Seek( 64, aiOrigin_CUR ); // padding
|
stream->Seek(64, aiOrigin_CUR); // padding
|
||||||
|
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
uLongf uncompressedSize = Read<uint32_t>(stream);
|
uLongf uncompressedSize = Read<uint32_t>(stream);
|
||||||
uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
|
uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
|
||||||
|
|
||||||
unsigned char * compressedData = new unsigned char[ compressedSize ];
|
unsigned char *compressedData = new unsigned char[compressedSize];
|
||||||
size_t len = stream->Read( compressedData, 1, compressedSize );
|
size_t len = stream->Read(compressedData, 1, compressedSize);
|
||||||
ai_assert(len == compressedSize);
|
ai_assert(len == compressedSize);
|
||||||
|
|
||||||
unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
|
unsigned char *uncompressedData = new unsigned char[uncompressedSize];
|
||||||
|
|
||||||
int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len );
|
int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len);
|
||||||
if(res != Z_OK)
|
if (res != Z_OK) {
|
||||||
{
|
delete[] uncompressedData;
|
||||||
delete [] uncompressedData;
|
delete[] compressedData;
|
||||||
delete [] compressedData;
|
|
||||||
pIOHandler->Close(stream);
|
pIOHandler->Close(stream);
|
||||||
throw DeadlyImportError("Zlib decompression failed.");
|
throw DeadlyImportError("Zlib decompression failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryIOStream io( uncompressedData, uncompressedSize );
|
MemoryIOStream io(uncompressedData, uncompressedSize);
|
||||||
|
|
||||||
ReadBinaryScene(&io,pScene);
|
ReadBinaryScene(&io, pScene);
|
||||||
|
|
||||||
delete[] uncompressedData;
|
delete[] uncompressedData;
|
||||||
delete[] compressedData;
|
delete[] compressedData;
|
||||||
} else {
|
} else {
|
||||||
ReadBinaryScene(stream,pScene);
|
ReadBinaryScene(stream, pScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
pIOHandler->Close(stream);
|
pIOHandler->Close(stream);
|
|
@ -9,6 +9,9 @@ For details, see http://sourceforge.net/projects/libb64
|
||||||
|
|
||||||
const int CHARS_PER_LINE = 72;
|
const int CHARS_PER_LINE = 72;
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4244)
|
||||||
|
|
||||||
void base64_init_encodestate(base64_encodestate* state_in)
|
void base64_init_encodestate(base64_encodestate* state_in)
|
||||||
{
|
{
|
||||||
state_in->step = step_A;
|
state_in->step = step_A;
|
||||||
|
@ -107,3 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||||
return (int)(codechar - code_out);
|
return (int)(codechar - code_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
|
@ -8,6 +8,10 @@ For details, see http://sourceforge.net/projects/libb64
|
||||||
#ifndef BASE64_CENCODE_H
|
#ifndef BASE64_CENCODE_H
|
||||||
#define BASE64_CENCODE_H
|
#define BASE64_CENCODE_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(disable : 4127 )
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
step_A, step_B, step_C
|
step_A, step_B, step_C
|
|
@ -9,30 +9,31 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
|
||||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||||
|
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/scene.h>
|
||||||
#include <assimp/Exporter.hpp>
|
#include <assimp/Exporter.hpp>
|
||||||
#include <assimp/IOStream.hpp>
|
#include <assimp/IOStream.hpp>
|
||||||
#include <assimp/IOSystem.hpp>
|
#include <assimp/IOSystem.hpp>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/Exceptional.h>
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <limits>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#define CURRENT_FORMAT_VERSION 100
|
#define CURRENT_FORMAT_VERSION 100
|
||||||
|
|
||||||
// grab scoped_ptr from assimp to avoid a dependency on boost.
|
// grab scoped_ptr from assimp to avoid a dependency on boost.
|
||||||
//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
|
//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
#include "mesh_splitter.h"
|
#include "mesh_splitter.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "cencode.h"
|
#include "cencode.h"
|
||||||
}
|
}
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
|
void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
|
||||||
|
|
||||||
// small utility class to simplify serializing the aiScene to Json
|
// small utility class to simplify serializing the aiScene to Json
|
||||||
class JSONWriter {
|
class JSONWriter {
|
||||||
|
@ -42,10 +43,8 @@ public:
|
||||||
Flag_WriteSpecialFloats = 0x2,
|
Flag_WriteSpecialFloats = 0x2,
|
||||||
};
|
};
|
||||||
|
|
||||||
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
|
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
|
||||||
: out(out)
|
out(out), first(), flags(flags) {
|
||||||
, first()
|
|
||||||
, flags(flags) {
|
|
||||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||||
buff.imbue(std::locale("C"));
|
buff.imbue(std::locale("C"));
|
||||||
}
|
}
|
||||||
|
@ -68,43 +67,43 @@ public:
|
||||||
indent.erase(indent.end() - 1);
|
indent.erase(indent.end() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key(const std::string& name) {
|
void Key(const std::string &name) {
|
||||||
AddIndentation();
|
AddIndentation();
|
||||||
Delimit();
|
Delimit();
|
||||||
buff << '\"' + name + "\": ";
|
buff << '\"' + name + "\": ";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Literal>
|
template <typename Literal>
|
||||||
void Element(const Literal& name) {
|
void Element(const Literal &name) {
|
||||||
AddIndentation();
|
AddIndentation();
|
||||||
Delimit();
|
Delimit();
|
||||||
|
|
||||||
LiteralToString(buff, name) << '\n';
|
LiteralToString(buff, name) << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Literal>
|
template <typename Literal>
|
||||||
void SimpleValue(const Literal& s) {
|
void SimpleValue(const Literal &s) {
|
||||||
LiteralToString(buff, s) << '\n';
|
LiteralToString(buff, s) << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleValue(const void* buffer, size_t len) {
|
void SimpleValue(const void *buffer, size_t len) {
|
||||||
base64_encodestate s;
|
base64_encodestate s;
|
||||||
base64_init_encodestate(&s);
|
base64_init_encodestate(&s);
|
||||||
|
|
||||||
char* const out = new char[std::max(len * 2, static_cast<size_t>(16u))];
|
char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
|
||||||
const int n = base64_encode_block(reinterpret_cast<const char*>(buffer), static_cast<int>(len), out, &s);
|
const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
|
||||||
out[n + base64_encode_blockend(out + n, &s)] = '\0';
|
cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
|
||||||
|
|
||||||
// base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
|
// base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
|
||||||
// (only escaped ones). Remove any newlines in out.
|
// (only escaped ones). Remove any newlines in out.
|
||||||
for (char* cur = out; *cur; ++cur) {
|
for (char *cur = cur_out; *cur; ++cur) {
|
||||||
if (*cur == '\n') {
|
if (*cur == '\n') {
|
||||||
*cur = ' ';
|
*cur = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buff << '\"' << out << "\"\n";
|
buff << '\"' << cur_out << "\"\n";
|
||||||
delete[] out;
|
delete[] cur_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartObj(bool is_element = false) {
|
void StartObj(bool is_element = false) {
|
||||||
|
@ -156,21 +155,20 @@ public:
|
||||||
void Delimit() {
|
void Delimit() {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
buff << ',';
|
buff << ',';
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buff << ' ';
|
buff << ' ';
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Literal>
|
template <typename Literal>
|
||||||
std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
|
std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
|
||||||
stream << s;
|
stream << s;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
|
std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
|
||||||
std::string t;
|
std::string t;
|
||||||
|
|
||||||
// escape backslashes and single quotes, both would render the JSON invalid if left as is
|
// escape backslashes and single quotes, both would render the JSON invalid if left as is
|
||||||
|
@ -189,10 +187,10 @@ private:
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream& LiteralToString(std::stringstream& stream, float f) {
|
std::stringstream &LiteralToString(std::stringstream &stream, float f) {
|
||||||
if (!std::numeric_limits<float>::is_iec559) {
|
if (!std::numeric_limits<float>::is_iec559) {
|
||||||
// on a non IEEE-754 platform, we make no assumptions about the representation or existence
|
// on a non IEEE-754 platform, we make no assumptions about the representation or existence
|
||||||
// of special floating-point numbers.
|
// of special floating-point numbers.
|
||||||
stream << f;
|
stream << f;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +226,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Assimp::IOStream& out;
|
Assimp::IOStream &out;
|
||||||
std::string indent, newline;
|
std::string indent, newline;
|
||||||
std::stringstream buff;
|
std::stringstream buff;
|
||||||
bool first;
|
bool first;
|
||||||
|
@ -236,7 +234,7 @@ private:
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
|
||||||
out.StartArray(is_elem);
|
out.StartArray(is_elem);
|
||||||
out.Element(ai.x);
|
out.Element(ai.x);
|
||||||
out.Element(ai.y);
|
out.Element(ai.y);
|
||||||
|
@ -244,7 +242,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
|
||||||
out.EndArray();
|
out.EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
|
||||||
out.StartArray(is_elem);
|
out.StartArray(is_elem);
|
||||||
out.Element(ai.w);
|
out.Element(ai.w);
|
||||||
out.Element(ai.x);
|
out.Element(ai.x);
|
||||||
|
@ -253,7 +251,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
|
||||||
out.EndArray();
|
out.EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
|
||||||
out.StartArray(is_elem);
|
out.StartArray(is_elem);
|
||||||
out.Element(ai.r);
|
out.Element(ai.r);
|
||||||
out.Element(ai.g);
|
out.Element(ai.g);
|
||||||
|
@ -261,7 +259,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
|
||||||
out.EndArray();
|
out.EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
|
||||||
out.StartArray(is_elem);
|
out.StartArray(is_elem);
|
||||||
for (unsigned int x = 0; x < 4; ++x) {
|
for (unsigned int x = 0; x < 4; ++x) {
|
||||||
for (unsigned int y = 0; y < 4; ++y) {
|
for (unsigned int y = 0; y < 4; ++y) {
|
||||||
|
@ -271,7 +269,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
|
||||||
out.EndArray();
|
out.EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -292,7 +290,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
|
||||||
out.StartArray(is_elem);
|
out.StartArray(is_elem);
|
||||||
for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
|
for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
|
||||||
out.Element(ai.mIndices[i]);
|
out.Element(ai.mIndices[i]);
|
||||||
|
@ -300,7 +298,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
|
||||||
out.EndArray();
|
out.EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -411,7 +409,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -441,13 +439,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("properties");
|
out.Key("properties");
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
|
for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
|
||||||
const aiMaterialProperty* const prop = ai.mProperties[i];
|
const aiMaterialProperty *const prop = ai.mProperties[i];
|
||||||
out.StartObj(true);
|
out.StartObj(true);
|
||||||
out.Key("key");
|
out.Key("key");
|
||||||
out.SimpleValue(prop->mKey);
|
out.SimpleValue(prop->mKey);
|
||||||
|
@ -461,46 +459,41 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
||||||
|
|
||||||
out.Key("value");
|
out.Key("value");
|
||||||
switch (prop->mType) {
|
switch (prop->mType) {
|
||||||
case aiPTI_Float:
|
case aiPTI_Float:
|
||||||
if (prop->mDataLength / sizeof(float) > 1) {
|
if (prop->mDataLength / sizeof(float) > 1) {
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) {
|
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
|
||||||
out.Element(reinterpret_cast<float*>(prop->mData)[i]);
|
out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
|
||||||
}
|
|
||||||
out.EndArray();
|
|
||||||
}
|
}
|
||||||
else {
|
out.EndArray();
|
||||||
out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
|
} else {
|
||||||
}
|
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case aiPTI_Integer:
|
case aiPTI_Integer:
|
||||||
if (prop->mDataLength / sizeof(int) > 1) {
|
if (prop->mDataLength / sizeof(int) > 1) {
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) {
|
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
|
||||||
out.Element(reinterpret_cast<int*>(prop->mData)[i]);
|
out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
|
||||||
}
|
|
||||||
out.EndArray();
|
|
||||||
} else {
|
|
||||||
out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
|
|
||||||
}
|
}
|
||||||
break;
|
out.EndArray();
|
||||||
|
} else {
|
||||||
|
out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case aiPTI_String:
|
case aiPTI_String: {
|
||||||
{
|
aiString s;
|
||||||
aiString s;
|
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
out.SimpleValue(s);
|
||||||
out.SimpleValue(s);
|
} break;
|
||||||
}
|
case aiPTI_Buffer: {
|
||||||
break;
|
// binary data is written as series of hex-encoded octets
|
||||||
case aiPTI_Buffer:
|
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||||
{
|
} break;
|
||||||
// binary data is written as series of hex-encoded octets
|
default:
|
||||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
assert(false);
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
|
@ -510,7 +503,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("width");
|
out.Key("width");
|
||||||
|
@ -525,13 +518,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
||||||
out.Key("data");
|
out.Key("data");
|
||||||
if (!ai.mHeight) {
|
if (!ai.mHeight) {
|
||||||
out.SimpleValue(ai.pcData, ai.mWidth);
|
out.SimpleValue(ai.pcData, ai.mWidth);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int y = 0; y < ai.mHeight; ++y) {
|
for (unsigned int y = 0; y < ai.mHeight; ++y) {
|
||||||
out.StartArray(true);
|
out.StartArray(true);
|
||||||
for (unsigned int x = 0; x < ai.mWidth; ++x) {
|
for (unsigned int x = 0; x < ai.mWidth; ++x) {
|
||||||
const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
|
const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
|
||||||
out.StartArray(true);
|
out.StartArray(true);
|
||||||
out.Element(static_cast<unsigned int>(tx.r));
|
out.Element(static_cast<unsigned int>(tx.r));
|
||||||
out.Element(static_cast<unsigned int>(tx.g));
|
out.Element(static_cast<unsigned int>(tx.g));
|
||||||
|
@ -547,7 +539,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
||||||
if (ai.mType != aiLightSource_POINT) {
|
if (ai.mType != aiLightSource_POINT) {
|
||||||
out.Key("direction");
|
out.Key("direction");
|
||||||
Write(out, ai.mDirection, false);
|
Write(out, ai.mDirection, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ai.mType != aiLightSource_DIRECTIONAL) {
|
if (ai.mType != aiLightSource_DIRECTIONAL) {
|
||||||
|
@ -596,7 +587,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -612,7 +603,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||||
out.Key("positionkeys");
|
out.Key("positionkeys");
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
|
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
|
||||||
const aiVectorKey& pos = ai.mPositionKeys[n];
|
const aiVectorKey &pos = ai.mPositionKeys[n];
|
||||||
out.StartArray(true);
|
out.StartArray(true);
|
||||||
out.Element(pos.mTime);
|
out.Element(pos.mTime);
|
||||||
Write(out, pos.mValue);
|
Write(out, pos.mValue);
|
||||||
|
@ -625,7 +616,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||||
out.Key("rotationkeys");
|
out.Key("rotationkeys");
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
|
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
|
||||||
const aiQuatKey& rot = ai.mRotationKeys[n];
|
const aiQuatKey &rot = ai.mRotationKeys[n];
|
||||||
out.StartArray(true);
|
out.StartArray(true);
|
||||||
out.Element(rot.mTime);
|
out.Element(rot.mTime);
|
||||||
Write(out, rot.mValue);
|
Write(out, rot.mValue);
|
||||||
|
@ -638,7 +629,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||||
out.Key("scalingkeys");
|
out.Key("scalingkeys");
|
||||||
out.StartArray();
|
out.StartArray();
|
||||||
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
|
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
|
||||||
const aiVectorKey& scl = ai.mScalingKeys[n];
|
const aiVectorKey &scl = ai.mScalingKeys[n];
|
||||||
out.StartArray(true);
|
out.StartArray(true);
|
||||||
out.Element(scl.mTime);
|
out.Element(scl.mTime);
|
||||||
Write(out, scl.mValue);
|
Write(out, scl.mValue);
|
||||||
|
@ -649,7 +640,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -670,7 +661,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
|
void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
|
||||||
out.StartObj(is_elem);
|
out.StartObj(is_elem);
|
||||||
|
|
||||||
out.Key("name");
|
out.Key("name");
|
||||||
|
@ -697,7 +688,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteFormatInfo(JSONWriter& out) {
|
void WriteFormatInfo(JSONWriter &out) {
|
||||||
out.StartObj();
|
out.StartObj();
|
||||||
out.Key("format");
|
out.Key("format");
|
||||||
out.SimpleValue("\"assimp2json\"");
|
out.SimpleValue("\"assimp2json\"");
|
||||||
|
@ -706,7 +697,7 @@ void WriteFormatInfo(JSONWriter& out) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(JSONWriter& out, const aiScene& ai) {
|
void Write(JSONWriter &out, const aiScene &ai) {
|
||||||
out.StartObj();
|
out.StartObj();
|
||||||
|
|
||||||
out.Key("__metadata__");
|
out.Key("__metadata__");
|
||||||
|
@ -774,15 +765,14 @@ void Write(JSONWriter& out, const aiScene& ai) {
|
||||||
out.EndObj();
|
out.EndObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
|
||||||
void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
|
|
||||||
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
|
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
|
||||||
if (!str) {
|
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
|
// get a copy of the scene so we can modify it
|
||||||
aiScene* scenecopy_tmp;
|
aiScene *scenecopy_tmp;
|
||||||
aiCopyScene(scene, &scenecopy_tmp);
|
aiCopyScene(scene, &scenecopy_tmp);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
|
||||||
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
|
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
|
||||||
Write(s, *scenecopy_tmp);
|
Write(s, *scenecopy_tmp);
|
||||||
|
|
||||||
}
|
} catch (...) {
|
||||||
catch (...) {
|
|
||||||
aiFreeScene(scenecopy_tmp);
|
aiFreeScene(scenecopy_tmp);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
aiFreeScene(scenecopy_tmp);
|
aiFreeScene(scenecopy_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
/** @file AssxmlExporter.cpp
|
||||||
|
* ASSXML exporter main code
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||||
|
|
||||||
|
#include "AssxmlFileWriter.h"
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
|
||||||
|
{
|
||||||
|
DumpSceneToAssxml(
|
||||||
|
pFile,
|
||||||
|
"\0", // command(s)
|
||||||
|
pIOSystem,
|
||||||
|
pScene,
|
||||||
|
false); // shortened?
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||||
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -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("<");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
out.Append(">");
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
out.Append("&");
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
out.Append(""");
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
out.Append("'");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out.data[out.length++] = in.data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.data[out.length] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Write a single node as text dump
|
||||||
|
static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
|
||||||
|
char prefix[512];
|
||||||
|
for (unsigned int i = 0; i < depth; ++i)
|
||||||
|
prefix[i] = '\t';
|
||||||
|
prefix[depth] = '\0';
|
||||||
|
|
||||||
|
const aiMatrix4x4 &m = node->mTransformation;
|
||||||
|
|
||||||
|
aiString name;
|
||||||
|
ConvertName(name, node->mName);
|
||||||
|
ioprintf(io, "%s<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("&"); break;
|
||||||
|
case '\"': buffer.append("""); break;
|
||||||
|
case '\'': buffer.append("'"); break;
|
||||||
|
case '<': buffer.append("<"); break;
|
||||||
|
case '>': buffer.append(">"); break;
|
||||||
|
default: buffer.append(&data[pos], 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Write a text model dump
|
||||||
|
static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) {
|
||||||
|
time_t tt = ::time(NULL);
|
||||||
|
#if _WIN32
|
||||||
|
tm *p = gmtime(&tt);
|
||||||
|
#else
|
||||||
|
struct tm now;
|
||||||
|
tm *p = gmtime_r(&tt, &now);
|
||||||
|
#endif
|
||||||
|
ai_assert(nullptr != p);
|
||||||
|
|
||||||
|
std::string c = cmd;
|
||||||
|
std::string::size_type s;
|
||||||
|
|
||||||
|
// https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632
|
||||||
|
// -- not allowed in XML comments
|
||||||
|
while ((s = c.find("--")) != std::string::npos) {
|
||||||
|
c[s] = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
// write header
|
||||||
|
std::string header(
|
||||||
|
"<?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
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file AssxmlFileWriter.h
|
||||||
|
* @brief Declaration of Assxml file writer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AI_ASSXMLFILEWRITER_H_INC
|
||||||
|
#define AI_ASSXMLFILEWRITER_H_INC
|
||||||
|
|
||||||
|
#include <assimp/defs.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
void ASSIMP_API DumpSceneToAssxml(
|
||||||
|
const char* pFile,
|
||||||
|
const char* cmd,
|
||||||
|
IOSystem* pIOSystem,
|
||||||
|
const aiScene* pScene,
|
||||||
|
bool shortened);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AI_ASSXMLFILEWRITER_H_INC
|
|
@ -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
|
|
@ -82,7 +82,7 @@ private:
|
||||||
std::string ReadString();
|
std::string ReadString();
|
||||||
std::string ReadChunk();
|
std::string ReadChunk();
|
||||||
void ExitChunk();
|
void ExitChunk();
|
||||||
unsigned ChunkSize();
|
size_t ChunkSize();
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T *to_array( const std::vector<T> &v );
|
T *to_array( const std::vector<T> &v );
|
||||||
|
@ -112,10 +112,10 @@ private:
|
||||||
|
|
||||||
void ReadBB3D( aiScene *scene );
|
void ReadBB3D( aiScene *scene );
|
||||||
|
|
||||||
unsigned _pos;
|
size_t _pos;
|
||||||
// unsigned _size;
|
// unsigned _size;
|
||||||
std::vector<unsigned char> _buf;
|
std::vector<unsigned char> _buf;
|
||||||
std::vector<unsigned> _stack;
|
std::vector<size_t> _stack;
|
||||||
|
|
||||||
std::vector<std::string> _textures;
|
std::vector<std::string> _textures;
|
||||||
std::vector<std::unique_ptr<aiMaterial> > _materials;
|
std::vector<std::unique_ptr<aiMaterial> > _materials;
|
|
@ -42,19 +42,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
|
||||||
|
|
||||||
#include "BVHLoader.h"
|
#include "BVHLoader.h"
|
||||||
#include <assimp/fast_atof.h>
|
|
||||||
#include <assimp/SkeletonMeshBuilder.h>
|
#include <assimp/SkeletonMeshBuilder.h>
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
#include <assimp/IOSystem.hpp>
|
#include <assimp/fast_atof.h>
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Formatter;
|
using namespace Assimp::Formatter;
|
||||||
|
@ -74,104 +73,98 @@ static const aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
BVHLoader::BVHLoader()
|
BVHLoader::BVHLoader() :
|
||||||
: mLine(),
|
mLine(),
|
||||||
mAnimTickDuration(),
|
mAnimTickDuration(),
|
||||||
mAnimNumFrames(),
|
mAnimNumFrames(),
|
||||||
noSkeletonMesh()
|
noSkeletonMesh() {}
|
||||||
{}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
BVHLoader::~BVHLoader()
|
BVHLoader::~BVHLoader() {}
|
||||||
{}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
|
bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
|
||||||
{
|
|
||||||
// check file extension
|
// check file extension
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
|
|
||||||
if( extension == "bvh")
|
if (extension == "bvh")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if ((!extension.length() || cs) && pIOHandler) {
|
if ((!extension.length() || cs) && pIOHandler) {
|
||||||
const char* tokens[] = {"HIERARCHY"};
|
const char *tokens[] = { "HIERARCHY" };
|
||||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
void BVHLoader::SetupProperties(const Importer *pImp) {
|
||||||
{
|
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Loader meta information
|
// Loader meta information
|
||||||
const aiImporterDesc* BVHLoader::GetInfo () const
|
const aiImporterDesc *BVHLoader::GetInfo() const {
|
||||||
{
|
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
{
|
|
||||||
mFileName = pFile;
|
mFileName = pFile;
|
||||||
|
|
||||||
// read file into memory
|
// read file into memory
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||||
if( file.get() == NULL)
|
if (file.get() == nullptr) {
|
||||||
throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
throw DeadlyImportError("Failed to open file " + pFile + ".");
|
||||||
|
}
|
||||||
|
|
||||||
size_t fileSize = file->FileSize();
|
size_t fileSize = file->FileSize();
|
||||||
if( fileSize == 0)
|
if (fileSize == 0) {
|
||||||
throw DeadlyImportError( "File is too small.");
|
throw DeadlyImportError("File is too small.");
|
||||||
|
}
|
||||||
|
|
||||||
mBuffer.resize( fileSize);
|
mBuffer.resize(fileSize);
|
||||||
file->Read( &mBuffer.front(), 1, fileSize);
|
file->Read(&mBuffer.front(), 1, fileSize);
|
||||||
|
|
||||||
// start reading
|
// start reading
|
||||||
mReader = mBuffer.begin();
|
mReader = mBuffer.begin();
|
||||||
mLine = 1;
|
mLine = 1;
|
||||||
ReadStructure( pScene);
|
ReadStructure(pScene);
|
||||||
|
|
||||||
if (!noSkeletonMesh) {
|
if (!noSkeletonMesh) {
|
||||||
// build a dummy mesh for the skeleton so that we see something at least
|
// build a dummy mesh for the skeleton so that we see something at least
|
||||||
SkeletonMeshBuilder meshBuilder( pScene);
|
SkeletonMeshBuilder meshBuilder(pScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct an animation from all the motion data we read
|
// construct an animation from all the motion data we read
|
||||||
CreateAnimation( pScene);
|
CreateAnimation(pScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the file
|
// Reads the file
|
||||||
void BVHLoader::ReadStructure( aiScene* pScene)
|
void BVHLoader::ReadStructure(aiScene *pScene) {
|
||||||
{
|
|
||||||
// first comes hierarchy
|
// first comes hierarchy
|
||||||
std::string header = GetNextToken();
|
std::string header = GetNextToken();
|
||||||
if( header != "HIERARCHY")
|
if (header != "HIERARCHY")
|
||||||
ThrowException( "Expected header string \"HIERARCHY\".");
|
ThrowException("Expected header string \"HIERARCHY\".");
|
||||||
ReadHierarchy( pScene);
|
ReadHierarchy(pScene);
|
||||||
|
|
||||||
// then comes the motion data
|
// then comes the motion data
|
||||||
std::string motion = GetNextToken();
|
std::string motion = GetNextToken();
|
||||||
if( motion != "MOTION")
|
if (motion != "MOTION")
|
||||||
ThrowException( "Expected beginning of motion data \"MOTION\".");
|
ThrowException("Expected beginning of motion data \"MOTION\".");
|
||||||
ReadMotion( pScene);
|
ReadMotion(pScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the hierarchy
|
// Reads the hierarchy
|
||||||
void BVHLoader::ReadHierarchy( aiScene* pScene)
|
void BVHLoader::ReadHierarchy(aiScene *pScene) {
|
||||||
{
|
|
||||||
std::string root = GetNextToken();
|
std::string root = GetNextToken();
|
||||||
if( root != "ROOT")
|
if (root != "ROOT")
|
||||||
ThrowException( "Expected root node \"ROOT\".");
|
ThrowException("Expected root node \"ROOT\".");
|
||||||
|
|
||||||
// Go read the hierarchy from here
|
// Go read the hierarchy from here
|
||||||
pScene->mRootNode = ReadNode();
|
pScene->mRootNode = ReadNode();
|
||||||
|
@ -179,73 +172,64 @@ void BVHLoader::ReadHierarchy( aiScene* pScene)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a node and recursively its childs and returns the created node;
|
// Reads a node and recursively its childs and returns the created node;
|
||||||
aiNode* BVHLoader::ReadNode()
|
aiNode *BVHLoader::ReadNode() {
|
||||||
{
|
|
||||||
// first token is name
|
// first token is name
|
||||||
std::string nodeName = GetNextToken();
|
std::string nodeName = GetNextToken();
|
||||||
if( nodeName.empty() || nodeName == "{")
|
if (nodeName.empty() || nodeName == "{")
|
||||||
ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." );
|
ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
|
||||||
|
|
||||||
// then an opening brace should follow
|
// then an opening brace should follow
|
||||||
std::string openBrace = GetNextToken();
|
std::string openBrace = GetNextToken();
|
||||||
if( openBrace != "{")
|
if (openBrace != "{")
|
||||||
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." );
|
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
||||||
|
|
||||||
// Create a node
|
// Create a node
|
||||||
aiNode* node = new aiNode( nodeName);
|
aiNode *node = new aiNode(nodeName);
|
||||||
std::vector<aiNode*> childNodes;
|
std::vector<aiNode *> childNodes;
|
||||||
|
|
||||||
// and create an bone entry for it
|
// and create an bone entry for it
|
||||||
mNodes.push_back( Node( node));
|
mNodes.push_back(Node(node));
|
||||||
Node& internNode = mNodes.back();
|
Node &internNode = mNodes.back();
|
||||||
|
|
||||||
// now read the node's contents
|
// now read the node's contents
|
||||||
std::string siteToken;
|
std::string siteToken;
|
||||||
while( 1)
|
while (1) {
|
||||||
{
|
|
||||||
std::string token = GetNextToken();
|
std::string token = GetNextToken();
|
||||||
|
|
||||||
// node offset to parent node
|
// node offset to parent node
|
||||||
if( token == "OFFSET")
|
if (token == "OFFSET")
|
||||||
ReadNodeOffset( node);
|
ReadNodeOffset(node);
|
||||||
else if( token == "CHANNELS")
|
else if (token == "CHANNELS")
|
||||||
ReadNodeChannels( internNode);
|
ReadNodeChannels(internNode);
|
||||||
else if( token == "JOINT")
|
else if (token == "JOINT") {
|
||||||
{
|
|
||||||
// child node follows
|
// child node follows
|
||||||
aiNode* child = ReadNode();
|
aiNode *child = ReadNode();
|
||||||
child->mParent = node;
|
child->mParent = node;
|
||||||
childNodes.push_back( child);
|
childNodes.push_back(child);
|
||||||
}
|
} else if (token == "End") {
|
||||||
else if( token == "End")
|
|
||||||
{
|
|
||||||
// The real symbol is "End Site". Second part comes in a separate token
|
// The real symbol is "End Site". Second part comes in a separate token
|
||||||
siteToken.clear();
|
siteToken.clear();
|
||||||
siteToken = GetNextToken();
|
siteToken = GetNextToken();
|
||||||
if( siteToken != "Site")
|
if (siteToken != "Site")
|
||||||
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
|
ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
|
||||||
|
|
||||||
aiNode* child = ReadEndSite( nodeName);
|
aiNode *child = ReadEndSite(nodeName);
|
||||||
child->mParent = node;
|
child->mParent = node;
|
||||||
childNodes.push_back( child);
|
childNodes.push_back(child);
|
||||||
}
|
} else if (token == "}") {
|
||||||
else if( token == "}")
|
|
||||||
{
|
|
||||||
// we're done with that part of the hierarchy
|
// we're done with that part of the hierarchy
|
||||||
break;
|
break;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// everything else is a parse error
|
// everything else is a parse error
|
||||||
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
ThrowException(format() << "Unknown keyword \"" << token << "\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the child nodes if there are any
|
// add the child nodes if there are any
|
||||||
if( childNodes.size() > 0)
|
if (childNodes.size() > 0) {
|
||||||
{
|
|
||||||
node->mNumChildren = static_cast<unsigned int>(childNodes.size());
|
node->mNumChildren = static_cast<unsigned int>(childNodes.size());
|
||||||
node->mChildren = new aiNode*[node->mNumChildren];
|
node->mChildren = new aiNode *[node->mNumChildren];
|
||||||
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
|
std::copy(childNodes.begin(), childNodes.end(), node->mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and return the sub-hierarchy we built here
|
// and return the sub-hierarchy we built here
|
||||||
|
@ -254,31 +238,30 @@ aiNode* BVHLoader::ReadNode()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads an end node and returns the created node.
|
// Reads an end node and returns the created node.
|
||||||
aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
|
||||||
{
|
|
||||||
// check opening brace
|
// check opening brace
|
||||||
std::string openBrace = GetNextToken();
|
std::string openBrace = GetNextToken();
|
||||||
if( openBrace != "{")
|
if (openBrace != "{")
|
||||||
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
||||||
|
|
||||||
// Create a node
|
// Create a node
|
||||||
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
aiNode *node = new aiNode("EndSite_" + pParentName);
|
||||||
|
|
||||||
// now read the node's contents. Only possible entry is "OFFSET"
|
// now read the node's contents. Only possible entry is "OFFSET"
|
||||||
std::string token;
|
std::string token;
|
||||||
while( 1) {
|
while (1) {
|
||||||
token.clear();
|
token.clear();
|
||||||
token = GetNextToken();
|
token = GetNextToken();
|
||||||
|
|
||||||
// end node's offset
|
// end node's offset
|
||||||
if( token == "OFFSET") {
|
if (token == "OFFSET") {
|
||||||
ReadNodeOffset( node);
|
ReadNodeOffset(node);
|
||||||
} else if( token == "}") {
|
} else if (token == "}") {
|
||||||
// we're done with the end node
|
// we're done with the end node
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// everything else is a parse error
|
// everything else is a parse error
|
||||||
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
ThrowException(format() << "Unknown keyword \"" << token << "\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,8 +270,7 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a node offset for the given node
|
// Reads a node offset for the given node
|
||||||
void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
void BVHLoader::ReadNodeOffset(aiNode *pNode) {
|
||||||
{
|
|
||||||
// Offset consists of three floats to read
|
// Offset consists of three floats to read
|
||||||
aiVector3D offset;
|
aiVector3D offset;
|
||||||
offset.x = GetNextTokenAsFloat();
|
offset.x = GetNextTokenAsFloat();
|
||||||
|
@ -296,74 +278,69 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||||
offset.z = GetNextTokenAsFloat();
|
offset.z = GetNextTokenAsFloat();
|
||||||
|
|
||||||
// build a transformation matrix from it
|
// build a transformation matrix from it
|
||||||
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
|
pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x,
|
||||||
0.0f, 1.0f, 0.0f, offset.y,
|
0.0f, 1.0f, 0.0f, offset.y,
|
||||||
0.0f, 0.0f, 1.0f, offset.z,
|
0.0f, 0.0f, 1.0f, offset.z,
|
||||||
0.0f, 0.0f, 0.0f, 1.0f);
|
0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the animation channels for the given node
|
// Reads the animation channels for the given node
|
||||||
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
|
||||||
{
|
|
||||||
// number of channels. Use the float reader because we're lazy
|
// number of channels. Use the float reader because we're lazy
|
||||||
float numChannelsFloat = GetNextTokenAsFloat();
|
float numChannelsFloat = GetNextTokenAsFloat();
|
||||||
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
unsigned int numChannels = (unsigned int)numChannelsFloat;
|
||||||
|
|
||||||
for( unsigned int a = 0; a < numChannels; a++)
|
for (unsigned int a = 0; a < numChannels; a++) {
|
||||||
{
|
|
||||||
std::string channelToken = GetNextToken();
|
std::string channelToken = GetNextToken();
|
||||||
|
|
||||||
if( channelToken == "Xposition")
|
if (channelToken == "Xposition")
|
||||||
pNode.mChannels.push_back( Channel_PositionX);
|
pNode.mChannels.push_back(Channel_PositionX);
|
||||||
else if( channelToken == "Yposition")
|
else if (channelToken == "Yposition")
|
||||||
pNode.mChannels.push_back( Channel_PositionY);
|
pNode.mChannels.push_back(Channel_PositionY);
|
||||||
else if( channelToken == "Zposition")
|
else if (channelToken == "Zposition")
|
||||||
pNode.mChannels.push_back( Channel_PositionZ);
|
pNode.mChannels.push_back(Channel_PositionZ);
|
||||||
else if( channelToken == "Xrotation")
|
else if (channelToken == "Xrotation")
|
||||||
pNode.mChannels.push_back( Channel_RotationX);
|
pNode.mChannels.push_back(Channel_RotationX);
|
||||||
else if( channelToken == "Yrotation")
|
else if (channelToken == "Yrotation")
|
||||||
pNode.mChannels.push_back( Channel_RotationY);
|
pNode.mChannels.push_back(Channel_RotationY);
|
||||||
else if( channelToken == "Zrotation")
|
else if (channelToken == "Zrotation")
|
||||||
pNode.mChannels.push_back( Channel_RotationZ);
|
pNode.mChannels.push_back(Channel_RotationZ);
|
||||||
else
|
else
|
||||||
ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." );
|
ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the motion data
|
// Reads the motion data
|
||||||
void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
|
||||||
{
|
|
||||||
// Read number of frames
|
// Read number of frames
|
||||||
std::string tokenFrames = GetNextToken();
|
std::string tokenFrames = GetNextToken();
|
||||||
if( tokenFrames != "Frames:")
|
if (tokenFrames != "Frames:")
|
||||||
ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
|
ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
|
||||||
|
|
||||||
float numFramesFloat = GetNextTokenAsFloat();
|
float numFramesFloat = GetNextTokenAsFloat();
|
||||||
mAnimNumFrames = (unsigned int) numFramesFloat;
|
mAnimNumFrames = (unsigned int)numFramesFloat;
|
||||||
|
|
||||||
// Read frame duration
|
// Read frame duration
|
||||||
std::string tokenDuration1 = GetNextToken();
|
std::string tokenDuration1 = GetNextToken();
|
||||||
std::string tokenDuration2 = GetNextToken();
|
std::string tokenDuration2 = GetNextToken();
|
||||||
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||||
ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." );
|
ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
|
||||||
|
|
||||||
mAnimTickDuration = GetNextTokenAsFloat();
|
mAnimTickDuration = GetNextTokenAsFloat();
|
||||||
|
|
||||||
// resize value vectors for each node
|
// resize value vectors for each node
|
||||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||||
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
|
it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames);
|
||||||
|
|
||||||
// now read all the data and store it in the corresponding node's value vector
|
// now read all the data and store it in the corresponding node's value vector
|
||||||
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
|
for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) {
|
||||||
{
|
|
||||||
// on each line read the values for all nodes
|
// on each line read the values for all nodes
|
||||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) {
|
||||||
{
|
|
||||||
// get as many values as the node has channels
|
// get as many values as the node has channels
|
||||||
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
|
for (unsigned int c = 0; c < it->mChannels.size(); ++c)
|
||||||
it->mChannelValues.push_back( GetNextTokenAsFloat());
|
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
|
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
|
||||||
|
@ -372,16 +349,14 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Retrieves the next token
|
// Retrieves the next token
|
||||||
std::string BVHLoader::GetNextToken()
|
std::string BVHLoader::GetNextToken() {
|
||||||
{
|
|
||||||
// skip any preceding whitespace
|
// skip any preceding whitespace
|
||||||
while( mReader != mBuffer.end())
|
while (mReader != mBuffer.end()) {
|
||||||
{
|
if (!isspace(*mReader))
|
||||||
if( !isspace( *mReader))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// count lines
|
// count lines
|
||||||
if( *mReader == '\n')
|
if (*mReader == '\n')
|
||||||
mLine++;
|
mLine++;
|
||||||
|
|
||||||
++mReader;
|
++mReader;
|
||||||
|
@ -389,16 +364,15 @@ std::string BVHLoader::GetNextToken()
|
||||||
|
|
||||||
// collect all chars till the next whitespace. BVH is easy in respect to that.
|
// collect all chars till the next whitespace. BVH is easy in respect to that.
|
||||||
std::string token;
|
std::string token;
|
||||||
while( mReader != mBuffer.end())
|
while (mReader != mBuffer.end()) {
|
||||||
{
|
if (isspace(*mReader))
|
||||||
if( isspace( *mReader))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
token.push_back( *mReader);
|
token.push_back(*mReader);
|
||||||
++mReader;
|
++mReader;
|
||||||
|
|
||||||
// little extra logic to make sure braces are counted correctly
|
// little extra logic to make sure braces are counted correctly
|
||||||
if( token == "{" || token == "}")
|
if (token == "{" || token == "}")
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,111 +382,101 @@ std::string BVHLoader::GetNextToken()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the next token as a float
|
// Reads the next token as a float
|
||||||
float BVHLoader::GetNextTokenAsFloat()
|
float BVHLoader::GetNextTokenAsFloat() {
|
||||||
{
|
|
||||||
std::string token = GetNextToken();
|
std::string token = GetNextToken();
|
||||||
if( token.empty())
|
if (token.empty())
|
||||||
ThrowException( "Unexpected end of file while trying to read a float");
|
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
|
// check if the float is valid by testing if the atof() function consumed every char of the token
|
||||||
const char* ctoken = token.c_str();
|
const char *ctoken = token.c_str();
|
||||||
float result = 0.0f;
|
float result = 0.0f;
|
||||||
ctoken = fast_atoreal_move<float>( ctoken, result);
|
ctoken = fast_atoreal_move<float>(ctoken, result);
|
||||||
|
|
||||||
if( ctoken != token.c_str() + token.length())
|
if (ctoken != token.c_str() + token.length())
|
||||||
ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." );
|
ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Aborts the file reading with an exception
|
// Aborts the file reading with an exception
|
||||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
|
AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
|
||||||
{
|
throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
|
||||||
throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructs an animation for the motion data and stores it in the given scene
|
// Constructs an animation for the motion data and stores it in the given scene
|
||||||
void BVHLoader::CreateAnimation( aiScene* pScene)
|
void BVHLoader::CreateAnimation(aiScene *pScene) {
|
||||||
{
|
|
||||||
// create the animation
|
// create the animation
|
||||||
pScene->mNumAnimations = 1;
|
pScene->mNumAnimations = 1;
|
||||||
pScene->mAnimations = new aiAnimation*[1];
|
pScene->mAnimations = new aiAnimation *[1];
|
||||||
aiAnimation* anim = new aiAnimation;
|
aiAnimation *anim = new aiAnimation;
|
||||||
pScene->mAnimations[0] = anim;
|
pScene->mAnimations[0] = anim;
|
||||||
|
|
||||||
// put down the basic parameters
|
// put down the basic parameters
|
||||||
anim->mName.Set( "Motion");
|
anim->mName.Set("Motion");
|
||||||
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
|
anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration);
|
||||||
anim->mDuration = double( mAnimNumFrames - 1);
|
anim->mDuration = double(mAnimNumFrames - 1);
|
||||||
|
|
||||||
// now generate the tracks for all nodes
|
// now generate the tracks for all nodes
|
||||||
anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
|
anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
|
||||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
|
||||||
|
|
||||||
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
|
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
|
||||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
for (unsigned int i = 0; i < anim->mNumChannels; ++i)
|
||||||
anim->mChannels[i] = NULL;
|
anim->mChannels[i] = NULL;
|
||||||
|
|
||||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
for (unsigned int a = 0; a < anim->mNumChannels; a++) {
|
||||||
{
|
const Node &node = mNodes[a];
|
||||||
const Node& node = mNodes[a];
|
const std::string nodeName = std::string(node.mNode->mName.data);
|
||||||
const std::string nodeName = std::string( node.mNode->mName.data );
|
aiNodeAnim *nodeAnim = new aiNodeAnim;
|
||||||
aiNodeAnim* nodeAnim = new aiNodeAnim;
|
|
||||||
anim->mChannels[a] = nodeAnim;
|
anim->mChannels[a] = nodeAnim;
|
||||||
nodeAnim->mNodeName.Set( nodeName);
|
nodeAnim->mNodeName.Set(nodeName);
|
||||||
std::map<BVHLoader::ChannelType, int> channelMap;
|
std::map<BVHLoader::ChannelType, int> channelMap;
|
||||||
|
|
||||||
//Build map of channels
|
//Build map of channels
|
||||||
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
|
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
|
||||||
{
|
channelMap[node.mChannels[channel]] = channel;
|
||||||
channelMap[node.mChannels[channel]] = channel;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// translational part, if given
|
// translational part, if given
|
||||||
if( node.mChannels.size() == 6)
|
if (node.mChannels.size() == 6) {
|
||||||
{
|
|
||||||
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
||||||
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
||||||
aiVectorKey* poskey = nodeAnim->mPositionKeys;
|
aiVectorKey *poskey = nodeAnim->mPositionKeys;
|
||||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
|
||||||
{
|
poskey->mTime = double(fr);
|
||||||
poskey->mTime = double( fr);
|
|
||||||
|
|
||||||
// Now compute all translations
|
// Now compute all translations
|
||||||
for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
|
for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
|
||||||
{
|
//Find channel in node
|
||||||
//Find channel in node
|
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
||||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
|
||||||
|
|
||||||
if (mapIter == channelMap.end())
|
if (mapIter == channelMap.end())
|
||||||
throw DeadlyImportError("Missing position channel in node " + nodeName);
|
throw DeadlyImportError("Missing position channel in node " + nodeName);
|
||||||
else {
|
else {
|
||||||
int channelIdx = mapIter->second;
|
int channelIdx = mapIter->second;
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
case Channel_PositionX:
|
case Channel_PositionX:
|
||||||
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||||
break;
|
break;
|
||||||
case Channel_PositionY:
|
case Channel_PositionY:
|
||||||
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||||
break;
|
break;
|
||||||
case Channel_PositionZ:
|
case Channel_PositionZ:
|
||||||
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++poskey;
|
++poskey;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// if no translation part is given, put a default sequence
|
// if no translation part is given, put a default sequence
|
||||||
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
||||||
nodeAnim->mNumPositionKeys = 1;
|
nodeAnim->mNumPositionKeys = 1;
|
||||||
nodeAnim->mPositionKeys = new aiVectorKey[1];
|
nodeAnim->mPositionKeys = new aiVectorKey[1];
|
||||||
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
||||||
|
@ -525,42 +489,36 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
||||||
// Then create the number of rotation keys
|
// Then create the number of rotation keys
|
||||||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||||
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
|
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
|
||||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
|
||||||
{
|
|
||||||
aiMatrix4x4 temp;
|
aiMatrix4x4 temp;
|
||||||
aiMatrix3x3 rotMatrix;
|
aiMatrix3x3 rotMatrix;
|
||||||
for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
|
for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) {
|
||||||
{
|
switch (node.mChannels[channelIdx]) {
|
||||||
//Find channel in node
|
case Channel_RotationX:
|
||||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
{
|
||||||
|
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||||
if (mapIter == channelMap.end())
|
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
throw DeadlyImportError("Missing rotation channel in node " + nodeName);
|
}
|
||||||
else {
|
break;
|
||||||
int channelIdx = mapIter->second;
|
case Channel_RotationY:
|
||||||
// translate ZXY euler angels into a quaternion
|
{
|
||||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||||
|
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
// Compute rotation transformations in the right order
|
}
|
||||||
switch (channel)
|
break;
|
||||||
{
|
case Channel_RotationZ:
|
||||||
case Channel_RotationX:
|
{
|
||||||
aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||||
break;
|
aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
case Channel_RotationY:
|
}
|
||||||
aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
break;
|
||||||
break;
|
default:
|
||||||
case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
break;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rotkey->mTime = double(fr);
|
||||||
rotkey->mTime = double( fr);
|
rotkey->mValue = aiQuaternion(rotMatrix);
|
||||||
rotkey->mValue = aiQuaternion( rotMatrix);
|
|
||||||
++rotkey;
|
++rotkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,7 +528,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
||||||
nodeAnim->mNumScalingKeys = 1;
|
nodeAnim->mNumScalingKeys = 1;
|
||||||
nodeAnim->mScalingKeys = new aiVectorKey[1];
|
nodeAnim->mScalingKeys = new aiVectorKey[1];
|
||||||
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
||||||
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
|
nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
struct aiNode;
|
struct aiNode;
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
/** Loader class to read Motion Capturing data from a .bvh file.
|
/** 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
|
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
|
||||||
* inside the loader just to be able to see something.
|
* 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 */
|
/** Possible animation channels for which the motion data holds the values */
|
||||||
enum ChannelType
|
enum ChannelType {
|
||||||
{
|
|
||||||
Channel_PositionX,
|
Channel_PositionX,
|
||||||
Channel_PositionY,
|
Channel_PositionY,
|
||||||
Channel_PositionZ,
|
Channel_PositionZ,
|
||||||
|
@ -78,61 +75,57 @@ class BVHLoader : public BaseImporter
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
/** 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;
|
||||||
const aiNode* mNode;
|
|
||||||
std::vector<ChannelType> mChannels;
|
std::vector<ChannelType> mChannels;
|
||||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||||
|
|
||||||
Node()
|
Node() :
|
||||||
: mNode(nullptr)
|
mNode(nullptr) {}
|
||||||
{ }
|
|
||||||
|
|
||||||
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
explicit Node(const aiNode *pNode) :
|
||||||
|
mNode(pNode) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BVHLoader();
|
BVHLoader();
|
||||||
~BVHLoader();
|
~BVHLoader();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details. */
|
* See BaseImporter::CanRead() for details. */
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const;
|
||||||
|
|
||||||
void SetupProperties(const Importer* pImp);
|
void SetupProperties(const Importer *pImp);
|
||||||
const aiImporterDesc* GetInfo () const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
/** Imports the given file into the given scene structure.
|
/** Imports the given file into the given scene structure.
|
||||||
* See BaseImporter::InternReadFile() for details
|
* See BaseImporter::InternReadFile() for details
|
||||||
*/
|
*/
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Reads the file */
|
/** Reads the file */
|
||||||
void ReadStructure( aiScene* pScene);
|
void ReadStructure(aiScene *pScene);
|
||||||
|
|
||||||
/** Reads the hierarchy */
|
/** Reads the hierarchy */
|
||||||
void ReadHierarchy( aiScene* pScene);
|
void ReadHierarchy(aiScene *pScene);
|
||||||
|
|
||||||
/** Reads a node and recursively its childs and returns the created node. */
|
/** Reads a node and recursively its childs and returns the created node. */
|
||||||
aiNode* ReadNode();
|
aiNode *ReadNode();
|
||||||
|
|
||||||
/** Reads an end node and returns the created node. */
|
/** Reads an end node and returns the created node. */
|
||||||
aiNode* ReadEndSite( const std::string& pParentName);
|
aiNode *ReadEndSite(const std::string &pParentName);
|
||||||
|
|
||||||
/** Reads a node offset for the given node */
|
/** Reads a node offset for the given node */
|
||||||
void ReadNodeOffset( aiNode* pNode);
|
void ReadNodeOffset(aiNode *pNode);
|
||||||
|
|
||||||
/** Reads the animation channels into the given node */
|
/** Reads the animation channels into the given node */
|
||||||
void ReadNodeChannels( BVHLoader::Node& pNode);
|
void ReadNodeChannels(BVHLoader::Node &pNode);
|
||||||
|
|
||||||
/** Reads the motion data */
|
/** Reads the motion data */
|
||||||
void ReadMotion( aiScene* pScene);
|
void ReadMotion(aiScene *pScene);
|
||||||
|
|
||||||
/** Retrieves the next token */
|
/** Retrieves the next token */
|
||||||
std::string GetNextToken();
|
std::string GetNextToken();
|
||||||
|
@ -141,10 +134,10 @@ protected:
|
||||||
float GetNextTokenAsFloat();
|
float GetNextTokenAsFloat();
|
||||||
|
|
||||||
/** Aborts the file reading with an exception */
|
/** Aborts the file reading with an exception */
|
||||||
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
|
||||||
|
|
||||||
/** Constructs an animation for the motion data and stores it in the given scene */
|
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||||
void CreateAnimation( aiScene* pScene);
|
void CreateAnimation(aiScene *pScene);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Filename, for a verbose error message */
|
/** Filename, for a verbose error message */
|
|
@ -42,165 +42,143 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Conversion of Blender's new BMesh stuff
|
* @brief Conversion of Blender's new BMesh stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
|
|
||||||
|
#include "BlenderBMesh.h"
|
||||||
#include "BlenderDNA.h"
|
#include "BlenderDNA.h"
|
||||||
#include "BlenderScene.h"
|
#include "BlenderScene.h"
|
||||||
#include "BlenderBMesh.h"
|
|
||||||
#include "BlenderTessellator.h"
|
#include "BlenderTessellator.h"
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
template <>
|
||||||
template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
|
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
|
||||||
{
|
static auto prefix = "BLEND_BMESH: ";
|
||||||
static auto prefix = "BLEND_BMESH: ";
|
return prefix;
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Blender;
|
using namespace Assimp::Blender;
|
||||||
using namespace Assimp::Formatter;
|
using namespace Assimp::Formatter;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
|
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
|
||||||
BMesh( mesh ),
|
BMesh(mesh),
|
||||||
triMesh( NULL )
|
triMesh(nullptr) {
|
||||||
{
|
ai_assert(nullptr != mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
BlenderBMeshConverter::~BlenderBMeshConverter( )
|
BlenderBMeshConverter::~BlenderBMeshConverter() {
|
||||||
{
|
DestroyTriMesh();
|
||||||
DestroyTriMesh( );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BlenderBMeshConverter::ContainsBMesh( ) const
|
bool BlenderBMeshConverter::ContainsBMesh() const {
|
||||||
{
|
|
||||||
// TODO - Should probably do some additional verification here
|
// TODO - Should probably do some additional verification here
|
||||||
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
|
||||||
{
|
AssertValidMesh();
|
||||||
AssertValidMesh( );
|
AssertValidSizes();
|
||||||
AssertValidSizes( );
|
PrepareTriMesh();
|
||||||
PrepareTriMesh( );
|
|
||||||
|
|
||||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
for (int i = 0; i < BMesh->totpoly; ++i) {
|
||||||
{
|
const MPoly &poly = BMesh->mpoly[i];
|
||||||
const MPoly& poly = BMesh->mpoly[ i ];
|
ConvertPolyToFaces(poly);
|
||||||
ConvertPolyToFaces( poly );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return triMesh;
|
return triMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::AssertValidMesh( )
|
void BlenderBMeshConverter::AssertValidMesh() {
|
||||||
{
|
if (!ContainsBMesh()) {
|
||||||
if ( !ContainsBMesh( ) )
|
ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
|
||||||
{
|
|
||||||
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::AssertValidSizes( )
|
void BlenderBMeshConverter::AssertValidSizes() {
|
||||||
{
|
if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
|
||||||
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
|
ThrowException("BMesh poly array has incorrect 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");
|
||||||
ThrowException( "BMesh loop array has incorrect size" );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::PrepareTriMesh( )
|
void BlenderBMeshConverter::PrepareTriMesh() {
|
||||||
{
|
if (triMesh) {
|
||||||
if ( triMesh )
|
DestroyTriMesh();
|
||||||
{
|
|
||||||
DestroyTriMesh( );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
triMesh = new Mesh( *BMesh );
|
triMesh = new Mesh(*BMesh);
|
||||||
triMesh->totface = 0;
|
triMesh->totface = 0;
|
||||||
triMesh->mface.clear( );
|
triMesh->mface.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::DestroyTriMesh( )
|
void BlenderBMeshConverter::DestroyTriMesh() {
|
||||||
{
|
|
||||||
delete triMesh;
|
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];
|
||||||
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);
|
||||||
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.
|
// UVs are optional, so only convert when present.
|
||||||
if ( BMesh->mloopuv.size() )
|
if (BMesh->mloopuv.size()) {
|
||||||
{
|
if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
|
||||||
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
|
ThrowException("BMesh uv loop array has incorrect size");
|
||||||
{
|
|
||||||
ThrowException( "BMesh uv loop array has incorrect size" );
|
|
||||||
}
|
}
|
||||||
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
|
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
|
||||||
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
|
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
|
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||||
BlenderTessellatorGL tessGL( *this );
|
BlenderTessellatorGL tessGL(*this);
|
||||||
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
|
||||||
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
|
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||||
BlenderTessellatorP2T tessP2T( *this );
|
BlenderTessellatorP2T tessP2T(*this);
|
||||||
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
tessP2T.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
|
||||||
{
|
|
||||||
MFace face;
|
MFace face;
|
||||||
face.v1 = v1;
|
face.v1 = v1;
|
||||||
face.v2 = v2;
|
face.v2 = v2;
|
||||||
face.v3 = v3;
|
face.v3 = v3;
|
||||||
face.v4 = v4;
|
face.v4 = v4;
|
||||||
|
face.flag = 0;
|
||||||
// TODO - Work out how materials work
|
// TODO - Work out how materials work
|
||||||
face.mat_nr = 0;
|
face.mat_nr = 0;
|
||||||
triMesh->mface.push_back( face );
|
triMesh->mface.push_back(face);
|
||||||
triMesh->totface = static_cast<int>(triMesh->mface.size( ));
|
triMesh->totface = static_cast<int>(triMesh->mface.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
|
void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) {
|
||||||
{
|
|
||||||
MTFace mtface;
|
MTFace mtface;
|
||||||
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
|
memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
|
||||||
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
|
memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
|
||||||
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
|
memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
|
||||||
|
|
||||||
if ( uv4 )
|
if (uv4) {
|
||||||
{
|
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
|
||||||
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
triMesh->mtface.push_back( mtface );
|
triMesh->mtface.push_back(mtface);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
|
@ -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((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
|
||||||
|
if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
|
||||||
|
// allocate cnt elements and parse them from file
|
||||||
|
out.reset(cdtd.Create(cnt), cdtd.Destroy);
|
||||||
|
return cdtd.Read(out.get(), cnt, db);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<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
|
|
@ -45,25 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* serialized set of data structures.
|
* serialized set of data structures.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
#include "BlenderDNA.h"
|
#include "BlenderDNA.h"
|
||||||
#include <assimp/StreamReader.h>
|
#include <assimp/StreamReader.h>
|
||||||
#include <assimp/fast_atof.h>
|
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
|
#include <assimp/fast_atof.h>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Blender;
|
using namespace Assimp::Blender;
|
||||||
using namespace Assimp::Formatter;
|
using namespace Assimp::Formatter;
|
||||||
|
|
||||||
static bool match4(StreamReaderAny& stream, const char* string) {
|
static bool match4(StreamReaderAny &stream, const char *string) {
|
||||||
ai_assert( nullptr != string );
|
ai_assert(nullptr != string);
|
||||||
char tmp[4];
|
char tmp[4];
|
||||||
tmp[ 0 ] = ( stream ).GetI1();
|
tmp[0] = (stream).GetI1();
|
||||||
tmp[ 1 ] = ( stream ).GetI1();
|
tmp[1] = (stream).GetI1();
|
||||||
tmp[ 2 ] = ( stream ).GetI1();
|
tmp[2] = (stream).GetI1();
|
||||||
tmp[ 3 ] = ( stream ).GetI1();
|
tmp[3] = (stream).GetI1();
|
||||||
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
|
@ -72,75 +71,76 @@ struct Type {
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void DNAParser::Parse ()
|
void DNAParser::Parse() {
|
||||||
{
|
StreamReaderAny &stream = *db.reader.get();
|
||||||
StreamReaderAny& stream = *db.reader.get();
|
DNA &dna = db.dna;
|
||||||
DNA& dna = db.dna;
|
|
||||||
|
|
||||||
if(!match4(stream,"SDNA")) {
|
if (!match4(stream, "SDNA")) {
|
||||||
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
|
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
|
||||||
}
|
}
|
||||||
|
|
||||||
// name dictionary
|
// name dictionary
|
||||||
if(!match4(stream,"NAME")) {
|
if (!match4(stream, "NAME")) {
|
||||||
throw DeadlyImportError("BlenderDNA: Expected NAME field");
|
throw DeadlyImportError("BlenderDNA: Expected NAME field");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> names (stream.GetI4());
|
std::vector<std::string> names(stream.GetI4());
|
||||||
for(std::string& s : names) {
|
for (std::string &s : names) {
|
||||||
while (char c = stream.GetI1()) {
|
while (char c = stream.GetI1()) {
|
||||||
s += c;
|
s += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type dictionary
|
// type dictionary
|
||||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||||
if(!match4(stream,"TYPE")) {
|
;
|
||||||
|
if (!match4(stream, "TYPE")) {
|
||||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Type> types (stream.GetI4());
|
std::vector<Type> types(stream.GetI4());
|
||||||
for(Type& s : types) {
|
for (Type &s : types) {
|
||||||
while (char c = stream.GetI1()) {
|
while (char c = stream.GetI1()) {
|
||||||
s.name += c;
|
s.name += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type length dictionary
|
// type length dictionary
|
||||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||||
if(!match4(stream,"TLEN")) {
|
;
|
||||||
|
if (!match4(stream, "TLEN")) {
|
||||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Type& s : types) {
|
for (Type &s : types) {
|
||||||
s.size = stream.GetI2();
|
s.size = stream.GetI2();
|
||||||
}
|
}
|
||||||
|
|
||||||
// structures dictionary
|
// structures dictionary
|
||||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||||
if(!match4(stream,"STRC")) {
|
;
|
||||||
|
if (!match4(stream, "STRC")) {
|
||||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t end = stream.GetI4(), fields = 0;
|
size_t end = stream.GetI4(), fields = 0;
|
||||||
|
|
||||||
dna.structures.reserve(end);
|
dna.structures.reserve(end);
|
||||||
for(size_t i = 0; i != end; ++i) {
|
for (size_t i = 0; i != end; ++i) {
|
||||||
|
|
||||||
uint16_t n = stream.GetI2();
|
uint16_t n = stream.GetI2();
|
||||||
if (n >= types.size()) {
|
if (n >= types.size()) {
|
||||||
throw DeadlyImportError((format(),
|
throw DeadlyImportError((format(),
|
||||||
"BlenderDNA: Invalid type index in structure name" ,n,
|
"BlenderDNA: Invalid type index in structure name", n,
|
||||||
" (there are only ", types.size(), " entries)"
|
" (there are only ", types.size(), " entries)"));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintain separate indexes
|
// maintain separate indexes
|
||||||
dna.indices[types[n].name] = dna.structures.size();
|
dna.indices[types[n].name] = dna.structures.size();
|
||||||
|
|
||||||
dna.structures.push_back(Structure());
|
dna.structures.push_back(Structure());
|
||||||
Structure& s = dna.structures.back();
|
Structure &s = dna.structures.back();
|
||||||
s.name = types[n].name;
|
s.name = types[n].name;
|
||||||
//s.index = dna.structures.size()-1;
|
//s.index = dna.structures.size()-1;
|
||||||
|
|
||||||
n = stream.GetI2();
|
n = stream.GetI2();
|
||||||
|
@ -152,12 +152,11 @@ void DNAParser::Parse ()
|
||||||
uint16_t j = stream.GetI2();
|
uint16_t j = stream.GetI2();
|
||||||
if (j >= types.size()) {
|
if (j >= types.size()) {
|
||||||
throw DeadlyImportError((format(),
|
throw DeadlyImportError((format(),
|
||||||
"BlenderDNA: Invalid type index in structure field ", j,
|
"BlenderDNA: Invalid type index in structure field ", j,
|
||||||
" (there are only ", types.size(), " entries)"
|
" (there are only ", types.size(), " entries)"));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
s.fields.push_back(Field());
|
s.fields.push_back(Field());
|
||||||
Field& f = s.fields.back();
|
Field &f = s.fields.back();
|
||||||
f.offset = offset;
|
f.offset = offset;
|
||||||
|
|
||||||
f.type = types[j].name;
|
f.type = types[j].name;
|
||||||
|
@ -166,9 +165,8 @@ void DNAParser::Parse ()
|
||||||
j = stream.GetI2();
|
j = stream.GetI2();
|
||||||
if (j >= names.size()) {
|
if (j >= names.size()) {
|
||||||
throw DeadlyImportError((format(),
|
throw DeadlyImportError((format(),
|
||||||
"BlenderDNA: Invalid name index in structure field ", j,
|
"BlenderDNA: Invalid name index in structure field ", j,
|
||||||
" (there are only ", names.size(), " entries)"
|
" (there are only ", names.size(), " entries)"));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.name = names[j];
|
f.name = names[j];
|
||||||
|
@ -191,26 +189,25 @@ void DNAParser::Parse ()
|
||||||
const std::string::size_type rb = f.name.find('[');
|
const std::string::size_type rb = f.name.find('[');
|
||||||
if (rb == std::string::npos) {
|
if (rb == std::string::npos) {
|
||||||
throw DeadlyImportError((format(),
|
throw DeadlyImportError((format(),
|
||||||
"BlenderDNA: Encountered invalid array declaration ",
|
"BlenderDNA: Encountered invalid array declaration ",
|
||||||
f.name
|
f.name));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.flags |= FieldFlag_Array;
|
f.flags |= FieldFlag_Array;
|
||||||
DNA::ExtractArraySize(f.name,f.array_sizes);
|
DNA::ExtractArraySize(f.name, f.array_sizes);
|
||||||
f.name = f.name.substr(0,rb);
|
f.name = f.name.substr(0, rb);
|
||||||
|
|
||||||
f.size *= f.array_sizes[0] * f.array_sizes[1];
|
f.size *= f.array_sizes[0] * f.array_sizes[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintain separate indexes
|
// maintain separate indexes
|
||||||
s.indices[f.name] = s.fields.size()-1;
|
s.indices[f.name] = s.fields.size() - 1;
|
||||||
offset += f.size;
|
offset += f.size;
|
||||||
}
|
}
|
||||||
s.size = offset;
|
s.size = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
|
ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
dna.DumpToFile();
|
dna.DumpToFile();
|
||||||
|
@ -220,13 +217,11 @@ void DNAParser::Parse ()
|
||||||
dna.RegisterConverters();
|
dna.RegisterConverters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void DNA :: DumpToFile()
|
void DNA ::DumpToFile() {
|
||||||
{
|
|
||||||
// we don't bother using the VFS here for this is only for debugging.
|
// we don't bother using the VFS here for this is only for debugging.
|
||||||
// (and all your bases are belong to us).
|
// (and all your bases are belong to us).
|
||||||
|
|
||||||
|
@ -235,12 +230,14 @@ void DNA :: DumpToFile()
|
||||||
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
|
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
f << "Field format: type name offset size" << "\n";
|
f << "Field format: type name offset size"
|
||||||
f << "Structure format: name size" << "\n";
|
<< "\n";
|
||||||
|
f << "Structure format: name size"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
for(const Structure& s : structures) {
|
for (const Structure &s : structures) {
|
||||||
f << s.name << " " << s.size << "\n\n";
|
f << s.name << " " << s.size << "\n\n";
|
||||||
for(const Field& ff : s.fields) {
|
for (const Field &ff : s.fields) {
|
||||||
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
|
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
|
||||||
}
|
}
|
||||||
f << "\n";
|
f << "\n";
|
||||||
|
@ -252,11 +249,9 @@ void DNA :: DumpToFile()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
/*static*/ void DNA :: ExtractArraySize(
|
/*static*/ void DNA ::ExtractArraySize(
|
||||||
const std::string& out,
|
const std::string &out,
|
||||||
size_t array_sizes[2]
|
size_t array_sizes[2]) {
|
||||||
)
|
|
||||||
{
|
|
||||||
array_sizes[0] = array_sizes[1] = 1;
|
array_sizes[0] = array_sizes[1] = 1;
|
||||||
std::string::size_type pos = out.find('[');
|
std::string::size_type pos = out.find('[');
|
||||||
if (pos++ == std::string::npos) {
|
if (pos++ == std::string::npos) {
|
||||||
|
@ -264,7 +259,7 @@ void DNA :: DumpToFile()
|
||||||
}
|
}
|
||||||
array_sizes[0] = strtoul10(&out[pos]);
|
array_sizes[0] = strtoul10(&out[pos]);
|
||||||
|
|
||||||
pos = out.find('[',pos);
|
pos = out.find('[', pos);
|
||||||
if (pos++ == std::string::npos) {
|
if (pos++ == std::string::npos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -272,36 +267,32 @@ void DNA :: DumpToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
|
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
|
||||||
const Structure& structure,
|
const Structure &structure,
|
||||||
const FileDatabase& db
|
const FileDatabase &db) const {
|
||||||
) const
|
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||||
{
|
|
||||||
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
|
|
||||||
if (it == converters.end()) {
|
if (it == converters.end()) {
|
||||||
return std::shared_ptr< ElemBase >();
|
return std::shared_ptr<ElemBase>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
|
std::shared_ptr<ElemBase> ret = (structure.*((*it).second.first))();
|
||||||
(structure.*((*it).second.second))(ret,db);
|
(structure.*((*it).second.second))(ret, db);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
DNA::FactoryPair DNA :: GetBlobToStructureConverter(
|
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
|
||||||
const Structure& structure,
|
const Structure &structure,
|
||||||
const FileDatabase& /*db*/
|
const FileDatabase & /*db*/
|
||||||
) const
|
) const {
|
||||||
{
|
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
|
||||||
return it == converters.end() ? FactoryPair() : (*it).second;
|
return it == converters.end() ? FactoryPair() : (*it).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
|
// 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
|
// NOTE: these are just dummies. Their presence enforces
|
||||||
// Structure::Convert<target_type> to be called on these
|
// Structure::Convert<target_type> to be called on these
|
||||||
// empty structures. These converters are special
|
// empty structures. These converters are special
|
||||||
|
@ -311,30 +302,27 @@ void DNA :: AddPrimitiveStructures()
|
||||||
// in question.
|
// in question.
|
||||||
|
|
||||||
indices["int"] = structures.size();
|
indices["int"] = structures.size();
|
||||||
structures.push_back( Structure() );
|
structures.push_back(Structure());
|
||||||
structures.back().name = "int";
|
structures.back().name = "int";
|
||||||
structures.back().size = 4;
|
structures.back().size = 4;
|
||||||
|
|
||||||
indices["short"] = structures.size();
|
indices["short"] = structures.size();
|
||||||
structures.push_back( Structure() );
|
structures.push_back(Structure());
|
||||||
structures.back().name = "short";
|
structures.back().name = "short";
|
||||||
structures.back().size = 2;
|
structures.back().size = 2;
|
||||||
|
|
||||||
|
|
||||||
indices["char"] = structures.size();
|
indices["char"] = structures.size();
|
||||||
structures.push_back( Structure() );
|
structures.push_back(Structure());
|
||||||
structures.back().name = "char";
|
structures.back().name = "char";
|
||||||
structures.back().size = 1;
|
structures.back().size = 1;
|
||||||
|
|
||||||
|
|
||||||
indices["float"] = structures.size();
|
indices["float"] = structures.size();
|
||||||
structures.push_back( Structure() );
|
structures.push_back(Structure());
|
||||||
structures.back().name = "float";
|
structures.back().name = "float";
|
||||||
structures.back().size = 4;
|
structures.back().size = 4;
|
||||||
|
|
||||||
|
|
||||||
indices["double"] = structures.size();
|
indices["double"] = structures.size();
|
||||||
structures.push_back( Structure() );
|
structures.push_back(Structure());
|
||||||
structures.back().name = "double";
|
structures.back().name = "double";
|
||||||
structures.back().size = 8;
|
structures.back().size = 8;
|
||||||
|
|
||||||
|
@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void SectionParser :: Next()
|
void SectionParser ::Next() {
|
||||||
{
|
|
||||||
stream.SetCurrentPos(current.start + current.size);
|
stream.SetCurrentPos(current.start + current.size);
|
||||||
|
|
||||||
const char tmp[] = {
|
const char tmp[] = {
|
||||||
|
@ -352,7 +339,7 @@ void SectionParser :: Next()
|
||||||
(const char)stream.GetI1(),
|
(const char)stream.GetI1(),
|
||||||
(const char)stream.GetI1()
|
(const char)stream.GetI1()
|
||||||
};
|
};
|
||||||
current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
|
current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
|
||||||
|
|
||||||
current.size = stream.GetI4();
|
current.size = stream.GetI4();
|
||||||
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
|
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
|
||||||
|
@ -366,10 +353,8 @@ void SectionParser :: Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
ASSIMP_LOG_DEBUG(current.id);
|
ASSIMP_LOG_VERBOSE_DEBUG(current.id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -49,26 +49,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <assimp/BaseImporter.h>
|
#include <assimp/BaseImporter.h>
|
||||||
#include <assimp/StreamReader.h>
|
#include <assimp/StreamReader.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <memory>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
// enable verbose log output. really verbose, so be careful.
|
// enable verbose log output. really verbose, so be careful.
|
||||||
#ifdef ASSIMP_BUILD_DEBUG
|
#ifdef ASSIMP_BUILD_DEBUG
|
||||||
# define ASSIMP_BUILD_BLENDER_DEBUG
|
#define ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// #define ASSIMP_BUILD_BLENDER_NO_STATS
|
// #define ASSIMP_BUILD_BLENDER_NO_STATS
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
template <bool,bool> class StreamReader;
|
template <bool, bool>
|
||||||
typedef StreamReader<true,true> StreamReaderAny;
|
class StreamReader;
|
||||||
|
typedef StreamReader<true, true> StreamReaderAny;
|
||||||
|
|
||||||
namespace Blender {
|
namespace Blender {
|
||||||
|
|
||||||
class FileDatabase;
|
class FileDatabase;
|
||||||
struct FileBlockHead;
|
struct FileBlockHead;
|
||||||
|
|
||||||
template <template <typename> class TOUT>
|
template <template <typename> class TOUT>
|
||||||
|
@ -82,8 +83,8 @@ class ObjectCache;
|
||||||
* ancestry. */
|
* ancestry. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Error : DeadlyImportError {
|
struct Error : DeadlyImportError {
|
||||||
Error (const std::string& s)
|
Error(const std::string &s) :
|
||||||
: DeadlyImportError(s) {
|
DeadlyImportError(s) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -93,9 +94,8 @@ struct Error : DeadlyImportError {
|
||||||
* descendents. It serves as base class for all data structure fields. */
|
* descendents. It serves as base class for all data structure fields. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct ElemBase {
|
struct ElemBase {
|
||||||
ElemBase()
|
ElemBase() :
|
||||||
: dna_type(nullptr)
|
dna_type(nullptr) {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ struct ElemBase {
|
||||||
* data type is not static, i.e. a std::shared_ptr<ElemBase>
|
* data type is not static, i.e. a std::shared_ptr<ElemBase>
|
||||||
* in the scene description would have its type resolved
|
* in the scene description would have its type resolved
|
||||||
* at runtime, so this member is always set. */
|
* at runtime, so this member is always set. */
|
||||||
const char* dna_type;
|
const char *dna_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@ -120,8 +120,8 @@ struct ElemBase {
|
||||||
* they used to point to.*/
|
* they used to point to.*/
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Pointer {
|
struct Pointer {
|
||||||
Pointer()
|
Pointer() :
|
||||||
: val() {
|
val() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
@ -131,8 +131,8 @@ struct Pointer {
|
||||||
/** Represents a generic offset within a BLEND file */
|
/** Represents a generic offset within a BLEND file */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct FileOffset {
|
struct FileOffset {
|
||||||
FileOffset()
|
FileOffset() :
|
||||||
: val() {
|
val() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
@ -154,7 +154,7 @@ public:
|
||||||
resize(0);
|
resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool () const {
|
operator bool() const {
|
||||||
return !empty();
|
return !empty();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -164,7 +164,7 @@ public:
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
enum FieldFlags {
|
enum FieldFlags {
|
||||||
FieldFlag_Pointer = 0x1,
|
FieldFlag_Pointer = 0x1,
|
||||||
FieldFlag_Array = 0x2
|
FieldFlag_Array = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@ -200,7 +200,7 @@ enum ErrorPolicy {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
# define ErrorPolicy_Igno ErrorPolicy_Warn
|
#define ErrorPolicy_Igno ErrorPolicy_Warn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@ -212,47 +212,42 @@ enum ErrorPolicy {
|
||||||
* meaningful contents. */
|
* meaningful contents. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class Structure {
|
class Structure {
|
||||||
template <template <typename> class> friend class ObjectCache;
|
template <template <typename> class>
|
||||||
|
friend class ObjectCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Structure()
|
Structure() :
|
||||||
: cache_idx(static_cast<size_t>(-1) ){
|
cache_idx(static_cast<size_t>(-1)) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// publicly accessible members
|
// publicly accessible members
|
||||||
std::string name;
|
std::string name;
|
||||||
vector< Field > fields;
|
vector<Field> fields;
|
||||||
std::map<std::string, size_t> indices;
|
std::map<std::string, size_t> indices;
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Access a field of the structure by its canonical name. The pointer version
|
/** 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 NULL on failure while the reference version raises an import error. */
|
||||||
inline const Field& operator [] (const std::string& ss) const;
|
inline const Field &operator[](const std::string &ss) const;
|
||||||
inline const Field* Get (const std::string& ss) const;
|
inline const Field *Get(const std::string &ss) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Access a field of the structure by its index */
|
/** Access a field of the structure by its index */
|
||||||
inline const Field& operator [] (const size_t i) const;
|
inline const Field &operator[](const size_t i) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
inline bool operator== (const Structure& other) const {
|
inline bool operator==(const Structure &other) const {
|
||||||
return name == other.name; // name is meant to be an unique identifier
|
return name == other.name; // name is meant to be an unique identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
inline bool operator!= (const Structure& other) const {
|
inline bool operator!=(const Structure &other) const {
|
||||||
return name != other.name;
|
return name != other.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Try to read an instance of the structure from the stream
|
/** Try to read an instance of the structure from the stream
|
||||||
* and attempt to convert to `T`. This is done by
|
* and attempt to convert to `T`. This is done by
|
||||||
|
@ -260,54 +255,54 @@ public:
|
||||||
* a compiler complain is the result.
|
* a compiler complain is the result.
|
||||||
* @param dest Destination value to be written
|
* @param dest Destination value to be written
|
||||||
* @param db File database, including input stream. */
|
* @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
|
// generic converter
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Convert(std::shared_ptr<ElemBase> in,const FileDatabase& db) const;
|
void Convert(std::shared_ptr<ElemBase> in, const FileDatabase &db) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// generic allocator
|
// 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
|
// field parsing for 1d arrays
|
||||||
template <int error_policy, typename T, size_t M>
|
template <int error_policy, typename T, size_t M>
|
||||||
void ReadFieldArray(T (& out)[M], const char* name,
|
void ReadFieldArray(T (&out)[M], const char *name,
|
||||||
const FileDatabase& db) const;
|
const FileDatabase &db) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// field parsing for 2d arrays
|
// field parsing for 2d arrays
|
||||||
template <int error_policy, typename T, size_t M, size_t N>
|
template <int error_policy, typename T, size_t M, size_t N>
|
||||||
void ReadFieldArray2(T (& out)[M][N], const char* name,
|
void ReadFieldArray2(T (&out)[M][N], const char *name,
|
||||||
const FileDatabase& db) const;
|
const FileDatabase &db) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// field parsing for pointer or dynamic array types
|
// field parsing for pointer or dynamic array types
|
||||||
// (std::shared_ptr)
|
// (std::shared_ptr)
|
||||||
// The return value indicates whether the data was already cached.
|
// The return value indicates whether the data was already cached.
|
||||||
template <int error_policy, template <typename> class TOUT, typename T>
|
template <int error_policy, template <typename> class TOUT, typename T>
|
||||||
bool ReadFieldPtr(TOUT<T>& out, const char* name,
|
bool ReadFieldPtr(TOUT<T> &out, const char *name,
|
||||||
const FileDatabase& db,
|
const FileDatabase &db,
|
||||||
bool non_recursive = false) const;
|
bool non_recursive = false) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// field parsing for static arrays of pointer or dynamic
|
// field parsing for static arrays of pointer or dynamic
|
||||||
// array types (std::shared_ptr[])
|
// array types (std::shared_ptr[])
|
||||||
// The return value indicates whether the data was already cached.
|
// The return value indicates whether the data was already cached.
|
||||||
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
|
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
|
||||||
bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
|
bool ReadFieldPtr(TOUT<T> (&out)[N], const char *name,
|
||||||
const FileDatabase& db) const;
|
const FileDatabase &db) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// field parsing for `normal` values
|
// field parsing for `normal` values
|
||||||
// The return value indicates whether the data was already cached.
|
// The return value indicates whether the data was already cached.
|
||||||
template <int error_policy, typename T>
|
template <int error_policy, typename T>
|
||||||
void ReadField(T& out, const char* name,
|
void ReadField(T &out, const char *name,
|
||||||
const FileDatabase& db) const;
|
const FileDatabase &db) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
|
@ -318,7 +313,7 @@ public:
|
||||||
* @return true when read was successful
|
* @return true when read was successful
|
||||||
*/
|
*/
|
||||||
template <int error_policy, template <typename> class TOUT, typename T>
|
template <int error_policy, template <typename> class TOUT, typename T>
|
||||||
bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
|
bool ReadFieldPtrVector(vector<TOUT<T>> &out, const char *name, const FileDatabase &db) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parses raw customdata
|
* @brief parses raw customdata
|
||||||
|
@ -329,40 +324,40 @@ public:
|
||||||
* @return true when read was successful
|
* @return true when read was successful
|
||||||
*/
|
*/
|
||||||
template <int error_policy>
|
template <int error_policy>
|
||||||
bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
|
bool ReadCustomDataPtr(std::shared_ptr<ElemBase> &out, int cdtype, const char *name, const FileDatabase &db) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// --------------------------------------------------------
|
||||||
|
template <template <typename> class TOUT, typename T>
|
||||||
|
bool ResolvePointer(TOUT<T> &out, const Pointer &ptrval,
|
||||||
|
const FileDatabase &db, const Field &f,
|
||||||
|
bool non_recursive = false) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
template <template <typename> class TOUT, typename T>
|
template <template <typename> class TOUT, typename T>
|
||||||
bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
|
bool ResolvePointer(vector<TOUT<T>> &out, const Pointer &ptrval,
|
||||||
const FileDatabase& db, const Field& f,
|
const FileDatabase &db, const Field &f, bool) const;
|
||||||
bool non_recursive = false) const;
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
template <template <typename> class TOUT, typename T>
|
bool ResolvePointer(std::shared_ptr<FileOffset> &out, const Pointer &ptrval,
|
||||||
bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
|
const FileDatabase &db, const Field &f, bool) const;
|
||||||
const FileDatabase& db, const Field& f, bool) const;
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
|
inline const FileBlockHead *LocateFileBlockForAddress(
|
||||||
const FileDatabase& db, const Field& f, bool) const;
|
const Pointer &ptrval,
|
||||||
|
const FileDatabase &db) const;
|
||||||
// --------------------------------------------------------
|
|
||||||
inline const FileBlockHead* LocateFileBlockForAddress(
|
|
||||||
const Pointer & ptrval,
|
|
||||||
const FileDatabase& db) const;
|
|
||||||
|
|
||||||
private:
|
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());
|
out = std::shared_ptr<T>(new T());
|
||||||
s = 1;
|
s = 1;
|
||||||
return out.get();
|
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);
|
out.resize(s);
|
||||||
return s ? &out.front() : NULL;
|
return s ? &out.front() : NULL;
|
||||||
}
|
}
|
||||||
|
@ -372,14 +367,14 @@ private:
|
||||||
struct _defaultInitializer {
|
struct _defaultInitializer {
|
||||||
|
|
||||||
template <typename T, unsigned int N>
|
template <typename T, unsigned int N>
|
||||||
void operator ()(T (& out)[N], const char* = NULL) {
|
void operator()(T (&out)[N], const char * = NULL) {
|
||||||
for (unsigned int i = 0; i < N; ++i) {
|
for (unsigned int i = 0; i < N; ++i) {
|
||||||
out[i] = T();
|
out[i] = T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, unsigned int N, unsigned int M>
|
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 * = NULL) {
|
||||||
for (unsigned int i = 0; i < N; ++i) {
|
for (unsigned int i = 0; i < N; ++i) {
|
||||||
for (unsigned int j = 0; j < M; ++j) {
|
for (unsigned int j = 0; j < M; ++j) {
|
||||||
out[i][j] = T();
|
out[i][j] = T();
|
||||||
|
@ -388,21 +383,21 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void operator ()(T& out, const char* = NULL) {
|
void operator()(T &out, const char * = NULL) {
|
||||||
out = T();
|
out = T();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable size_t cache_idx;
|
mutable size_t cache_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
|
template <>
|
||||||
|
struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void operator ()(T& out, const char* reason = "<add reason>") {
|
void operator()(T &out, const char *reason = "<add reason>") {
|
||||||
ASSIMP_LOG_WARN(reason);
|
ASSIMP_LOG_WARN(reason);
|
||||||
|
|
||||||
// ... and let the show go on
|
// ... and let the show go on
|
||||||
|
@ -410,10 +405,11 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
|
template <>
|
||||||
|
struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void operator ()(T& /*out*/,const char* = "") {
|
void operator()(T & /*out*/, const char * = "") {
|
||||||
// obviously, it is crucial that _DefaultInitializer is used
|
// obviously, it is crucial that _DefaultInitializer is used
|
||||||
// only from within a catch clause.
|
// only from within a catch clause.
|
||||||
throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
|
throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
|
||||||
|
@ -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 <>
|
||||||
const Pointer & ptrval,
|
inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
|
||||||
const FileDatabase& db,
|
const Pointer &ptrval,
|
||||||
const Field& f,
|
const FileDatabase &db,
|
||||||
bool
|
const Field &f,
|
||||||
) const;
|
bool) const;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Represents the full data structure information for a single BLEND file.
|
/** Represents the full data structure information for a single BLEND file.
|
||||||
|
@ -435,40 +430,34 @@ template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(st
|
||||||
* #DNAParser does the reading and represents currently the only place where
|
* #DNAParser does the reading and represents currently the only place where
|
||||||
* DNA is altered.*/
|
* DNA is altered.*/
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class DNA
|
class DNA {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
typedef void (Structure::*ConvertProcPtr)(
|
||||||
typedef void (Structure::*ConvertProcPtr) (
|
std::shared_ptr<ElemBase> in,
|
||||||
std::shared_ptr<ElemBase> in,
|
const FileDatabase &) const;
|
||||||
const FileDatabase&
|
|
||||||
) const;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<ElemBase> (
|
typedef std::shared_ptr<ElemBase> (
|
||||||
Structure::*AllocProcPtr) () const;
|
Structure::*AllocProcPtr)() const;
|
||||||
|
|
||||||
typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
|
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::map<std::string, FactoryPair> converters;
|
||||||
std::map<std::string, FactoryPair > converters;
|
vector<Structure> structures;
|
||||||
vector<Structure > structures;
|
|
||||||
std::map<std::string, size_t> indices;
|
std::map<std::string, size_t> indices;
|
||||||
|
|
||||||
public:
|
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 NULL on failure
|
||||||
* while the reference version raises an error. */
|
* while the reference version raises an error. */
|
||||||
inline const Structure& operator [] (const std::string& ss) const;
|
inline const Structure &operator[](const std::string &ss) const;
|
||||||
inline const Structure* Get (const std::string& ss) const;
|
inline const Structure *Get(const std::string &ss) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Access a structure by its index */
|
/** Access a structure by its index */
|
||||||
inline const Structure& operator [] (const size_t i) const;
|
inline const Structure &operator[](const size_t i) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Add structure definitions for all the primitive types,
|
/** Add structure definitions for all the primitive types,
|
||||||
* i.e. integer, short, char, float */
|
* i.e. integer, short, char, float */
|
||||||
|
@ -483,7 +472,6 @@ public:
|
||||||
* known at compile time (consier Object::data).*/
|
* known at compile time (consier Object::data).*/
|
||||||
void RegisterConverters();
|
void RegisterConverters();
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Take an input blob from the stream, interpret it according to
|
/** Take an input blob from the stream, interpret it according to
|
||||||
* a its structure name and convert it to the intermediate
|
* a its structure name and convert it to the intermediate
|
||||||
|
@ -491,10 +479,9 @@ public:
|
||||||
* @param structure Destination structure definition
|
* @param structure Destination structure definition
|
||||||
* @param db File database.
|
* @param db File database.
|
||||||
* @return A null pointer if no appropriate converter is available.*/
|
* @return A null pointer if no appropriate converter is available.*/
|
||||||
std::shared_ptr< ElemBase > ConvertBlobToStructure(
|
std::shared_ptr<ElemBase> ConvertBlobToStructure(
|
||||||
const Structure& structure,
|
const Structure &structure,
|
||||||
const FileDatabase& db
|
const FileDatabase &db) const;
|
||||||
) const;
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Find a suitable conversion function for a given Structure.
|
/** Find a suitable conversion function for a given Structure.
|
||||||
|
@ -505,10 +492,8 @@ public:
|
||||||
* @param db File database.
|
* @param db File database.
|
||||||
* @return A null pointer in .first if no appropriate converter is available.*/
|
* @return A null pointer in .first if no appropriate converter is available.*/
|
||||||
FactoryPair GetBlobToStructureConverter(
|
FactoryPair GetBlobToStructureConverter(
|
||||||
const Structure& structure,
|
const Structure &structure,
|
||||||
const FileDatabase& db
|
const FileDatabase &db) const;
|
||||||
) const;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
@ -527,25 +512,29 @@ public:
|
||||||
* @throw DeadlyImportError if more than 2 dimensions are
|
* @throw DeadlyImportError if more than 2 dimensions are
|
||||||
* encountered. */
|
* encountered. */
|
||||||
static void ExtractArraySize(
|
static void ExtractArraySize(
|
||||||
const std::string& out,
|
const std::string &out,
|
||||||
size_t array_sizes[2]
|
size_t array_sizes[2]);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// special converters for primitive types
|
// special converters for primitive types
|
||||||
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
|
template <>
|
||||||
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
|
inline void Structure ::Convert<int>(int &dest, const FileDatabase &db) const;
|
||||||
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
|
template <>
|
||||||
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
|
inline void Structure ::Convert<short>(short &dest, const FileDatabase &db) const;
|
||||||
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
|
template <>
|
||||||
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
|
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
|
/** Describes a master file block header. Each master file sections holds n
|
||||||
* elements of a certain SDNA structure (or otherwise unspecified data). */
|
* elements of a certain SDNA structure (or otherwise unspecified data). */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct FileBlockHead
|
struct FileBlockHead {
|
||||||
{
|
|
||||||
// points right after the header of the file block
|
// points right after the header of the file block
|
||||||
StreamReaderAny::pos start;
|
StreamReaderAny::pos start;
|
||||||
|
|
||||||
|
@ -561,66 +550,55 @@ struct FileBlockHead
|
||||||
// number of structure instances to follow
|
// number of structure instances to follow
|
||||||
size_t num;
|
size_t num;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// file blocks are sorted by address to quickly locate specific memory addresses
|
// file blocks are sorted by address to quickly locate specific memory addresses
|
||||||
bool operator < (const FileBlockHead& o) const {
|
bool operator<(const FileBlockHead &o) const {
|
||||||
return address.val < o.address.val;
|
return address.val < o.address.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for std::upper_bound
|
// for std::upper_bound
|
||||||
operator const Pointer& () const {
|
operator const Pointer &() const {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// for std::upper_bound
|
// for std::upper_bound
|
||||||
inline bool operator< (const Pointer& a, const Pointer& b) {
|
inline bool operator<(const Pointer &a, const Pointer &b) {
|
||||||
return a.val < b.val;
|
return a.val < b.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Utility to read all master file blocks in turn. */
|
/** Utility to read all master file blocks in turn. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class SectionParser
|
class SectionParser {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** @param stream Inout stream, must point to the
|
/** @param stream Inout stream, must point to the
|
||||||
* first section in the file. Call Next() once
|
* first section in the file. Call Next() once
|
||||||
* to have it read.
|
* to have it read.
|
||||||
* @param ptr64 Pointer size in file is 64 bits? */
|
* @param ptr64 Pointer size in file is 64 bits? */
|
||||||
SectionParser(StreamReaderAny& stream,bool ptr64)
|
SectionParser(StreamReaderAny &stream, bool ptr64) :
|
||||||
: stream(stream)
|
stream(stream), ptr64(ptr64) {
|
||||||
, ptr64(ptr64)
|
|
||||||
{
|
|
||||||
current.size = current.start = 0;
|
current.size = current.start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
const FileBlockHead& GetCurrent() const {
|
const FileBlockHead &GetCurrent() const {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Advance to the next section.
|
/** Advance to the next section.
|
||||||
* @throw DeadlyImportError if the last chunk was passed. */
|
* @throw DeadlyImportError if the last chunk was passed. */
|
||||||
void Next();
|
void Next();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FileBlockHead current;
|
FileBlockHead current;
|
||||||
StreamReaderAny& stream;
|
StreamReaderAny &stream;
|
||||||
bool ptr64;
|
bool ptr64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Import statistics, i.e. number of file blocks read*/
|
/** Import statistics, i.e. number of file blocks read*/
|
||||||
|
@ -628,17 +606,13 @@ public:
|
||||||
class Statistics {
|
class Statistics {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Statistics() :
|
||||||
Statistics ()
|
fields_read(), pointers_resolved(), cache_hits()
|
||||||
: fields_read ()
|
// , blocks_read ()
|
||||||
, pointers_resolved ()
|
,
|
||||||
, cache_hits ()
|
cached_objects() {}
|
||||||
// , blocks_read ()
|
|
||||||
, cached_objects ()
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** total number of fields we read */
|
/** total number of fields we read */
|
||||||
unsigned int fields_read;
|
unsigned int fields_read;
|
||||||
|
|
||||||
|
@ -662,17 +636,13 @@ public:
|
||||||
* avoids circular references and avoids object duplication. */
|
* avoids circular references and avoids object duplication. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
template <template <typename> class TOUT>
|
template <template <typename> class TOUT>
|
||||||
class ObjectCache
|
class ObjectCache {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
|
||||||
typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ObjectCache(const FileDatabase &db) :
|
||||||
ObjectCache(const FileDatabase& db)
|
db(db) {
|
||||||
: db(db)
|
|
||||||
{
|
|
||||||
// currently there are only ~400 structure records per blend file.
|
// currently there are only ~400 structure records per blend file.
|
||||||
// we read only a small part of them and don't cache objects
|
// we read only a small part of them and don't cache objects
|
||||||
// which we don't need, so this should suffice.
|
// which we don't need, so this should suffice.
|
||||||
|
@ -680,17 +650,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Check whether a specific item is in the cache.
|
/** Check whether a specific item is in the cache.
|
||||||
* @param s Data type of the item
|
* @param s Data type of the item
|
||||||
* @param out Output pointer. Unchanged if the
|
* @param out Output pointer. Unchanged if the
|
||||||
* cache doesn't know the item yet.
|
* cache doesn't know the item yet.
|
||||||
* @param ptr Item address to look for. */
|
* @param ptr Item address to look for. */
|
||||||
template <typename T> void get (
|
template <typename T>
|
||||||
const Structure& s,
|
void get(
|
||||||
TOUT<T>& out,
|
const Structure &s,
|
||||||
const Pointer& ptr) const;
|
TOUT<T> &out,
|
||||||
|
const Pointer &ptr) const;
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Add an item to the cache after the item has
|
/** Add an item to the cache after the item has
|
||||||
|
@ -700,47 +670,44 @@ public:
|
||||||
* @param s Data type of the item
|
* @param s Data type of the item
|
||||||
* @param out Item to insert into the cache
|
* @param out Item to insert into the cache
|
||||||
* @param ptr address (cache key) of the item. */
|
* @param ptr address (cache key) of the item. */
|
||||||
template <typename T> void set
|
template <typename T>
|
||||||
(const Structure& s,
|
void set(const Structure &s,
|
||||||
const TOUT<T>& out,
|
const TOUT<T> &out,
|
||||||
const Pointer& ptr);
|
const Pointer &ptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable vector<StructureCache> caches;
|
mutable vector<StructureCache> caches;
|
||||||
const FileDatabase& db;
|
const FileDatabase &db;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
template <> class ObjectCache<Blender::vector>
|
template <>
|
||||||
{
|
class ObjectCache<Blender::vector> {
|
||||||
public:
|
public:
|
||||||
|
ObjectCache(const FileDatabase &) {}
|
||||||
|
|
||||||
ObjectCache(const FileDatabase&) {}
|
template <typename T>
|
||||||
|
void get(const Structure &, vector<T> &, const Pointer &) {}
|
||||||
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
|
template <typename T>
|
||||||
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
|
void set(const Structure &, const vector<T> &, const Pointer &) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(disable:4355)
|
#pragma warning(disable : 4355)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Memory representation of a full BLEND file and all its dependencies. The
|
/** Memory representation of a full BLEND file and all its dependencies. The
|
||||||
* output aiScene is constructed from an instance of this data structure. */
|
* output aiScene is constructed from an instance of this data structure. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class FileDatabase
|
class FileDatabase {
|
||||||
{
|
template <template <typename> class TOUT>
|
||||||
template <template <typename> class TOUT> friend class ObjectCache;
|
friend class ObjectCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileDatabase()
|
FileDatabase() :
|
||||||
: _cacheArrays(*this)
|
_cacheArrays(*this), _cache(*this), next_cache_idx() {}
|
||||||
, _cache(*this)
|
|
||||||
, next_cache_idx()
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// publicly accessible fields
|
// publicly accessible fields
|
||||||
|
@ -748,12 +715,11 @@ public:
|
||||||
bool little;
|
bool little;
|
||||||
|
|
||||||
DNA dna;
|
DNA dna;
|
||||||
std::shared_ptr< StreamReaderAny > reader;
|
std::shared_ptr<StreamReaderAny> reader;
|
||||||
vector< FileBlockHead > entries;
|
vector<FileBlockHead> entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Statistics &stats() const {
|
||||||
Statistics& stats() const {
|
|
||||||
return _stats;
|
return _stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,18 +728,16 @@ public:
|
||||||
// arrays of objects are never cached because we can't easily
|
// arrays of objects are never cached because we can't easily
|
||||||
// ensure their proper destruction.
|
// ensure their proper destruction.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ObjectCache<std::shared_ptr>& cache(std::shared_ptr<T>& /*in*/) const {
|
ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
|
||||||
return _cache;
|
return _cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ObjectCache<vector>& cache(vector<T>& /*in*/) const {
|
ObjectCache<vector> &cache(vector<T> & /*in*/) const {
|
||||||
return _cacheArrays;
|
return _cacheArrays;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||||
mutable Statistics _stats;
|
mutable Statistics _stats;
|
||||||
#endif
|
#endif
|
||||||
|
@ -785,24 +749,20 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(default:4355)
|
#pragma warning(default : 4355)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
|
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
class DNAParser
|
class DNAParser {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Bind the parser to a empty DNA and an input stream */
|
/** Bind the parser to a empty DNA and an input stream */
|
||||||
DNAParser(FileDatabase& db)
|
DNAParser(FileDatabase &db) :
|
||||||
: db(db)
|
db(db) {}
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
/** Locate the DNA in the file and parse it. The input
|
/** Locate the DNA in the file and parse it. The input
|
||||||
* stream is expected to point to the beginning of the DN1
|
* stream is expected to point to the beginning of the DN1
|
||||||
|
@ -811,18 +771,16 @@ public:
|
||||||
* @throw DeadlyImportError if the DNA cannot be read.
|
* @throw DeadlyImportError if the DNA cannot be read.
|
||||||
* @note The position of the stream pointer is undefined
|
* @note The position of the stream pointer is undefined
|
||||||
* afterwards.*/
|
* afterwards.*/
|
||||||
void Parse ();
|
void Parse();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Obtain a reference to the extracted DNA information */
|
/** Obtain a reference to the extracted DNA information */
|
||||||
const Blender::DNA& GetDNA() const {
|
const Blender::DNA &GetDNA() const {
|
||||||
return db.dna;
|
return db.dna;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FileDatabase &db;
|
||||||
FileDatabase& db;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -835,9 +793,8 @@ private:
|
||||||
*/
|
*/
|
||||||
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
|
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
|
||||||
|
|
||||||
|
} // namespace Blender
|
||||||
} // end Blend
|
} // namespace Assimp
|
||||||
} // end Assimp
|
|
||||||
|
|
||||||
#include "BlenderDNA.inl"
|
#include "BlenderDNA.inl"
|
||||||
|
|
|
@ -795,7 +795,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
|
||||||
const Structure* DNA :: Get (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);
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
|
@ -206,7 +206,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
||||||
inflateInit2(&zstream, 16+MAX_WBITS);
|
inflateInit2(&zstream, 16+MAX_WBITS);
|
||||||
|
|
||||||
zstream.next_in = reinterpret_cast<Bytef*>( reader->GetPtr() );
|
zstream.next_in = reinterpret_cast<Bytef*>( reader->GetPtr() );
|
||||||
zstream.avail_in = reader->GetRemainingSize();
|
zstream.avail_in = (uInt) reader->GetRemainingSize();
|
||||||
|
|
||||||
size_t total = 0l;
|
size_t total = 0l;
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
||||||
name.length = 1+ ASSIMP_itoa10(name.data+1,static_cast<unsigned int>(MAXLEN-1), static_cast<int32_t>(conv_data.textures->size()));
|
name.length = 1+ ASSIMP_itoa10(name.data+1,static_cast<unsigned int>(MAXLEN-1), static_cast<int32_t>(conv_data.textures->size()));
|
||||||
|
|
||||||
conv_data.textures->push_back(new aiTexture());
|
conv_data.textures->push_back(new aiTexture());
|
||||||
aiTexture* tex = conv_data.textures->back();
|
aiTexture* curTex = conv_data.textures->back();
|
||||||
|
|
||||||
// usually 'img->name' will be the original file name of the embedded textures,
|
// usually 'img->name' will be the original file name of the embedded textures,
|
||||||
// so we can extract the file extension from it.
|
// so we can extract the file extension from it.
|
||||||
|
@ -439,19 +439,19 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
||||||
--s;
|
--s;
|
||||||
}
|
}
|
||||||
|
|
||||||
tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
|
curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
|
||||||
tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
|
curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
|
||||||
tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
|
curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
|
||||||
tex->achFormatHint[3] = '\0';
|
curTex->achFormatHint[3] = '\0';
|
||||||
|
|
||||||
// tex->mHeight = 0;
|
// tex->mHeight = 0;
|
||||||
tex->mWidth = img->packedfile->size;
|
curTex->mWidth = img->packedfile->size;
|
||||||
uint8_t* ch = new uint8_t[tex->mWidth];
|
uint8_t *ch = new uint8_t[curTex->mWidth];
|
||||||
|
|
||||||
conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
|
conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
|
||||||
conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth);
|
conv_data.db.reader->CopyAndAdvance(ch, curTex->mWidth);
|
||||||
|
|
||||||
tex->pcData = reinterpret_cast<aiTexel*>(ch);
|
curTex->pcData = reinterpret_cast<aiTexel *>(ch);
|
||||||
|
|
||||||
LogInfo("Reading embedded texture, original file was "+std::string(img->name));
|
LogInfo("Reading embedded texture, original file was "+std::string(img->name));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1078,9 +1078,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
const aiFace& f = out->mFaces[out->mNumFaces++];
|
const aiFace& f = out->mFaces[out->mNumFaces++];
|
||||||
|
|
||||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||||
vo->x = v->uv[i][0];
|
vo->x = v->uv[j][0];
|
||||||
vo->y = v->uv[i][1];
|
vo->y = v->uv[j][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,8 +1098,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
vo->x = uv.uv[0];
|
vo->x = uv.uv[0];
|
||||||
vo->y = uv.uv[1];
|
vo->y = uv.uv[1];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// create textureCoords for every mapped tex
|
// create textureCoords for every mapped tex
|
||||||
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
|
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
|
||||||
const MLoopUV *tm = itMatTexUvMapping->second[m];
|
const MLoopUV *tm = itMatTexUvMapping->second[m];
|
||||||
|
@ -1139,9 +1138,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
||||||
const aiFace& f = out->mFaces[out->mNumFaces++];
|
const aiFace& f = out->mFaces[out->mNumFaces++];
|
||||||
|
|
||||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||||
vo->x = v->uv[i][0];
|
vo->x = v->uv[j][0];
|
||||||
vo->y = v->uv[i][1];
|
vo->y = v->uv[j][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,52 +57,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Blender;
|
using namespace Assimp::Blender;
|
||||||
|
|
||||||
template <typename T> BlenderModifier* god() {
|
template <typename T>
|
||||||
|
BlenderModifier *god() {
|
||||||
return new T();
|
return new T();
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all available modifiers here
|
// add all available modifiers here
|
||||||
typedef BlenderModifier* (*fpCreateModifier)();
|
typedef BlenderModifier *(*fpCreateModifier)();
|
||||||
static const fpCreateModifier creators[] = {
|
static const fpCreateModifier creators[] = {
|
||||||
&god<BlenderModifier_Mirror>,
|
&god<BlenderModifier_Mirror>,
|
||||||
&god<BlenderModifier_Subdivision>,
|
&god<BlenderModifier_Subdivision>,
|
||||||
|
|
||||||
NULL // sentinel
|
nullptr // sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
struct SharedModifierData : ElemBase
|
struct SharedModifierData : ElemBase {
|
||||||
{
|
|
||||||
ModifierData modifier;
|
ModifierData modifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
|
void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) {
|
||||||
{
|
|
||||||
size_t cnt = 0u, ful = 0u;
|
size_t cnt = 0u, ful = 0u;
|
||||||
|
|
||||||
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
||||||
// we're allowed to dereference the pointers without risking to crash. We might still be
|
// we're allowed to dereference the pointers without risking to crash. We might still be
|
||||||
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
||||||
// structures is at offset sizeof(vftable) with no padding.
|
// structures is at offset sizeof(vftable) with no padding.
|
||||||
const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
|
const SharedModifierData *cur = static_cast<const SharedModifierData *>(orig_object.modifiers.first.get());
|
||||||
for (; cur; cur = static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
|
for (; cur; cur = static_cast<const SharedModifierData *>(cur->modifier.next.get()), ++ful) {
|
||||||
ai_assert(cur->dna_type);
|
ai_assert(cur->dna_type);
|
||||||
|
|
||||||
const Structure* s = conv_data.db.dna.Get( cur->dna_type );
|
const Structure *s = conv_data.db.dna.Get(cur->dna_type);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
|
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ", cur->dna_type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
||||||
const Field* f = s->Get("modifier");
|
const Field *f = s->Get("modifier");
|
||||||
if (!f || f->offset != 0) {
|
if (!f || f->offset != 0) {
|
||||||
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = conv_data.db.dna.Get( f->type );
|
s = conv_data.db.dna.Get(f->type);
|
||||||
if (!s || s->name != "ModifierData") {
|
if (!s || s->name != "ModifierData") {
|
||||||
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
||||||
continue;
|
continue;
|
||||||
|
@ -110,30 +109,30 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
||||||
|
|
||||||
// now, we can be sure that we should be fine to dereference *cur* as
|
// now, we can be sure that we should be fine to dereference *cur* as
|
||||||
// ModifierData (with the above note).
|
// ModifierData (with the above note).
|
||||||
const ModifierData& dat = cur->modifier;
|
const ModifierData &dat = cur->modifier;
|
||||||
|
|
||||||
const fpCreateModifier* curgod = creators;
|
const fpCreateModifier *curgod = creators;
|
||||||
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
std::vector<BlenderModifier *>::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
||||||
|
|
||||||
for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
|
for (; *curgod; ++curgod, ++curmod) { // allocate modifiers on the fly
|
||||||
if (curmod == endmod) {
|
if (curmod == endmod) {
|
||||||
cached_modifiers->push_back((*curgod)());
|
cached_modifiers->push_back((*curgod)());
|
||||||
|
|
||||||
endmod = cached_modifiers->end();
|
endmod = cached_modifiers->end();
|
||||||
curmod = endmod-1;
|
curmod = endmod - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlenderModifier* const modifier = *curmod;
|
BlenderModifier *const modifier = *curmod;
|
||||||
if(modifier->IsActive(dat)) {
|
if (modifier->IsActive(dat)) {
|
||||||
modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
|
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
curgod = NULL;
|
curgod = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curgod) {
|
if (curgod) {
|
||||||
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
|
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ", dat.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,26 +140,22 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
||||||
// object, we still can't say whether our modifier implementations were
|
// object, we still can't say whether our modifier implementations were
|
||||||
// able to fully do their job.
|
// able to fully do their job.
|
||||||
if (ful) {
|
if (ful) {
|
||||||
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
|
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name,
|
||||||
"`, check log messages above for errors");
|
"`, check log messages above for errors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
|
bool BlenderModifier_Mirror ::IsActive(const ModifierData &modin) {
|
||||||
{
|
|
||||||
return modin.type == ModifierData::eModifierType_Mirror;
|
return modin.type == ModifierData::eModifierType_Mirror;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||||
const Scene& /*in*/,
|
const Scene & /*in*/,
|
||||||
const Object& orig_object )
|
const Object &orig_object) {
|
||||||
{
|
|
||||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||||
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
|
const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier);
|
||||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
||||||
|
|
||||||
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
||||||
|
@ -169,48 +164,55 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||||
|
|
||||||
// take all input meshes and clone them
|
// take all input meshes and clone them
|
||||||
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
||||||
aiMesh* mesh;
|
aiMesh *mesh;
|
||||||
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
|
SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]);
|
||||||
|
|
||||||
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
||||||
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
||||||
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
||||||
|
|
||||||
if (mir.mirror_ob) {
|
if (mir.mirror_ob) {
|
||||||
const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
|
const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]);
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mVertices[i];
|
aiVector3D &v = mesh->mVertices[j];
|
||||||
|
|
||||||
v.x = center.x + xs*(center.x - v.x);
|
v.x = center.x + xs * (center.x - v.x);
|
||||||
v.y = center.y + ys*(center.y - v.y);
|
v.y = center.y + ys * (center.y - v.y);
|
||||||
v.z = center.z + zs*(center.z - v.z);
|
v.z = center.z + zs * (center.z - v.z);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
aiVector3D &v = mesh->mVertices[j];
|
||||||
aiVector3D& v = mesh->mVertices[i];
|
v.x *= xs;
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mNormals) {
|
if (mesh->mNormals) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mNormals[i];
|
aiVector3D &v = mesh->mNormals[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mTangents) {
|
if (mesh->mTangents) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mTangents[i];
|
aiVector3D &v = mesh->mTangents[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mBitangents) {
|
if (mesh->mBitangents) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mBitangents[i];
|
aiVector3D &v = mesh->mBitangents[j];
|
||||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
v.x *= xs;
|
||||||
|
v.y *= ys;
|
||||||
|
v.z *= zs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,55 +220,53 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
||||||
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
||||||
|
|
||||||
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||||
aiVector3D& v = mesh->mTextureCoords[n][i];
|
aiVector3D &v = mesh->mTextureCoords[n][j];
|
||||||
v.x *= us;v.y *= vs;
|
v.x *= us;
|
||||||
|
v.y *= vs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||||
if (xs * ys * zs < 0) {
|
if (xs * ys * zs < 0) {
|
||||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
|
||||||
aiFace& face = mesh->mFaces[i];
|
aiFace &face = mesh->mFaces[j];
|
||||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conv_data.meshes->push_back(mesh);
|
conv_data.meshes->push_back(mesh);
|
||||||
}
|
}
|
||||||
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
|
unsigned int *nind = new unsigned int[out.mNumMeshes * 2];
|
||||||
|
|
||||||
std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
|
std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind);
|
||||||
std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
|
std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes,
|
||||||
[&out](unsigned int n) { return out.mNumMeshes + n; });
|
[&out](unsigned int n) { return out.mNumMeshes + n; });
|
||||||
|
|
||||||
delete[] out.mMeshes;
|
delete[] out.mMeshes;
|
||||||
out.mMeshes = nind;
|
out.mMeshes = nind;
|
||||||
out.mNumMeshes *= 2;
|
out.mNumMeshes *= 2;
|
||||||
|
|
||||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
||||||
orig_object.id.name,"`");
|
orig_object.id.name, "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
|
bool BlenderModifier_Subdivision ::IsActive(const ModifierData &modin) {
|
||||||
{
|
|
||||||
return modin.type == ModifierData::eModifierType_Subsurf;
|
return modin.type == ModifierData::eModifierType_Subsurf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||||
const Scene& /*in*/,
|
const Scene & /*in*/,
|
||||||
const Object& orig_object )
|
const Object &orig_object) {
|
||||||
{
|
|
||||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||||
const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
|
const SubsurfModifierData &mir = static_cast<const SubsurfModifierData &>(orig_modifier);
|
||||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
||||||
|
|
||||||
Subdivider::Algorithm algo;
|
Subdivider::Algorithm algo;
|
||||||
switch (mir.subdivType)
|
switch (mir.subdivType) {
|
||||||
{
|
|
||||||
case SubsurfModifierData::TYPE_CatmullClarke:
|
case SubsurfModifierData::TYPE_CatmullClarke:
|
||||||
algo = Subdivider::CATMULL_CLARKE;
|
algo = Subdivider::CATMULL_CLARKE;
|
||||||
break;
|
break;
|
||||||
|
@ -277,23 +277,23 @@ void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
|
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
|
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
|
||||||
ai_assert(subd);
|
ai_assert(subd);
|
||||||
if ( conv_data.meshes->empty() ) {
|
if (conv_data.meshes->empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
||||||
std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
|
std::unique_ptr<aiMesh *[]> tempmeshes(new aiMesh *[out.mNumMeshes]());
|
||||||
|
|
||||||
subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
|
subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
|
||||||
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
|
std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
|
||||||
|
|
||||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
||||||
orig_object.id.name,"`");
|
orig_object.id.name, "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
|
@ -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
|
|
@ -48,14 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "BlenderDNA.h"
|
#include "BlenderDNA.h"
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace Blender {
|
namespace Blender {
|
||||||
|
|
||||||
// Minor parts of this file are extracts from blender data structures,
|
// Minor parts of this file are extracts from blender data structures,
|
||||||
// declared in the ./source/blender/makesdna directory.
|
// declared in the ./source/blender/makesdna directory.
|
||||||
// Stuff that is not used by Assimp is commented.
|
// Stuff that is not used by Assimp is commented.
|
||||||
|
|
||||||
|
|
||||||
// NOTE
|
// NOTE
|
||||||
// this file serves as input data to the `./scripts/genblenddna.py`
|
// this file serves as input data to the `./scripts/genblenddna.py`
|
||||||
// script. This script generates the actual binding code to read a
|
// script. This script generates the actual binding code to read a
|
||||||
|
@ -95,15 +94,15 @@ namespace Blender {
|
||||||
|
|
||||||
// warn if field is missing, substitute default value
|
// warn if field is missing, substitute default value
|
||||||
#ifdef WARN
|
#ifdef WARN
|
||||||
# undef WARN
|
#undef WARN
|
||||||
#endif
|
#endif
|
||||||
#define WARN
|
#define WARN
|
||||||
|
|
||||||
// fail the import if the field does not exist
|
// fail the import if the field does not exist
|
||||||
#ifdef FAIL
|
#ifdef FAIL
|
||||||
# undef FAIL
|
#undef FAIL
|
||||||
#endif
|
#endif
|
||||||
#define FAIL
|
#define FAIL
|
||||||
|
|
||||||
struct Object;
|
struct Object;
|
||||||
struct MTex;
|
struct MTex;
|
||||||
|
@ -117,7 +116,7 @@ static const size_t MaxNameLen = 1024;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct ID : ElemBase {
|
struct ID : ElemBase {
|
||||||
char name[ MaxNameLen ] WARN;
|
char name[MaxNameLen] WARN;
|
||||||
short flag;
|
short flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,17 +126,16 @@ struct ListBase : ElemBase {
|
||||||
std::shared_ptr<ElemBase> last;
|
std::shared_ptr<ElemBase> last;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct PackedFile : ElemBase {
|
struct PackedFile : ElemBase {
|
||||||
int size WARN;
|
int size WARN;
|
||||||
int seek WARN;
|
int seek WARN;
|
||||||
std::shared_ptr< FileOffset > data WARN;
|
std::shared_ptr<FileOffset> data WARN;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct GroupObject : ElemBase {
|
struct GroupObject : ElemBase {
|
||||||
std::shared_ptr<GroupObject> prev,next FAIL;
|
std::shared_ptr<GroupObject> prev, next FAIL;
|
||||||
std::shared_ptr<Object> ob;
|
std::shared_ptr<Object> ob;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,23 +155,20 @@ struct World : ElemBase {
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MVert : ElemBase {
|
struct MVert : ElemBase {
|
||||||
float co[3] FAIL;
|
float co[3] FAIL;
|
||||||
float no[3] FAIL; // readed as short and divided through / 32767.f
|
float no[3] FAIL; // readed as short and divided through / 32767.f
|
||||||
char flag;
|
char flag;
|
||||||
int mat_nr WARN;
|
int mat_nr WARN;
|
||||||
int bweight;
|
int bweight;
|
||||||
|
|
||||||
MVert() : ElemBase()
|
MVert() :
|
||||||
, flag(0)
|
ElemBase(), flag(0), mat_nr(0), bweight(0) {}
|
||||||
, mat_nr(0)
|
|
||||||
, bweight(0)
|
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MEdge : ElemBase {
|
struct MEdge : ElemBase {
|
||||||
int v1, v2 FAIL;
|
int v1, v2 FAIL;
|
||||||
char crease, bweight;
|
char crease, bweight;
|
||||||
short flag;
|
short flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@ -190,7 +185,7 @@ struct MLoopUV : ElemBase {
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Note that red and blue are not swapped, as with MCol
|
// Note that red and blue are not swapped, as with MCol
|
||||||
struct MLoopCol : ElemBase {
|
struct MLoopCol : ElemBase {
|
||||||
unsigned char r, g, b, a;
|
unsigned char r, g, b, a;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@ -203,19 +198,19 @@ struct MPoly : ElemBase {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MTexPoly : ElemBase {
|
struct MTexPoly : ElemBase {
|
||||||
Image* tpage;
|
Image *tpage;
|
||||||
char flag, transp;
|
char flag, transp;
|
||||||
short mode, tile, pad;
|
short mode, tile, pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MCol : ElemBase {
|
struct MCol : ElemBase {
|
||||||
char r,g,b,a FAIL;
|
char r, g, b, a FAIL;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MFace : ElemBase {
|
struct MFace : ElemBase {
|
||||||
int v1,v2,v3,v4 FAIL;
|
int v1, v2, v3, v4 FAIL;
|
||||||
int mat_nr FAIL;
|
int mat_nr FAIL;
|
||||||
char flag;
|
char flag;
|
||||||
};
|
};
|
||||||
|
@ -232,13 +227,9 @@ struct TFace : ElemBase {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MTFace : ElemBase {
|
struct MTFace : ElemBase {
|
||||||
MTFace()
|
MTFace() :
|
||||||
: flag(0)
|
flag(0), mode(0), tile(0), unwrap(0) {
|
||||||
, mode(0)
|
}
|
||||||
, tile(0)
|
|
||||||
, unwrap(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
float uv[4][2] FAIL;
|
float uv[4][2] FAIL;
|
||||||
char flag;
|
char flag;
|
||||||
|
@ -250,31 +241,31 @@ struct MTFace : ElemBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MDeformWeight : ElemBase {
|
struct MDeformWeight : ElemBase {
|
||||||
int def_nr FAIL;
|
int def_nr FAIL;
|
||||||
float weight FAIL;
|
float weight FAIL;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct MDeformVert : ElemBase {
|
struct MDeformVert : ElemBase {
|
||||||
vector<MDeformWeight> dw WARN;
|
vector<MDeformWeight> dw WARN;
|
||||||
int totweight;
|
int totweight;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
#define MA_RAYMIRROR 0x40000
|
#define MA_RAYMIRROR 0x40000
|
||||||
#define MA_TRANSPARENCY 0x10000
|
#define MA_TRANSPARENCY 0x10000
|
||||||
#define MA_RAYTRANSP 0x20000
|
#define MA_RAYTRANSP 0x20000
|
||||||
#define MA_ZTRANSP 0x00040
|
#define MA_ZTRANSP 0x00040
|
||||||
|
|
||||||
struct Material : ElemBase {
|
struct Material : ElemBase {
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
|
|
||||||
float r,g,b WARN;
|
float r, g, b WARN;
|
||||||
float specr,specg,specb WARN;
|
float specr, specg, specb WARN;
|
||||||
short har;
|
short har;
|
||||||
float ambr,ambg,ambb WARN;
|
float ambr, ambg, ambb WARN;
|
||||||
float mirr,mirg,mirb;
|
float mirr, mirg, mirb;
|
||||||
float emit WARN;
|
float emit WARN;
|
||||||
float ray_mirror;
|
float ray_mirror;
|
||||||
float alpha WARN;
|
float alpha WARN;
|
||||||
|
@ -399,20 +390,19 @@ struct CustomDataLayer : ElemBase {
|
||||||
int active_mask;
|
int active_mask;
|
||||||
int uid;
|
int uid;
|
||||||
char name[64];
|
char name[64];
|
||||||
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
|
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
|
||||||
|
|
||||||
CustomDataLayer()
|
CustomDataLayer() :
|
||||||
: ElemBase()
|
ElemBase(),
|
||||||
, type(0)
|
type(0),
|
||||||
, offset(0)
|
offset(0),
|
||||||
, flag(0)
|
flag(0),
|
||||||
, active(0)
|
active(0),
|
||||||
, active_rnd(0)
|
active_rnd(0),
|
||||||
, active_clone(0)
|
active_clone(0),
|
||||||
, active_mask(0)
|
active_mask(0),
|
||||||
, uid(0)
|
uid(0),
|
||||||
, data(nullptr)
|
data(nullptr) {
|
||||||
{
|
|
||||||
memset(name, 0, sizeof name);
|
memset(name, 0, sizeof name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -430,8 +420,8 @@ CustomData 208
|
||||||
CustomDataExternal *external 200 8
|
CustomDataExternal *external 200 8
|
||||||
*/
|
*/
|
||||||
struct CustomData : ElemBase {
|
struct CustomData : ElemBase {
|
||||||
vector<std::shared_ptr<struct CustomDataLayer> > layers;
|
vector<std::shared_ptr<struct CustomDataLayer>> layers;
|
||||||
int typemap[42]; // CD_NUMTYPES
|
int typemap[42]; // CD_NUMTYPES
|
||||||
int totlayer;
|
int totlayer;
|
||||||
int maxlayer;
|
int maxlayer;
|
||||||
int totsize;
|
int totsize;
|
||||||
|
@ -469,7 +459,7 @@ struct Mesh : ElemBase {
|
||||||
vector<MDeformVert> dvert;
|
vector<MDeformVert> dvert;
|
||||||
vector<MCol> mcol;
|
vector<MCol> mcol;
|
||||||
|
|
||||||
vector< std::shared_ptr<Material> > mat FAIL;
|
vector<std::shared_ptr<Material>> mat FAIL;
|
||||||
|
|
||||||
struct CustomData vdata;
|
struct CustomData vdata;
|
||||||
struct CustomData edata;
|
struct CustomData edata;
|
||||||
|
@ -490,142 +480,141 @@ struct Library : ElemBase {
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Camera : ElemBase {
|
struct Camera : ElemBase {
|
||||||
enum Type {
|
enum Type {
|
||||||
Type_PERSP = 0
|
Type_PERSP = 0,
|
||||||
,Type_ORTHO = 1
|
Type_ORTHO = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
|
|
||||||
Type type,flag WARN;
|
Type type, flag WARN;
|
||||||
float lens WARN;
|
float lens WARN;
|
||||||
float sensor_x WARN;
|
float sensor_x WARN;
|
||||||
float clipsta, clipend;
|
float clipsta, clipend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Lamp : ElemBase {
|
struct Lamp : ElemBase {
|
||||||
|
|
||||||
enum FalloffType {
|
enum FalloffType {
|
||||||
FalloffType_Constant = 0x0
|
FalloffType_Constant = 0x0,
|
||||||
,FalloffType_InvLinear = 0x1
|
FalloffType_InvLinear = 0x1,
|
||||||
,FalloffType_InvSquare = 0x2
|
FalloffType_InvSquare = 0x2
|
||||||
//,FalloffType_Curve = 0x3
|
//,FalloffType_Curve = 0x3
|
||||||
//,FalloffType_Sliders = 0x4
|
//,FalloffType_Sliders = 0x4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
Type_Local = 0x0
|
Type_Local = 0x0,
|
||||||
,Type_Sun = 0x1
|
Type_Sun = 0x1,
|
||||||
,Type_Spot = 0x2
|
Type_Spot = 0x2,
|
||||||
,Type_Hemi = 0x3
|
Type_Hemi = 0x3,
|
||||||
,Type_Area = 0x4
|
Type_Area = 0x4
|
||||||
//,Type_YFPhoton = 0x5
|
//,Type_YFPhoton = 0x5
|
||||||
};
|
};
|
||||||
|
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
//AnimData *adt;
|
//AnimData *adt;
|
||||||
|
|
||||||
Type type FAIL;
|
Type type FAIL;
|
||||||
short flags;
|
short flags;
|
||||||
|
|
||||||
//int mode;
|
//int mode;
|
||||||
|
|
||||||
short colormodel, totex;
|
short colormodel, totex;
|
||||||
float r,g,b,k WARN;
|
float r, g, b, k WARN;
|
||||||
//float shdwr, shdwg, shdwb;
|
//float shdwr, shdwg, shdwb;
|
||||||
|
|
||||||
float energy, dist, spotsize, spotblend;
|
float energy, dist, spotsize, spotblend;
|
||||||
//float haint;
|
//float haint;
|
||||||
|
|
||||||
float constant_coefficient;
|
float constant_coefficient;
|
||||||
float linear_coefficient;
|
float linear_coefficient;
|
||||||
float quadratic_coefficient;
|
float quadratic_coefficient;
|
||||||
|
|
||||||
float att1, att2;
|
float att1, att2;
|
||||||
//struct CurveMapping *curfalloff;
|
//struct CurveMapping *curfalloff;
|
||||||
FalloffType falloff_type;
|
FalloffType falloff_type;
|
||||||
|
|
||||||
//float clipsta, clipend, shadspotsize;
|
//float clipsta, clipend, shadspotsize;
|
||||||
//float bias, soft, compressthresh;
|
//float bias, soft, compressthresh;
|
||||||
//short bufsize, samp, buffers, filtertype;
|
//short bufsize, samp, buffers, filtertype;
|
||||||
//char bufflag, buftype;
|
//char bufflag, buftype;
|
||||||
|
|
||||||
//short ray_samp, ray_sampy, ray_sampz;
|
//short ray_samp, ray_sampy, ray_sampz;
|
||||||
//short ray_samp_type;
|
//short ray_samp_type;
|
||||||
short area_shape;
|
short area_shape;
|
||||||
float area_size, area_sizey, area_sizez;
|
float area_size, area_sizey, area_sizez;
|
||||||
//float adapt_thresh;
|
//float adapt_thresh;
|
||||||
//short ray_samp_method;
|
//short ray_samp_method;
|
||||||
|
|
||||||
//short texact, shadhalostep;
|
//short texact, shadhalostep;
|
||||||
|
|
||||||
//short sun_effect_type;
|
//short sun_effect_type;
|
||||||
//short skyblendtype;
|
//short skyblendtype;
|
||||||
//float horizon_brightness;
|
//float horizon_brightness;
|
||||||
//float spread;
|
//float spread;
|
||||||
float sun_brightness;
|
float sun_brightness;
|
||||||
//float sun_size;
|
//float sun_size;
|
||||||
//float backscattered_light;
|
//float backscattered_light;
|
||||||
//float sun_intensity;
|
//float sun_intensity;
|
||||||
//float atm_turbidity;
|
//float atm_turbidity;
|
||||||
//float atm_inscattering_factor;
|
//float atm_inscattering_factor;
|
||||||
//float atm_extinction_factor;
|
//float atm_extinction_factor;
|
||||||
//float atm_distance_factor;
|
//float atm_distance_factor;
|
||||||
//float skyblendfac;
|
//float skyblendfac;
|
||||||
//float sky_exposure;
|
//float sky_exposure;
|
||||||
//short sky_colorspace;
|
//short sky_colorspace;
|
||||||
|
|
||||||
// int YF_numphotons, YF_numsearch;
|
// int YF_numphotons, YF_numsearch;
|
||||||
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
|
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
|
||||||
// float YF_causticblur, YF_ltradius;
|
// float YF_causticblur, YF_ltradius;
|
||||||
|
|
||||||
// float YF_glowint, YF_glowofs;
|
// float YF_glowint, YF_glowofs;
|
||||||
// short YF_glowtype, YF_pad2;
|
// short YF_glowtype, YF_pad2;
|
||||||
|
|
||||||
//struct Ipo *ipo;
|
//struct Ipo *ipo;
|
||||||
//struct MTex *mtex[18];
|
//struct MTex *mtex[18];
|
||||||
// short pr_texture;
|
// short pr_texture;
|
||||||
|
|
||||||
//struct PreviewImage *preview;
|
//struct PreviewImage *preview;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct ModifierData : ElemBase {
|
struct ModifierData : ElemBase {
|
||||||
enum ModifierType {
|
enum ModifierType {
|
||||||
eModifierType_None = 0,
|
eModifierType_None = 0,
|
||||||
eModifierType_Subsurf,
|
eModifierType_Subsurf,
|
||||||
eModifierType_Lattice,
|
eModifierType_Lattice,
|
||||||
eModifierType_Curve,
|
eModifierType_Curve,
|
||||||
eModifierType_Build,
|
eModifierType_Build,
|
||||||
eModifierType_Mirror,
|
eModifierType_Mirror,
|
||||||
eModifierType_Decimate,
|
eModifierType_Decimate,
|
||||||
eModifierType_Wave,
|
eModifierType_Wave,
|
||||||
eModifierType_Armature,
|
eModifierType_Armature,
|
||||||
eModifierType_Hook,
|
eModifierType_Hook,
|
||||||
eModifierType_Softbody,
|
eModifierType_Softbody,
|
||||||
eModifierType_Boolean,
|
eModifierType_Boolean,
|
||||||
eModifierType_Array,
|
eModifierType_Array,
|
||||||
eModifierType_EdgeSplit,
|
eModifierType_EdgeSplit,
|
||||||
eModifierType_Displace,
|
eModifierType_Displace,
|
||||||
eModifierType_UVProject,
|
eModifierType_UVProject,
|
||||||
eModifierType_Smooth,
|
eModifierType_Smooth,
|
||||||
eModifierType_Cast,
|
eModifierType_Cast,
|
||||||
eModifierType_MeshDeform,
|
eModifierType_MeshDeform,
|
||||||
eModifierType_ParticleSystem,
|
eModifierType_ParticleSystem,
|
||||||
eModifierType_ParticleInstance,
|
eModifierType_ParticleInstance,
|
||||||
eModifierType_Explode,
|
eModifierType_Explode,
|
||||||
eModifierType_Cloth,
|
eModifierType_Cloth,
|
||||||
eModifierType_Collision,
|
eModifierType_Collision,
|
||||||
eModifierType_Bevel,
|
eModifierType_Bevel,
|
||||||
eModifierType_Shrinkwrap,
|
eModifierType_Shrinkwrap,
|
||||||
eModifierType_Fluidsim,
|
eModifierType_Fluidsim,
|
||||||
eModifierType_Mask,
|
eModifierType_Mask,
|
||||||
eModifierType_SimpleDeform,
|
eModifierType_SimpleDeform,
|
||||||
eModifierType_Multires,
|
eModifierType_Multires,
|
||||||
eModifierType_Surface,
|
eModifierType_Surface,
|
||||||
eModifierType_Smoke,
|
eModifierType_Smoke,
|
||||||
eModifierType_ShapeKey
|
eModifierType_ShapeKey
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<ElemBase> next WARN;
|
std::shared_ptr<ElemBase> next WARN;
|
||||||
|
@ -636,7 +625,7 @@ struct ModifierData : ElemBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct SubsurfModifierData : ElemBase {
|
struct SubsurfModifierData : ElemBase {
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
|
||||||
|
@ -646,13 +635,13 @@ struct SubsurfModifierData : ElemBase {
|
||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
// some omitted
|
// some omitted
|
||||||
FLAGS_SubsurfUV =1<<3
|
FLAGS_SubsurfUV = 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
ModifierData modifier FAIL;
|
ModifierData modifier FAIL;
|
||||||
short subdivType WARN;
|
short subdivType WARN;
|
||||||
short levels FAIL;
|
short levels FAIL;
|
||||||
short renderLevels ;
|
short renderLevels;
|
||||||
short flags;
|
short flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -660,13 +649,13 @@ struct SubsurfModifierData : ElemBase {
|
||||||
struct MirrorModifierData : ElemBase {
|
struct MirrorModifierData : ElemBase {
|
||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
Flags_CLIPPING =1<<0,
|
Flags_CLIPPING = 1 << 0,
|
||||||
Flags_MIRROR_U =1<<1,
|
Flags_MIRROR_U = 1 << 1,
|
||||||
Flags_MIRROR_V =1<<2,
|
Flags_MIRROR_V = 1 << 2,
|
||||||
Flags_AXIS_X =1<<3,
|
Flags_AXIS_X = 1 << 3,
|
||||||
Flags_AXIS_Y =1<<4,
|
Flags_AXIS_Y = 1 << 4,
|
||||||
Flags_AXIS_Z =1<<5,
|
Flags_AXIS_Z = 1 << 5,
|
||||||
Flags_VGROUP =1<<6
|
Flags_VGROUP = 1 << 6
|
||||||
};
|
};
|
||||||
|
|
||||||
ModifierData modifier FAIL;
|
ModifierData modifier FAIL;
|
||||||
|
@ -677,22 +666,24 @@ struct MirrorModifierData : ElemBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Object : ElemBase {
|
struct Object : ElemBase {
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
Type_EMPTY = 0
|
Type_EMPTY = 0,
|
||||||
,Type_MESH = 1
|
Type_MESH = 1,
|
||||||
,Type_CURVE = 2
|
Type_CURVE = 2,
|
||||||
,Type_SURF = 3
|
Type_SURF = 3,
|
||||||
,Type_FONT = 4
|
Type_FONT = 4,
|
||||||
,Type_MBALL = 5
|
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;
|
Type type FAIL;
|
||||||
|
@ -700,39 +691,29 @@ struct Object : ElemBase {
|
||||||
float parentinv[4][4] WARN;
|
float parentinv[4][4] WARN;
|
||||||
char parsubstr[32] WARN;
|
char parsubstr[32] WARN;
|
||||||
|
|
||||||
Object* parent WARN;
|
Object *parent WARN;
|
||||||
std::shared_ptr<Object> track WARN;
|
std::shared_ptr<Object> track WARN;
|
||||||
|
|
||||||
std::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
|
std::shared_ptr<Object> proxy, proxy_from, proxy_group WARN;
|
||||||
std::shared_ptr<Group> dup_group WARN;
|
std::shared_ptr<Group> dup_group WARN;
|
||||||
std::shared_ptr<ElemBase> data FAIL;
|
std::shared_ptr<ElemBase> data FAIL;
|
||||||
|
|
||||||
ListBase modifiers;
|
ListBase modifiers;
|
||||||
|
|
||||||
Object()
|
Object() :
|
||||||
: ElemBase()
|
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
|
||||||
, type( Type_EMPTY )
|
|
||||||
, parent( nullptr )
|
|
||||||
, track()
|
|
||||||
, proxy()
|
|
||||||
, proxy_from()
|
|
||||||
, data() {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct Base : ElemBase {
|
struct Base : ElemBase {
|
||||||
Base* prev WARN;
|
Base *prev WARN;
|
||||||
std::shared_ptr<Base> next WARN;
|
std::shared_ptr<Base> next WARN;
|
||||||
std::shared_ptr<Object> object WARN;
|
std::shared_ptr<Object> object WARN;
|
||||||
|
|
||||||
Base()
|
Base() :
|
||||||
: ElemBase()
|
ElemBase(), prev(nullptr), next(), object() {
|
||||||
, prev( nullptr )
|
|
||||||
, next()
|
|
||||||
, object() {
|
|
||||||
// empty
|
// empty
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
@ -748,11 +729,8 @@ struct Scene : ElemBase {
|
||||||
|
|
||||||
ListBase base;
|
ListBase base;
|
||||||
|
|
||||||
Scene()
|
Scene() :
|
||||||
: ElemBase()
|
ElemBase(), camera(), world(), basact() {
|
||||||
, camera()
|
|
||||||
, world()
|
|
||||||
, basact() {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -783,9 +761,9 @@ struct Image : ElemBase {
|
||||||
short animspeed;
|
short animspeed;
|
||||||
|
|
||||||
short gen_x, gen_y, gen_type;
|
short gen_x, gen_y, gen_type;
|
||||||
|
|
||||||
Image()
|
Image() :
|
||||||
: ElemBase() {
|
ElemBase() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -795,33 +773,33 @@ struct Tex : ElemBase {
|
||||||
|
|
||||||
// actually, the only texture type we support is Type_IMAGE
|
// actually, the only texture type we support is Type_IMAGE
|
||||||
enum Type {
|
enum Type {
|
||||||
Type_CLOUDS = 1
|
Type_CLOUDS = 1,
|
||||||
,Type_WOOD = 2
|
Type_WOOD = 2,
|
||||||
,Type_MARBLE = 3
|
Type_MARBLE = 3,
|
||||||
,Type_MAGIC = 4
|
Type_MAGIC = 4,
|
||||||
,Type_BLEND = 5
|
Type_BLEND = 5,
|
||||||
,Type_STUCCI = 6
|
Type_STUCCI = 6,
|
||||||
,Type_NOISE = 7
|
Type_NOISE = 7,
|
||||||
,Type_IMAGE = 8
|
Type_IMAGE = 8,
|
||||||
,Type_PLUGIN = 9
|
Type_PLUGIN = 9,
|
||||||
,Type_ENVMAP = 10
|
Type_ENVMAP = 10,
|
||||||
,Type_MUSGRAVE = 11
|
Type_MUSGRAVE = 11,
|
||||||
,Type_VORONOI = 12
|
Type_VORONOI = 12,
|
||||||
,Type_DISTNOISE = 13
|
Type_DISTNOISE = 13,
|
||||||
,Type_POINTDENSITY = 14
|
Type_POINTDENSITY = 14,
|
||||||
,Type_VOXELDATA = 15
|
Type_VOXELDATA = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ImageFlags {
|
enum ImageFlags {
|
||||||
ImageFlags_INTERPOL = 1
|
ImageFlags_INTERPOL = 1,
|
||||||
,ImageFlags_USEALPHA = 2
|
ImageFlags_USEALPHA = 2,
|
||||||
,ImageFlags_MIPMAP = 4
|
ImageFlags_MIPMAP = 4,
|
||||||
,ImageFlags_IMAROT = 16
|
ImageFlags_IMAROT = 16,
|
||||||
,ImageFlags_CALCALPHA = 32
|
ImageFlags_CALCALPHA = 32,
|
||||||
,ImageFlags_NORMALMAP = 2048
|
ImageFlags_NORMALMAP = 2048,
|
||||||
,ImageFlags_GAUSS_MIP = 4096
|
ImageFlags_GAUSS_MIP = 4096,
|
||||||
,ImageFlags_FILTER_MIN = 8192
|
ImageFlags_FILTER_MIN = 8192,
|
||||||
,ImageFlags_DERIVATIVEMAP = 16384
|
ImageFlags_DERIVATIVEMAP = 16384
|
||||||
};
|
};
|
||||||
|
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
|
@ -876,11 +854,8 @@ struct Tex : ElemBase {
|
||||||
|
|
||||||
//char use_nodes;
|
//char use_nodes;
|
||||||
|
|
||||||
Tex()
|
Tex() :
|
||||||
: ElemBase()
|
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
|
||||||
, imaflag( ImageFlags_INTERPOL )
|
|
||||||
, type( Type_CLOUDS )
|
|
||||||
, ima() {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -889,52 +864,52 @@ struct Tex : ElemBase {
|
||||||
struct MTex : ElemBase {
|
struct MTex : ElemBase {
|
||||||
|
|
||||||
enum Projection {
|
enum Projection {
|
||||||
Proj_N = 0
|
Proj_N = 0,
|
||||||
,Proj_X = 1
|
Proj_X = 1,
|
||||||
,Proj_Y = 2
|
Proj_Y = 2,
|
||||||
,Proj_Z = 3
|
Proj_Z = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Flag {
|
enum Flag {
|
||||||
Flag_RGBTOINT = 0x1
|
Flag_RGBTOINT = 0x1,
|
||||||
,Flag_STENCIL = 0x2
|
Flag_STENCIL = 0x2,
|
||||||
,Flag_NEGATIVE = 0x4
|
Flag_NEGATIVE = 0x4,
|
||||||
,Flag_ALPHAMIX = 0x8
|
Flag_ALPHAMIX = 0x8,
|
||||||
,Flag_VIEWSPACE = 0x10
|
Flag_VIEWSPACE = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BlendType {
|
enum BlendType {
|
||||||
BlendType_BLEND = 0
|
BlendType_BLEND = 0,
|
||||||
,BlendType_MUL = 1
|
BlendType_MUL = 1,
|
||||||
,BlendType_ADD = 2
|
BlendType_ADD = 2,
|
||||||
,BlendType_SUB = 3
|
BlendType_SUB = 3,
|
||||||
,BlendType_DIV = 4
|
BlendType_DIV = 4,
|
||||||
,BlendType_DARK = 5
|
BlendType_DARK = 5,
|
||||||
,BlendType_DIFF = 6
|
BlendType_DIFF = 6,
|
||||||
,BlendType_LIGHT = 7
|
BlendType_LIGHT = 7,
|
||||||
,BlendType_SCREEN = 8
|
BlendType_SCREEN = 8,
|
||||||
,BlendType_OVERLAY = 9
|
BlendType_OVERLAY = 9,
|
||||||
,BlendType_BLEND_HUE = 10
|
BlendType_BLEND_HUE = 10,
|
||||||
,BlendType_BLEND_SAT = 11
|
BlendType_BLEND_SAT = 11,
|
||||||
,BlendType_BLEND_VAL = 12
|
BlendType_BLEND_VAL = 12,
|
||||||
,BlendType_BLEND_COLOR = 13
|
BlendType_BLEND_COLOR = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MapType {
|
enum MapType {
|
||||||
MapType_COL = 1
|
MapType_COL = 1,
|
||||||
,MapType_NORM = 2
|
MapType_NORM = 2,
|
||||||
,MapType_COLSPEC = 4
|
MapType_COLSPEC = 4,
|
||||||
,MapType_COLMIR = 8
|
MapType_COLMIR = 8,
|
||||||
,MapType_REF = 16
|
MapType_REF = 16,
|
||||||
,MapType_SPEC = 32
|
MapType_SPEC = 32,
|
||||||
,MapType_EMIT = 64
|
MapType_EMIT = 64,
|
||||||
,MapType_ALPHA = 128
|
MapType_ALPHA = 128,
|
||||||
,MapType_HAR = 256
|
MapType_HAR = 256,
|
||||||
,MapType_RAYMIRR = 512
|
MapType_RAYMIRR = 512,
|
||||||
,MapType_TRANSLU = 1024
|
MapType_TRANSLU = 1024,
|
||||||
,MapType_AMB = 2048
|
MapType_AMB = 2048,
|
||||||
,MapType_DISPLACE = 4096
|
MapType_DISPLACE = 4096,
|
||||||
,MapType_WARP = 8192
|
MapType_WARP = 8192
|
||||||
};
|
};
|
||||||
|
|
||||||
// short texco, maptoneg;
|
// short texco, maptoneg;
|
||||||
|
@ -945,7 +920,7 @@ struct MTex : ElemBase {
|
||||||
std::shared_ptr<Tex> tex;
|
std::shared_ptr<Tex> tex;
|
||||||
char uvname[32];
|
char uvname[32];
|
||||||
|
|
||||||
Projection projx,projy,projz;
|
Projection projx, projy, projz;
|
||||||
char mapping;
|
char mapping;
|
||||||
float ofs[3], size[3], rot;
|
float ofs[3], size[3], rot;
|
||||||
|
|
||||||
|
@ -953,7 +928,7 @@ struct MTex : ElemBase {
|
||||||
short colormodel, pmapto, pmaptoneg;
|
short colormodel, pmapto, pmaptoneg;
|
||||||
//short normapspace, which_output;
|
//short normapspace, which_output;
|
||||||
//char brush_map_mode;
|
//char brush_map_mode;
|
||||||
float r,g,b,k WARN;
|
float r, g, b, k WARN;
|
||||||
//float def_var, rt;
|
//float def_var, rt;
|
||||||
|
|
||||||
//float colfac, varfac;
|
//float colfac, varfac;
|
||||||
|
@ -972,12 +947,12 @@ struct MTex : ElemBase {
|
||||||
//float shadowfac;
|
//float shadowfac;
|
||||||
//float zenupfac, zendownfac, blendfac;
|
//float zenupfac, zendownfac, blendfac;
|
||||||
|
|
||||||
MTex()
|
MTex() :
|
||||||
: ElemBase() {
|
ElemBase() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Blender
|
||||||
}
|
} // namespace Assimp
|
||||||
#endif
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -75,10 +75,10 @@ struct Face
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
/** COB chunk header information */
|
/** COB chunk header information */
|
||||||
|
const unsigned int NO_SIZE = UINT_MAX;
|
||||||
|
|
||||||
struct ChunkInfo
|
struct ChunkInfo
|
||||||
{
|
{
|
||||||
enum {NO_SIZE=UINT_MAX};
|
|
||||||
|
|
||||||
ChunkInfo ()
|
ChunkInfo ()
|
||||||
: id (0)
|
: id (0)
|
||||||
, parent_id (0)
|
, parent_id (0)
|
|
@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
*ot++ = *buffer++;
|
*ot++ = *buffer++;
|
||||||
|
|
||||||
*ot = '\0';
|
*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());
|
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "ColladaHelper.h"
|
#include "ColladaHelper.h"
|
||||||
|
|
||||||
#include <assimp/commonMetaData.h>
|
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
|
#include <assimp/commonMetaData.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace Collada {
|
namespace Collada {
|
||||||
|
@ -63,42 +63,35 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
|
||||||
|
|
||||||
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
|
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
|
||||||
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
|
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
|
||||||
for (auto &val : result)
|
for (auto &val : result) {
|
||||||
{
|
|
||||||
ToCamelCase(val.first);
|
ToCamelCase(val.first);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
|
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
|
||||||
{
|
|
||||||
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
|
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
|
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
|
||||||
void ToCamelCase(std::string &text)
|
void ToCamelCase(std::string &text) {
|
||||||
{
|
|
||||||
if (text.empty())
|
if (text.empty())
|
||||||
return;
|
return;
|
||||||
// Capitalise first character
|
// Capitalise first character
|
||||||
auto it = text.begin();
|
auto it = text.begin();
|
||||||
(*it) = ToUpper(*it);
|
(*it) = ToUpper(*it);
|
||||||
++it;
|
++it;
|
||||||
for (/*started above*/ ; it != text.end(); /*iterated below*/)
|
for (/*started above*/; it != text.end(); /*iterated below*/) {
|
||||||
{
|
if ((*it) == '_') {
|
||||||
if ((*it) == '_')
|
|
||||||
{
|
|
||||||
it = text.erase(it);
|
it = text.erase(it);
|
||||||
if (it != text.end())
|
if (it != text.end())
|
||||||
(*it) = ToUpper(*it);
|
(*it) = ToUpper(*it);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Make lower case
|
// Make lower case
|
||||||
(*it) = ToLower(*it);
|
(*it) = ToLower(*it);
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -45,31 +45,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_COLLADAHELPER_H_INC
|
#ifndef AI_COLLADAHELPER_H_INC
|
||||||
#define AI_COLLADAHELPER_H_INC
|
#define AI_COLLADAHELPER_H_INC
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <set>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <assimp/light.h>
|
#include <assimp/light.h>
|
||||||
#include <assimp/mesh.h>
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct aiMaterial;
|
struct aiMaterial;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace Collada {
|
namespace Collada {
|
||||||
|
|
||||||
/** Collada file versions which evolved during the years ... */
|
/** Collada file versions which evolved during the years ... */
|
||||||
enum FormatVersion
|
enum FormatVersion {
|
||||||
{
|
|
||||||
FV_1_5_n,
|
FV_1_5_n,
|
||||||
FV_1_4_n,
|
FV_1_4_n,
|
||||||
FV_1_3_n
|
FV_1_3_n
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Transformation types that can be applied to a node */
|
/** Transformation types that can be applied to a node */
|
||||||
enum TransformType
|
enum TransformType {
|
||||||
{
|
|
||||||
TF_LOOKAT,
|
TF_LOOKAT,
|
||||||
TF_ROTATE,
|
TF_ROTATE,
|
||||||
TF_TRANSLATE,
|
TF_TRANSLATE,
|
||||||
|
@ -79,10 +76,9 @@ enum TransformType
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Different types of input data to a vertex or face */
|
/** Different types of input data to a vertex or face */
|
||||||
enum InputType
|
enum InputType {
|
||||||
{
|
|
||||||
IT_Invalid,
|
IT_Invalid,
|
||||||
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
||||||
IT_Position,
|
IT_Position,
|
||||||
IT_Normal,
|
IT_Normal,
|
||||||
IT_Texcoord,
|
IT_Texcoord,
|
||||||
|
@ -92,15 +88,13 @@ enum InputType
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Supported controller types */
|
/** Supported controller types */
|
||||||
enum ControllerType
|
enum ControllerType {
|
||||||
{
|
|
||||||
Skin,
|
Skin,
|
||||||
Morph
|
Morph
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Supported morph methods */
|
/** Supported morph methods */
|
||||||
enum MorphMethod
|
enum MorphMethod {
|
||||||
{
|
|
||||||
Normalized,
|
Normalized,
|
||||||
Relative
|
Relative
|
||||||
};
|
};
|
||||||
|
@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
|
||||||
void ToCamelCase(std::string &text);
|
void ToCamelCase(std::string &text);
|
||||||
|
|
||||||
/** Contains all data for one of the different transformation types */
|
/** Contains all data for one of the different transformation types */
|
||||||
struct Transform
|
struct Transform {
|
||||||
{
|
std::string mID; ///< SID of the transform step, by which anim channels address their target node
|
||||||
std::string mID; ///< SID of the transform step, by which anim channels address their target node
|
|
||||||
TransformType mType;
|
TransformType mType;
|
||||||
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
|
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A collada camera. */
|
/** A collada camera. */
|
||||||
struct Camera
|
struct Camera {
|
||||||
{
|
Camera() :
|
||||||
Camera()
|
mOrtho(false),
|
||||||
: mOrtho (false)
|
mHorFov(10e10f),
|
||||||
, mHorFov (10e10f)
|
mVerFov(10e10f),
|
||||||
, mVerFov (10e10f)
|
mAspect(10e10f),
|
||||||
, mAspect (10e10f)
|
mZNear(0.1f),
|
||||||
, mZNear (0.1f)
|
mZFar(1000.f) {}
|
||||||
, mZFar (1000.f)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Name of camera
|
// Name of camera
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
@ -159,19 +150,17 @@ struct Camera
|
||||||
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
|
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
|
||||||
|
|
||||||
/** A collada light source. */
|
/** A collada light source. */
|
||||||
struct Light
|
struct Light {
|
||||||
{
|
Light() :
|
||||||
Light()
|
mType(aiLightSource_UNDEFINED),
|
||||||
: mType (aiLightSource_UNDEFINED)
|
mAttConstant(1.f),
|
||||||
, mAttConstant (1.f)
|
mAttLinear(0.f),
|
||||||
, mAttLinear (0.f)
|
mAttQuadratic(0.f),
|
||||||
, mAttQuadratic (0.f)
|
mFalloffAngle(180.f),
|
||||||
, mFalloffAngle (180.f)
|
mFalloffExponent(0.f),
|
||||||
, mFalloffExponent (0.f)
|
mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
|
||||||
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
|
||||||
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
mIntensity(1.f) {}
|
||||||
, mIntensity (1.f)
|
|
||||||
{}
|
|
||||||
|
|
||||||
//! Type of the light source aiLightSourceType + ambient
|
//! Type of the light source aiLightSourceType + ambient
|
||||||
unsigned int mType;
|
unsigned int mType;
|
||||||
|
@ -180,7 +169,7 @@ struct Light
|
||||||
aiColor3D mColor;
|
aiColor3D mColor;
|
||||||
|
|
||||||
//! Light attenuation
|
//! Light attenuation
|
||||||
ai_real mAttConstant,mAttLinear,mAttQuadratic;
|
ai_real mAttConstant, mAttLinear, mAttQuadratic;
|
||||||
|
|
||||||
//! Spot light falloff
|
//! Spot light falloff
|
||||||
ai_real mFalloffAngle;
|
ai_real mFalloffAngle;
|
||||||
|
@ -198,12 +187,10 @@ struct Light
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Short vertex index description */
|
/** Short vertex index description */
|
||||||
struct InputSemanticMapEntry
|
struct InputSemanticMapEntry {
|
||||||
{
|
InputSemanticMapEntry() :
|
||||||
InputSemanticMapEntry()
|
mSet(0),
|
||||||
: mSet(0)
|
mType(IT_Invalid) {}
|
||||||
, mType(IT_Invalid)
|
|
||||||
{}
|
|
||||||
|
|
||||||
//! Index of set, optional
|
//! Index of set, optional
|
||||||
unsigned int mSet;
|
unsigned int mSet;
|
||||||
|
@ -213,8 +200,7 @@ struct InputSemanticMapEntry
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Table to map from effect to vertex input semantics */
|
/** Table to map from effect to vertex input semantics */
|
||||||
struct SemanticMappingTable
|
struct SemanticMappingTable {
|
||||||
{
|
|
||||||
//! Name of material
|
//! Name of material
|
||||||
std::string mMatName;
|
std::string mMatName;
|
||||||
|
|
||||||
|
@ -222,7 +208,7 @@ struct SemanticMappingTable
|
||||||
std::map<std::string, InputSemanticMapEntry> mMap;
|
std::map<std::string, InputSemanticMapEntry> mMap;
|
||||||
|
|
||||||
//! For std::find
|
//! For std::find
|
||||||
bool operator == (const std::string& s) const {
|
bool operator==(const std::string &s) const {
|
||||||
return s == mMatName;
|
return s == mMatName;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -230,8 +216,7 @@ struct SemanticMappingTable
|
||||||
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
|
/** 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
|
* The ID refers to either a mesh or a controller which specifies the mesh
|
||||||
*/
|
*/
|
||||||
struct MeshInstance
|
struct MeshInstance {
|
||||||
{
|
|
||||||
///< ID of the mesh or controller to be instanced
|
///< ID of the mesh or controller to be instanced
|
||||||
std::string mMeshOrController;
|
std::string mMeshOrController;
|
||||||
|
|
||||||
|
@ -240,34 +225,30 @@ struct MeshInstance
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A reference to a camera inside a node*/
|
/** A reference to a camera inside a node*/
|
||||||
struct CameraInstance
|
struct CameraInstance {
|
||||||
{
|
///< ID of the camera
|
||||||
///< ID of the camera
|
|
||||||
std::string mCamera;
|
std::string mCamera;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A reference to a light inside a node*/
|
/** A reference to a light inside a node*/
|
||||||
struct LightInstance
|
struct LightInstance {
|
||||||
{
|
///< ID of the camera
|
||||||
///< ID of the camera
|
|
||||||
std::string mLight;
|
std::string mLight;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A reference to a node inside a node*/
|
/** A reference to a node inside a node*/
|
||||||
struct NodeInstance
|
struct NodeInstance {
|
||||||
{
|
///< ID of the node
|
||||||
///< ID of the node
|
|
||||||
std::string mNode;
|
std::string mNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A node in a scene hierarchy */
|
/** A node in a scene hierarchy */
|
||||||
struct Node
|
struct Node {
|
||||||
{
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mID;
|
std::string mID;
|
||||||
std::string mSID;
|
std::string mSID;
|
||||||
Node* mParent;
|
Node *mParent;
|
||||||
std::vector<Node*> mChildren;
|
std::vector<Node *> mChildren;
|
||||||
|
|
||||||
/** Operations in order to calculate the resulting transformation to parent. */
|
/** Operations in order to calculate the resulting transformation to parent. */
|
||||||
std::vector<Transform> mTransforms;
|
std::vector<Transform> mTransforms;
|
||||||
|
@ -288,80 +269,83 @@ struct Node
|
||||||
std::string mPrimaryCamera;
|
std::string mPrimaryCamera;
|
||||||
|
|
||||||
//! Constructor. Begin with a zero parent
|
//! Constructor. Begin with a zero parent
|
||||||
Node()
|
Node() :
|
||||||
: mParent( nullptr ){
|
mParent(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor: delete all children subsequently
|
//! Destructor: delete all children subsequently
|
||||||
~Node() {
|
~Node() {
|
||||||
for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
|
for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Data source array: either floats or strings */
|
/** Data source array: either floats or strings */
|
||||||
struct Data
|
struct Data {
|
||||||
{
|
|
||||||
bool mIsStringArray;
|
bool mIsStringArray;
|
||||||
std::vector<ai_real> mValues;
|
std::vector<ai_real> mValues;
|
||||||
std::vector<std::string> mStrings;
|
std::vector<std::string> mStrings;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Accessor to a data array */
|
/** Accessor to a data array */
|
||||||
struct Accessor
|
struct Accessor {
|
||||||
{
|
size_t mCount; // in number of objects
|
||||||
size_t mCount; // in number of objects
|
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
|
||||||
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
|
size_t mOffset; // in number of values
|
||||||
size_t mOffset; // in number of values
|
size_t mStride; // Stride 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.
|
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
|
||||||
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
|
size_t mSubOffset[4]; // Suboffset 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.
|
// 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
|
std::string mSource; // URL of the source array
|
||||||
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
|
mutable const Data *mData; // Pointer to the source array, if resolved. NULL else
|
||||||
|
|
||||||
Accessor()
|
Accessor() {
|
||||||
{
|
mCount = 0;
|
||||||
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
|
mSize = 0;
|
||||||
|
mOffset = 0;
|
||||||
|
mStride = 0;
|
||||||
|
mData = NULL;
|
||||||
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single face in a mesh */
|
/** A single face in a mesh */
|
||||||
struct Face
|
struct Face {
|
||||||
{
|
|
||||||
std::vector<size_t> mIndices;
|
std::vector<size_t> mIndices;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An input channel for mesh data, referring to a single accessor */
|
/** An input channel for mesh data, referring to a single accessor */
|
||||||
struct InputChannel
|
struct InputChannel {
|
||||||
{
|
InputType mType; // Type of the data
|
||||||
InputType mType; // Type of the data
|
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
||||||
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.
|
||||||
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.
|
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
||||||
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
|
mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. NULL else
|
||||||
|
|
||||||
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
|
InputChannel() {
|
||||||
|
mType = IT_Invalid;
|
||||||
|
mIndex = 0;
|
||||||
|
mOffset = 0;
|
||||||
|
mResolved = NULL;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Subset of a mesh with a certain material */
|
/** Subset of a mesh with a certain material */
|
||||||
struct SubMesh
|
struct SubMesh {
|
||||||
{
|
|
||||||
std::string mMaterial; ///< subgroup identifier
|
std::string mMaterial; ///< subgroup identifier
|
||||||
size_t mNumFaces; ///< number of faces in this submesh
|
size_t mNumFaces; ///< number of faces in this submesh
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Contains data for a single mesh */
|
/** Contains data for a single mesh */
|
||||||
struct Mesh
|
struct Mesh {
|
||||||
{
|
Mesh(const std::string &id) :
|
||||||
Mesh()
|
mId(id) {
|
||||||
{
|
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
|
||||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
|
||||||
mNumUVComponents[i] = 2;
|
mNumUVComponents[i] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string mId;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
// just to check if there's some sophisticated addressing involved...
|
// just to check if there's some sophisticated addressing involved...
|
||||||
|
@ -377,7 +361,7 @@ struct Mesh
|
||||||
std::vector<aiVector3D> mTangents;
|
std::vector<aiVector3D> mTangents;
|
||||||
std::vector<aiVector3D> mBitangents;
|
std::vector<aiVector3D> mBitangents;
|
||||||
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||||
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||||
|
|
||||||
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||||
|
|
||||||
|
@ -394,8 +378,7 @@ struct Mesh
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Which type of primitives the ReadPrimitives() function is going to read */
|
/** Which type of primitives the ReadPrimitives() function is going to read */
|
||||||
enum PrimitiveType
|
enum PrimitiveType {
|
||||||
{
|
|
||||||
Prim_Invalid,
|
Prim_Invalid,
|
||||||
Prim_Lines,
|
Prim_Lines,
|
||||||
Prim_LineStrip,
|
Prim_LineStrip,
|
||||||
|
@ -407,8 +390,7 @@ enum PrimitiveType
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A skeleton controller to deform a mesh with the use of joints */
|
/** A skeleton controller to deform a mesh with the use of joints */
|
||||||
struct Controller
|
struct Controller {
|
||||||
{
|
|
||||||
// controller type
|
// controller type
|
||||||
ControllerType mType;
|
ControllerType mType;
|
||||||
|
|
||||||
|
@ -436,36 +418,32 @@ struct Controller
|
||||||
std::vector<size_t> mWeightCounts;
|
std::vector<size_t> mWeightCounts;
|
||||||
|
|
||||||
// JointIndex-WeightIndex pairs for all vertices
|
// JointIndex-WeightIndex pairs for all vertices
|
||||||
std::vector< std::pair<size_t, size_t> > mWeights;
|
std::vector<std::pair<size_t, size_t>> mWeights;
|
||||||
|
|
||||||
std::string mMorphTarget;
|
std::string mMorphTarget;
|
||||||
std::string mMorphWeight;
|
std::string mMorphWeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A collada material. Pretty much the only member is a reference to an effect. */
|
/** A collada material. Pretty much the only member is a reference to an effect. */
|
||||||
struct Material
|
struct Material {
|
||||||
{
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mEffect;
|
std::string mEffect;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Type of the effect param */
|
/** Type of the effect param */
|
||||||
enum ParamType
|
enum ParamType {
|
||||||
{
|
|
||||||
Param_Sampler,
|
Param_Sampler,
|
||||||
Param_Surface
|
Param_Surface
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
|
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
|
||||||
struct EffectParam
|
struct EffectParam {
|
||||||
{
|
|
||||||
ParamType mType;
|
ParamType mType;
|
||||||
std::string mReference; // to which other thing the param is referring to.
|
std::string mReference; // to which other thing the param is referring to.
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Shading type supported by the standard effect spec of Collada */
|
/** Shading type supported by the standard effect spec of Collada */
|
||||||
enum ShadeType
|
enum ShadeType {
|
||||||
{
|
|
||||||
Shade_Invalid,
|
Shade_Invalid,
|
||||||
Shade_Constant,
|
Shade_Constant,
|
||||||
Shade_Lambert,
|
Shade_Lambert,
|
||||||
|
@ -474,18 +452,16 @@ enum ShadeType
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Represents a texture sampler in collada */
|
/** Represents a texture sampler in collada */
|
||||||
struct Sampler
|
struct Sampler {
|
||||||
{
|
Sampler() :
|
||||||
Sampler()
|
mWrapU(true),
|
||||||
: mWrapU (true)
|
mWrapV(true),
|
||||||
, mWrapV (true)
|
mMirrorU(),
|
||||||
, mMirrorU ()
|
mMirrorV(),
|
||||||
, mMirrorV ()
|
mOp(aiTextureOp_Multiply),
|
||||||
, mOp (aiTextureOp_Multiply)
|
mUVId(UINT_MAX),
|
||||||
, mUVId (UINT_MAX)
|
mWeighting(1.f),
|
||||||
, mWeighting (1.f)
|
mMixWithPrevious(1.f) {}
|
||||||
, mMixWithPrevious (1.f)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/** Name of image reference
|
/** Name of image reference
|
||||||
*/
|
*/
|
||||||
|
@ -537,18 +513,17 @@ struct Sampler
|
||||||
|
|
||||||
/** A collada effect. Can contain about anything according to the Collada spec,
|
/** A collada effect. Can contain about anything according to the Collada spec,
|
||||||
but we limit our version to a reasonable subset. */
|
but we limit our version to a reasonable subset. */
|
||||||
struct Effect
|
struct Effect {
|
||||||
{
|
|
||||||
// Shading mode
|
// Shading mode
|
||||||
ShadeType mShadeType;
|
ShadeType mShadeType;
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
|
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
|
||||||
mTransparent, mReflective;
|
mTransparent, mReflective;
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
|
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
|
||||||
mTexTransparent, mTexBump, mTexReflective;
|
mTexTransparent, mTexBump, mTexReflective;
|
||||||
|
|
||||||
// Scalar factory
|
// Scalar factory
|
||||||
ai_real mShininess, mRefractIndex, mReflectivity;
|
ai_real mShininess, mRefractIndex, mReflectivity;
|
||||||
|
@ -566,30 +541,28 @@ struct Effect
|
||||||
// Double-sided?
|
// Double-sided?
|
||||||
bool mDoubleSided, mWireframe, mFaceted;
|
bool mDoubleSided, mWireframe, mFaceted;
|
||||||
|
|
||||||
Effect()
|
Effect() :
|
||||||
: mShadeType (Shade_Phong)
|
mShadeType(Shade_Phong),
|
||||||
, mEmissive ( 0, 0, 0, 1)
|
mEmissive(0, 0, 0, 1),
|
||||||
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
|
mAmbient(0.1f, 0.1f, 0.1f, 1),
|
||||||
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
|
mDiffuse(0.6f, 0.6f, 0.6f, 1),
|
||||||
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
|
mSpecular(0.4f, 0.4f, 0.4f, 1),
|
||||||
, mTransparent ( 0, 0, 0, 1)
|
mTransparent(0, 0, 0, 1),
|
||||||
, mShininess (10.0f)
|
mShininess(10.0f),
|
||||||
, mRefractIndex (1.f)
|
mRefractIndex(1.f),
|
||||||
, mReflectivity (0.f)
|
mReflectivity(0.f),
|
||||||
, mTransparency (1.f)
|
mTransparency(1.f),
|
||||||
, mHasTransparency (false)
|
mHasTransparency(false),
|
||||||
, mRGBTransparency(false)
|
mRGBTransparency(false),
|
||||||
, mInvertTransparency(false)
|
mInvertTransparency(false),
|
||||||
, mDoubleSided (false)
|
mDoubleSided(false),
|
||||||
, mWireframe (false)
|
mWireframe(false),
|
||||||
, mFaceted (false)
|
mFaceted(false) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An image, meaning texture */
|
/** An image, meaning texture */
|
||||||
struct Image
|
struct Image {
|
||||||
{
|
|
||||||
std::string mFileName;
|
std::string mFileName;
|
||||||
|
|
||||||
/** Embedded image data */
|
/** Embedded image data */
|
||||||
|
@ -600,8 +573,7 @@ struct Image
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An animation channel. */
|
/** An animation channel. */
|
||||||
struct AnimationChannel
|
struct AnimationChannel {
|
||||||
{
|
|
||||||
/** URL of the data to animate. Could be about anything, but we support only the
|
/** URL of the data to animate. Could be about anything, but we support only the
|
||||||
* "NodeID/TransformID.SubElement" notation
|
* "NodeID/TransformID.SubElement" notation
|
||||||
*/
|
*/
|
||||||
|
@ -620,8 +592,7 @@ struct AnimationChannel
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An animation. Container for 0-x animation channels or 0-x animations */
|
/** An animation. Container for 0-x animation channels or 0-x animations */
|
||||||
struct Animation
|
struct Animation {
|
||||||
{
|
|
||||||
/** Anim name */
|
/** Anim name */
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
|
@ -629,96 +600,86 @@ struct Animation
|
||||||
std::vector<AnimationChannel> mChannels;
|
std::vector<AnimationChannel> mChannels;
|
||||||
|
|
||||||
/** the sub-animations, if any */
|
/** the sub-animations, if any */
|
||||||
std::vector<Animation*> mSubAnims;
|
std::vector<Animation *> mSubAnims;
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~Animation()
|
~Animation() {
|
||||||
{
|
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||||
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Collect all channels in the animation hierarchy into a single channel list. */
|
/** Collect all channels in the animation hierarchy into a single channel list. */
|
||||||
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
|
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
|
||||||
{
|
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
|
||||||
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
|
|
||||||
|
|
||||||
for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
|
||||||
{
|
Animation *pAnim = (*it);
|
||||||
Animation *pAnim = (*it);
|
|
||||||
|
|
||||||
pAnim->CollectChannelsRecursively(channels);
|
pAnim->CollectChannelsRecursively(channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
|
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
|
||||||
void CombineSingleChannelAnimations()
|
void CombineSingleChannelAnimations() {
|
||||||
{
|
CombineSingleChannelAnimationsRecursively(this);
|
||||||
CombineSingleChannelAnimationsRecursively(this);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
|
void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
|
||||||
{
|
std::set<std::string> childrenTargets;
|
||||||
std::set<std::string> childrenTargets;
|
bool childrenAnimationsHaveDifferentChannels = true;
|
||||||
bool childrenAnimationsHaveDifferentChannels = true;
|
|
||||||
|
|
||||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
|
||||||
{
|
Animation *anim = *it;
|
||||||
Animation *anim = *it;
|
CombineSingleChannelAnimationsRecursively(anim);
|
||||||
CombineSingleChannelAnimationsRecursively(anim);
|
|
||||||
|
|
||||||
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
|
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
|
||||||
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
|
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
|
||||||
childrenTargets.insert(anim->mChannels[0].mTarget);
|
childrenTargets.insert(anim->mChannels[0].mTarget);
|
||||||
} else {
|
} else {
|
||||||
childrenAnimationsHaveDifferentChannels = false;
|
childrenAnimationsHaveDifferentChannels = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only want to combine animations if they have different channels
|
// We only want to combine animations if they have different channels
|
||||||
if (childrenAnimationsHaveDifferentChannels)
|
if (childrenAnimationsHaveDifferentChannels) {
|
||||||
{
|
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
|
||||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
Animation *anim = *it;
|
||||||
{
|
|
||||||
Animation *anim = *it;
|
|
||||||
|
|
||||||
pParent->mChannels.push_back(anim->mChannels[0]);
|
pParent->mChannels.push_back(anim->mChannels[0]);
|
||||||
|
|
||||||
it = pParent->mSubAnims.erase(it);
|
it = pParent->mSubAnims.erase(it);
|
||||||
|
|
||||||
delete anim;
|
delete anim;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Description of a collada animation channel which has been determined to affect the current node */
|
/** Description of a collada animation channel which has been determined to affect the current node */
|
||||||
struct ChannelEntry
|
struct ChannelEntry {
|
||||||
{
|
const Collada::AnimationChannel *mChannel; ///> the source channel
|
||||||
const Collada::AnimationChannel* mChannel; ///> the source channel
|
|
||||||
std::string mTargetId;
|
std::string mTargetId;
|
||||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
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 mTransformIndex; // Index into the node's transform chain to apply the channel to
|
||||||
size_t mSubElement; // starting index inside the transform data
|
size_t mSubElement; // starting index inside the transform data
|
||||||
|
|
||||||
// resolved data references
|
// resolved data references
|
||||||
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
|
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
|
||||||
const Collada::Data* mTimeData; ///> Source data array for 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::Accessor *mValueAccessor; ///> Collada accessor to the key value values
|
||||||
const Collada::Data* mValueData; ///> Source datat array for the key value values
|
const Collada::Data *mValueData; ///> Source datat array for the key value values
|
||||||
|
|
||||||
ChannelEntry()
|
ChannelEntry() :
|
||||||
: mChannel()
|
mChannel(),
|
||||||
, mTransformIndex()
|
mTransformIndex(),
|
||||||
, mSubElement()
|
mSubElement(),
|
||||||
, mTimeAccessor()
|
mTimeAccessor(),
|
||||||
, mTimeData()
|
mTimeData(),
|
||||||
, mValueAccessor()
|
mValueAccessor(),
|
||||||
, mValueData()
|
mValueData() {}
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Collada
|
} // end of namespace Collada
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,392 @@
|
||||||
|
/*
|
||||||
|
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 ColladaParser.h
|
||||||
|
* @brief Defines the parser helper class for the collada loader
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AI_COLLADAPARSER_H_INC
|
||||||
|
#define AI_COLLADAPARSER_H_INC
|
||||||
|
|
||||||
|
#include "ColladaHelper.h"
|
||||||
|
#include <assimp/TinyFormatter.h>
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
|
#include <assimp/irrXMLWrapper.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
class ZipArchiveIOSystem;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
/** Parser helper class for the Collada loader.
|
||||||
|
*
|
||||||
|
* Does all the XML reading and builds internal data structures from it,
|
||||||
|
* but leaves the resolving of all the references to the loader.
|
||||||
|
*/
|
||||||
|
class ColladaParser {
|
||||||
|
friend class ColladaLoader;
|
||||||
|
|
||||||
|
/** Converts a path read from a collada file to the usual representation */
|
||||||
|
static void UriDecodePath(aiString &ss);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Map for generic metadata as aiString */
|
||||||
|
typedef std::map<std::string, aiString> StringMetaData;
|
||||||
|
|
||||||
|
/** Constructor from XML file */
|
||||||
|
ColladaParser(IOSystem *pIOHandler, const std::string &pFile);
|
||||||
|
|
||||||
|
/** Destructor */
|
||||||
|
~ColladaParser();
|
||||||
|
|
||||||
|
/** Attempts to read the ZAE manifest and returns the DAE to open */
|
||||||
|
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
|
||||||
|
|
||||||
|
/** Reads the contents of the file */
|
||||||
|
void ReadContents();
|
||||||
|
|
||||||
|
/** Reads the structure of the file */
|
||||||
|
void ReadStructure();
|
||||||
|
|
||||||
|
/** Reads asset information such as coordinate system information and legal blah */
|
||||||
|
void ReadAssetInfo();
|
||||||
|
|
||||||
|
/** Reads contributor information such as author and legal blah */
|
||||||
|
void ReadContributorInfo();
|
||||||
|
|
||||||
|
/** Reads generic metadata into provided map and renames keys for Assimp */
|
||||||
|
void ReadMetaDataItem(StringMetaData &metadata);
|
||||||
|
|
||||||
|
/** Reads the animation library */
|
||||||
|
void ReadAnimationLibrary();
|
||||||
|
|
||||||
|
/** Reads the animation clip library */
|
||||||
|
void ReadAnimationClipLibrary();
|
||||||
|
|
||||||
|
/** Unwrap controllers dependency hierarchy */
|
||||||
|
void PostProcessControllers();
|
||||||
|
|
||||||
|
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
|
||||||
|
void PostProcessRootAnimations();
|
||||||
|
|
||||||
|
/** Reads an animation into the given parent structure */
|
||||||
|
void ReadAnimation(Collada::Animation *pParent);
|
||||||
|
|
||||||
|
/** Reads an animation sampler into the given anim channel */
|
||||||
|
void ReadAnimationSampler(Collada::AnimationChannel &pChannel);
|
||||||
|
|
||||||
|
/** Reads the skeleton controller library */
|
||||||
|
void ReadControllerLibrary();
|
||||||
|
|
||||||
|
/** Reads a controller into the given mesh structure */
|
||||||
|
void ReadController(Collada::Controller &pController);
|
||||||
|
|
||||||
|
/** Reads the joint definitions for the given controller */
|
||||||
|
void ReadControllerJoints(Collada::Controller &pController);
|
||||||
|
|
||||||
|
/** Reads the joint weights for the given controller */
|
||||||
|
void ReadControllerWeights(Collada::Controller &pController);
|
||||||
|
|
||||||
|
/** Reads the image library contents */
|
||||||
|
void ReadImageLibrary();
|
||||||
|
|
||||||
|
/** Reads an image entry into the given image */
|
||||||
|
void ReadImage(Collada::Image &pImage);
|
||||||
|
|
||||||
|
/** Reads the material library */
|
||||||
|
void ReadMaterialLibrary();
|
||||||
|
|
||||||
|
/** Reads a material entry into the given material */
|
||||||
|
void ReadMaterial(Collada::Material &pMaterial);
|
||||||
|
|
||||||
|
/** Reads the camera library */
|
||||||
|
void ReadCameraLibrary();
|
||||||
|
|
||||||
|
/** Reads a camera entry into the given camera */
|
||||||
|
void ReadCamera(Collada::Camera &pCamera);
|
||||||
|
|
||||||
|
/** Reads the light library */
|
||||||
|
void ReadLightLibrary();
|
||||||
|
|
||||||
|
/** Reads a light entry into the given light */
|
||||||
|
void ReadLight(Collada::Light &pLight);
|
||||||
|
|
||||||
|
/** Reads the effect library */
|
||||||
|
void ReadEffectLibrary();
|
||||||
|
|
||||||
|
/** Reads an effect entry into the given effect*/
|
||||||
|
void ReadEffect(Collada::Effect &pEffect);
|
||||||
|
|
||||||
|
/** Reads an COMMON effect profile */
|
||||||
|
void ReadEffectProfileCommon(Collada::Effect &pEffect);
|
||||||
|
|
||||||
|
/** Read sampler properties */
|
||||||
|
void ReadSamplerProperties(Collada::Sampler &pSampler);
|
||||||
|
|
||||||
|
/** Reads an effect entry containing a color or a texture defining that color */
|
||||||
|
void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler);
|
||||||
|
|
||||||
|
/** Reads an effect entry containing a float */
|
||||||
|
void ReadEffectFloat(ai_real &pFloat);
|
||||||
|
|
||||||
|
/** Reads an effect parameter specification of any kind */
|
||||||
|
void ReadEffectParam(Collada::EffectParam &pParam);
|
||||||
|
|
||||||
|
/** Reads the geometry library contents */
|
||||||
|
void ReadGeometryLibrary();
|
||||||
|
|
||||||
|
/** Reads a geometry from the geometry library. */
|
||||||
|
void ReadGeometry(Collada::Mesh &pMesh);
|
||||||
|
|
||||||
|
/** Reads a mesh from the geometry library */
|
||||||
|
void ReadMesh(Collada::Mesh &pMesh);
|
||||||
|
|
||||||
|
/** Reads a source element - a combination of raw data and an accessor defining
|
||||||
|
* things that should not be redefinable. Yes, that's another rant.
|
||||||
|
*/
|
||||||
|
void ReadSource();
|
||||||
|
|
||||||
|
/** Reads a data array holding a number of elements, and stores it in the global library.
|
||||||
|
* Currently supported are array of floats and arrays of strings.
|
||||||
|
*/
|
||||||
|
void ReadDataArray();
|
||||||
|
|
||||||
|
/** Reads an accessor and stores it in the global library under the given ID -
|
||||||
|
* accessors use the ID of the parent <source> element
|
||||||
|
*/
|
||||||
|
void ReadAccessor(const std::string &pID);
|
||||||
|
|
||||||
|
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
||||||
|
void ReadVertexData(Collada::Mesh &pMesh);
|
||||||
|
|
||||||
|
/** Reads input declarations of per-index mesh data into the given mesh */
|
||||||
|
void ReadIndexData(Collada::Mesh &pMesh);
|
||||||
|
|
||||||
|
/** Reads a single input channel element and stores it in the given array, if valid */
|
||||||
|
void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
|
||||||
|
|
||||||
|
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
||||||
|
size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
|
||||||
|
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
|
||||||
|
|
||||||
|
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
|
||||||
|
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
|
||||||
|
Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
|
||||||
|
size_t currentPrimitive, const std::vector<size_t> &indices);
|
||||||
|
|
||||||
|
/** Reads one triangle of a tristrip into the mesh */
|
||||||
|
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh,
|
||||||
|
std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices);
|
||||||
|
|
||||||
|
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
||||||
|
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
|
||||||
|
|
||||||
|
/** Reads the library of node hierarchies and scene parts */
|
||||||
|
void ReadSceneLibrary();
|
||||||
|
|
||||||
|
/** Reads a scene node's contents including children and stores it in the given node */
|
||||||
|
void ReadSceneNode(Collada::Node *pNode);
|
||||||
|
|
||||||
|
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
||||||
|
void ReadNodeTransformation(Collada::Node *pNode, Collada::TransformType pType);
|
||||||
|
|
||||||
|
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
||||||
|
void ReadNodeGeometry(Collada::Node *pNode);
|
||||||
|
|
||||||
|
/** Reads the collada scene */
|
||||||
|
void ReadScene();
|
||||||
|
|
||||||
|
// Processes bind_vertex_input and bind elements
|
||||||
|
void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl);
|
||||||
|
|
||||||
|
/** Reads embedded textures from a ZAE archive*/
|
||||||
|
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Aborts the file reading with an exception */
|
||||||
|
AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX;
|
||||||
|
void ReportWarning(const char *msg, ...);
|
||||||
|
|
||||||
|
/** Skips all data until the end node of the current element */
|
||||||
|
void SkipElement();
|
||||||
|
|
||||||
|
/** Skips all data until the end node of the given element */
|
||||||
|
void SkipElement(const char *pElement);
|
||||||
|
|
||||||
|
/** Compares the current xml element name to the given string and returns true if equal */
|
||||||
|
bool IsElement(const char *pName) const;
|
||||||
|
|
||||||
|
/** Tests for the opening tag of the given element, throws an exception if not found */
|
||||||
|
void TestOpening(const char *pName);
|
||||||
|
|
||||||
|
/** Tests for the closing tag of the given element, throws an exception if not found */
|
||||||
|
void TestClosing(const char *pName);
|
||||||
|
|
||||||
|
/** Checks the present element for the presence of the attribute, returns its index
|
||||||
|
or throws an exception if not found */
|
||||||
|
int GetAttribute(const char *pAttr) const;
|
||||||
|
|
||||||
|
/** Returns the index of the named attribute or -1 if not found. Does not throw,
|
||||||
|
therefore useful for optional attributes */
|
||||||
|
int TestAttribute(const char *pAttr) const;
|
||||||
|
|
||||||
|
/** Reads the text contents of an element, throws an exception if not given.
|
||||||
|
Skips leading whitespace. */
|
||||||
|
const char *GetTextContent();
|
||||||
|
|
||||||
|
/** Reads the text contents of an element, returns NULL if not given.
|
||||||
|
Skips leading whitespace. */
|
||||||
|
const char *TestTextContent();
|
||||||
|
|
||||||
|
/** Reads a single bool from current text content */
|
||||||
|
bool ReadBoolFromTextContent();
|
||||||
|
|
||||||
|
/** Reads a single float from current text content */
|
||||||
|
ai_real ReadFloatFromTextContent();
|
||||||
|
|
||||||
|
/** Calculates the resulting transformation from all the given transform steps */
|
||||||
|
aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
|
||||||
|
|
||||||
|
/** Determines the input data type for the given semantic string */
|
||||||
|
Collada::InputType GetTypeForSemantic(const std::string &pSemantic);
|
||||||
|
|
||||||
|
/** Finds the item in the given library by its reference, throws if not found */
|
||||||
|
template <typename Type>
|
||||||
|
const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Filename, for a verbose error message */
|
||||||
|
std::string mFileName;
|
||||||
|
|
||||||
|
/** XML reader, member for everyday use */
|
||||||
|
irr::io::IrrXMLReader *mReader;
|
||||||
|
|
||||||
|
/** All data arrays found in the file by ID. Might be referred to by actually
|
||||||
|
everyone. Collada, you are a steaming pile of indirection. */
|
||||||
|
typedef std::map<std::string, Collada::Data> DataLibrary;
|
||||||
|
DataLibrary mDataLibrary;
|
||||||
|
|
||||||
|
/** Same for accessors which define how the data in a data array is accessed. */
|
||||||
|
typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
|
||||||
|
AccessorLibrary mAccessorLibrary;
|
||||||
|
|
||||||
|
/** Mesh library: mesh by ID */
|
||||||
|
typedef std::map<std::string, Collada::Mesh *> MeshLibrary;
|
||||||
|
MeshLibrary mMeshLibrary;
|
||||||
|
|
||||||
|
/** node library: root node of the hierarchy part by ID */
|
||||||
|
typedef std::map<std::string, Collada::Node *> NodeLibrary;
|
||||||
|
NodeLibrary mNodeLibrary;
|
||||||
|
|
||||||
|
/** Image library: stores texture properties by ID */
|
||||||
|
typedef std::map<std::string, Collada::Image> ImageLibrary;
|
||||||
|
ImageLibrary mImageLibrary;
|
||||||
|
|
||||||
|
/** Effect library: surface attributes by ID */
|
||||||
|
typedef std::map<std::string, Collada::Effect> EffectLibrary;
|
||||||
|
EffectLibrary mEffectLibrary;
|
||||||
|
|
||||||
|
/** Material library: surface material by ID */
|
||||||
|
typedef std::map<std::string, Collada::Material> MaterialLibrary;
|
||||||
|
MaterialLibrary mMaterialLibrary;
|
||||||
|
|
||||||
|
/** Light library: surface light by ID */
|
||||||
|
typedef std::map<std::string, Collada::Light> LightLibrary;
|
||||||
|
LightLibrary mLightLibrary;
|
||||||
|
|
||||||
|
/** Camera library: surface material by ID */
|
||||||
|
typedef std::map<std::string, Collada::Camera> CameraLibrary;
|
||||||
|
CameraLibrary mCameraLibrary;
|
||||||
|
|
||||||
|
/** Controller library: joint controllers by ID */
|
||||||
|
typedef std::map<std::string, Collada::Controller> ControllerLibrary;
|
||||||
|
ControllerLibrary mControllerLibrary;
|
||||||
|
|
||||||
|
/** Animation library: animation references by ID */
|
||||||
|
typedef std::map<std::string, Collada::Animation *> AnimationLibrary;
|
||||||
|
AnimationLibrary mAnimationLibrary;
|
||||||
|
|
||||||
|
/** Animation clip library: clip animation references by ID */
|
||||||
|
typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary;
|
||||||
|
AnimationClipLibrary mAnimationClipLibrary;
|
||||||
|
|
||||||
|
/** Pointer to the root node. Don't delete, it just points to one of
|
||||||
|
the nodes in the node library. */
|
||||||
|
Collada::Node *mRootNode;
|
||||||
|
|
||||||
|
/** Root animation container */
|
||||||
|
Collada::Animation mAnims;
|
||||||
|
|
||||||
|
/** Size unit: how large compared to a meter */
|
||||||
|
ai_real mUnitSize;
|
||||||
|
|
||||||
|
/** Which is the up vector */
|
||||||
|
enum { UP_X,
|
||||||
|
UP_Y,
|
||||||
|
UP_Z } mUpDirection;
|
||||||
|
|
||||||
|
/** Asset metadata (global for scene) */
|
||||||
|
StringMetaData mAssetMetaData;
|
||||||
|
|
||||||
|
/** Collada file format version */
|
||||||
|
Collada::FormatVersion mFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Check for element match
|
||||||
|
inline bool ColladaParser::IsElement(const char *pName) const {
|
||||||
|
ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT);
|
||||||
|
return ::strcmp(mReader->getNodeName(), pName) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Finds the item in the given library by its reference, throws if not found
|
||||||
|
template <typename Type>
|
||||||
|
const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
|
||||||
|
typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
|
||||||
|
if (it == pLibrary.end())
|
||||||
|
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\".");
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // AI_COLLADAPARSER_H_INC
|
|
@ -135,7 +135,7 @@ public:
|
||||||
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
|
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
|
||||||
|
|
||||||
splitter++;
|
splitter++;
|
||||||
ASSIMP_LOG_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
|
ASSIMP_LOG_VERBOSE_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
|
||||||
}
|
}
|
||||||
} catch(std::logic_error&) {
|
} catch(std::logic_error&) {
|
||||||
ai_assert(!splitter);
|
ai_assert(!splitter);
|
|
@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
|
||||||
|
|
||||||
#include "DXF/DXFLoader.h"
|
#include "AssetLib/DXF/DXFLoader.h"
|
||||||
#include "DXF/DXFHelper.h"
|
#include "AssetLib/DXF/DXFHelper.h"
|
||||||
#include "PostProcessing/ConvertToLHProcess.h"
|
#include "PostProcessing/ConvertToLHProcess.h"
|
||||||
|
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
|
@ -241,7 +241,7 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
|
ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! output.blocks.size() ) {
|
if (! output.blocks.size() ) {
|
||||||
|
@ -473,7 +473,7 @@ void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
|
||||||
++reader;
|
++reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
|
ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -549,7 +549,7 @@ void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output)
|
||||||
++reader;
|
++reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
|
ASSIMP_LOG_VERBOSE_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
|
||||||
" inserted blocks in ENTITIES" );
|
" inserted blocks in ENTITIES" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
#include <assimp/ByteSwapper.h>
|
#include <assimp/ByteSwapper.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
@ -426,7 +427,8 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
||||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||||
{
|
{
|
||||||
ai_assert(input);
|
ai_assert(input);
|
||||||
|
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
|
||||||
|
|
||||||
if(length < 0x1b) {
|
if(length < 0x1b) {
|
||||||
TokenizeError("file is too short",0);
|
TokenizeError("file is too short",0);
|
||||||
|
@ -451,6 +453,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||||
const uint32_t version = ReadWord(input, cursor, input + length);
|
const uint32_t version = ReadWord(input, cursor, input + length);
|
||||||
|
ASSIMP_LOG_DEBUG_F("FBX version: ", version);
|
||||||
const bool is64bits = version >= 7500;
|
const bool is64bits = version >= 7500;
|
||||||
const char *end = input + length;
|
const char *end = input + length;
|
||||||
while (cursor < end ) {
|
while (cursor < end ) {
|
|
@ -48,40 +48,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX
|
namespace FBX {
|
||||||
{
|
|
||||||
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
|
|
||||||
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
|
|
||||||
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
|
|
||||||
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
|
|
||||||
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
|
|
||||||
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
|
||||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
|
||||||
|
|
||||||
// rotation order. We'll probably use EulerXYZ for everything
|
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
|
||||||
enum RotOrder {
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||||
RotOrder_EulerXYZ = 0,
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||||
RotOrder_EulerXZY,
|
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
|
||||||
RotOrder_EulerYZX,
|
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
|
||||||
RotOrder_EulerYXZ,
|
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||||
RotOrder_EulerZXY,
|
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||||
RotOrder_EulerZYX,
|
|
||||||
|
|
||||||
RotOrder_SphericXYZ,
|
// rotation order. We'll probably use EulerXYZ for everything
|
||||||
|
enum RotOrder {
|
||||||
|
RotOrder_EulerXYZ = 0,
|
||||||
|
RotOrder_EulerXZY,
|
||||||
|
RotOrder_EulerYZX,
|
||||||
|
RotOrder_EulerYXZ,
|
||||||
|
RotOrder_EulerZXY,
|
||||||
|
RotOrder_EulerZYX,
|
||||||
|
|
||||||
RotOrder_MAX // end-of-enum sentinel
|
RotOrder_SphericXYZ,
|
||||||
};
|
|
||||||
|
|
||||||
// transformation inheritance method. Most of the time RSrs
|
RotOrder_MAX // end-of-enum sentinel
|
||||||
enum TransformInheritance {
|
};
|
||||||
TransformInheritance_RrSs = 0,
|
|
||||||
TransformInheritance_RSrs,
|
|
||||||
TransformInheritance_Rrs,
|
|
||||||
|
|
||||||
TransformInheritance_MAX // end-of-enum sentinel
|
// transformation inheritance method. Most of the time RSrs
|
||||||
};
|
enum TransformInheritance {
|
||||||
}
|
TransformInheritance_RrSs = 0,
|
||||||
}
|
TransformInheritance_RSrs,
|
||||||
|
TransformInheritance_Rrs,
|
||||||
|
|
||||||
|
TransformInheritance_MAX // end-of-enum sentinel
|
||||||
|
};
|
||||||
|
} // namespace FBX
|
||||||
|
} // namespace Assimp
|
||||||
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
#endif // AI_FBXCOMMON_H_INC
|
#endif // AI_FBXCOMMON_H_INC
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue