Merge branch 'master' into pugi_xml
commit
2be731d1bf
|
@ -70,8 +70,8 @@ IncludeCategories:
|
|||
- Regex: '^<.*'
|
||||
Priority: 3
|
||||
# IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: true
|
||||
# IndentPPDirectives: None
|
||||
IndentCaseLabels: false
|
||||
#IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
# IndentWrappedFunctionNames: false
|
||||
# JavaScriptQuotes: Leave
|
||||
|
@ -108,7 +108,7 @@ IndentWidth: 4
|
|||
# SpacesInParentheses: false
|
||||
# SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
UseTab: Never
|
||||
---
|
||||
### C++ specific config ###
|
||||
Language: Cpp
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
patreon: assimp
|
||||
ko_fi: kimkulling
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
|
||||
open_collective: assimp
|
||||
|
|
|
@ -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
|
||||
*.pyc
|
||||
|
||||
### Rust ###
|
||||
# Generated by Cargo; will have compiled files and executables
|
||||
port/assimp_rs/target/
|
||||
# Backup files generated by rustfmt
|
||||
port/assimp_rs/**/*.rs.bk
|
||||
|
||||
# Unix editor backups
|
||||
*~
|
||||
test/gtest/src/gtest-stamp/gtest-gitinfo.txt
|
||||
|
|
235
CMakeLists.txt
235
CMakeLists.txt
|
@ -39,17 +39,17 @@ SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
|
|||
CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
|
||||
|
||||
# Toggles the use of the hunter package manager
|
||||
option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
||||
option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
||||
|
||||
include("cmake/HunterGate.cmake")
|
||||
HunterGate(
|
||||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
include("cmake/HunterGate.cmake")
|
||||
HunterGate(
|
||||
URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
|
||||
SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
|
||||
)
|
||||
)
|
||||
|
||||
IF(HUNTER_ENABLED)
|
||||
add_definitions(-DASSIMP_USE_HUNTER)
|
||||
ENDIF(HUNTER_ENABLED)
|
||||
ENDIF()
|
||||
|
||||
PROJECT( Assimp VERSION 5.0.1 )
|
||||
|
||||
|
@ -60,7 +60,7 @@ OPTION( BUILD_SHARED_LIBS
|
|||
ON
|
||||
)
|
||||
|
||||
OPTION( BUILD_FRAMEWORK
|
||||
OPTION( ASSIMP_BUILD_FRAMEWORK
|
||||
"Build package as Mac OS X Framework bundle."
|
||||
OFF
|
||||
)
|
||||
|
@ -100,14 +100,14 @@ OPTION ( ASSIMP_COVERALLS
|
|||
"Enable this to measure test coverage."
|
||||
OFF
|
||||
)
|
||||
OPTION( ASSIMP_INSTALL
|
||||
"Disable this if you want to use assimp as a submodule."
|
||||
ON
|
||||
)
|
||||
OPTION ( ASSIMP_ERROR_MAX
|
||||
"Enable all warnings."
|
||||
OFF
|
||||
)
|
||||
OPTION ( ASSIMP_WERROR
|
||||
"Treat warnings as errors."
|
||||
OFF
|
||||
)
|
||||
OPTION ( ASSIMP_ASAN
|
||||
"Enable AddressSanitizer."
|
||||
OFF
|
||||
|
@ -116,30 +116,36 @@ OPTION ( ASSIMP_UBSAN
|
|||
"Enable Undefined Behavior sanitizer."
|
||||
OFF
|
||||
)
|
||||
OPTION ( SYSTEM_IRRXML
|
||||
OPTION ( ASSIMP_SYSTEM_IRRXML
|
||||
"Use system installed Irrlicht/IrrXML library."
|
||||
OFF
|
||||
)
|
||||
OPTION ( BUILD_DOCS
|
||||
OPTION ( ASSIMP_BUILD_DOCS
|
||||
"Build documentation using Doxygen."
|
||||
OFF
|
||||
)
|
||||
OPTION( INJECT_DEBUG_POSTFIX
|
||||
OPTION( ASSIMP_INJECT_DEBUG_POSTFIX
|
||||
"Inject debug postfix in .a/.so/.dll lib names"
|
||||
ON
|
||||
)
|
||||
|
||||
OPTION ( IGNORE_GIT_HASH
|
||||
OPTION ( ASSIMP_IGNORE_GIT_HASH
|
||||
"Don't call git to get the hash."
|
||||
OFF
|
||||
)
|
||||
|
||||
IF (IOS AND NOT HUNTER_ENABLED)
|
||||
IF ( WIN32 )
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
|
||||
"If the Assimp view tool is built. (requires DirectX)"
|
||||
OFF )
|
||||
ENDIF()
|
||||
|
||||
IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
|
||||
IF (NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF (NOT CMAKE_BUILD_TYPE)
|
||||
ENDIF ()
|
||||
ADD_DEFINITIONS(-DENABLE_BITCODE)
|
||||
ENDIF (IOS AND NOT HUNTER_ENABLED)
|
||||
ENDIF ()
|
||||
|
||||
# Use subset of Windows.h
|
||||
if (WIN32)
|
||||
|
@ -155,19 +161,19 @@ IF(MSVC)
|
|||
# Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
|
||||
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
|
||||
ENDIF()
|
||||
ENDIF(MSVC)
|
||||
ENDIF()
|
||||
|
||||
IF (BUILD_FRAMEWORK)
|
||||
IF (ASSIMP_BUILD_FRAMEWORK)
|
||||
SET (BUILD_SHARED_LIBS ON)
|
||||
MESSAGE(STATUS "Framework bundle building enabled")
|
||||
ENDIF(BUILD_FRAMEWORK)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT BUILD_SHARED_LIBS)
|
||||
MESSAGE(STATUS "Shared libraries disabled")
|
||||
SET(LINK_SEARCH_START_STATIC TRUE)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Shared libraries enabled")
|
||||
ENDIF(NOT BUILD_SHARED_LIBS)
|
||||
ENDIF()
|
||||
|
||||
# Define here the needed parameters
|
||||
SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
|
@ -177,12 +183,12 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER
|
|||
SET (ASSIMP_SOVERSION 5)
|
||||
|
||||
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
||||
if(NOT HUNTER_ENABLED)
|
||||
if(NOT ASSIMP_HUNTER_ENABLED)
|
||||
# Enable C++11 support globally
|
||||
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
||||
endif()
|
||||
|
||||
IF(NOT IGNORE_GIT_HASH)
|
||||
IF(NOT ASSIMP_IGNORE_GIT_HASH)
|
||||
# Get the current working branch
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
|
@ -204,11 +210,11 @@ ENDIF()
|
|||
|
||||
IF(NOT GIT_COMMIT_HASH)
|
||||
SET(GIT_COMMIT_HASH 0)
|
||||
ENDIF(NOT GIT_COMMIT_HASH)
|
||||
ENDIF()
|
||||
|
||||
IF(ASSIMP_DOUBLE_PRECISION)
|
||||
ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
|
||||
ENDIF(ASSIMP_DOUBLE_PRECISION)
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
|
||||
|
@ -238,33 +244,32 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
|
|||
IF( UNIX )
|
||||
# Use GNUInstallDirs for Unix predefined directories
|
||||
INCLUDE(GNUInstallDirs)
|
||||
ENDIF( UNIX )
|
||||
ENDIF()
|
||||
|
||||
# Grouped compiler settings
|
||||
# Grouped compiler settings ########################################
|
||||
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
ENDIF()
|
||||
# hide all not-exported symbols
|
||||
SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||
ELSEIF(MSVC)
|
||||
# enable multi-core compilation with MSVC
|
||||
ADD_COMPILE_OPTIONS(/MP)
|
||||
ADD_COMPILE_OPTIONS( /bigobj )
|
||||
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX )
|
||||
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
||||
IF(MSVC12)
|
||||
ADD_COMPILE_OPTIONS(/wd4351)
|
||||
ENDIF()
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
|
||||
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
ENDIF()
|
||||
SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
||||
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
|
||||
|
@ -272,7 +277,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
|||
ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
|
||||
message(WARNING "MinGW is old, if you experience errors, update MinGW.")
|
||||
ENDIF()
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||
ENDIF()
|
||||
|
@ -281,7 +286,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
|||
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
||||
ENDIF()
|
||||
|
||||
IF ( IOS AND NOT HUNTER_ENABLED)
|
||||
IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
|
||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
|
||||
|
@ -290,7 +295,7 @@ IF ( IOS AND NOT HUNTER_ENABLED)
|
|||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
|
||||
# Experimental for pdb generation
|
||||
ENDIF()
|
||||
ENDIF( IOS AND NOT HUNTER_ENABLED)
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_COVERALLS)
|
||||
MESSAGE(STATUS "Coveralls enabled")
|
||||
|
@ -309,16 +314,6 @@ IF (ASSIMP_ERROR_MAX)
|
|||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_WERROR)
|
||||
MESSAGE(STATUS "Treating warnings as errors")
|
||||
IF (MSVC)
|
||||
ADD_COMPILE_OPTIONS(/WX)
|
||||
ELSE()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_ASAN)
|
||||
MESSAGE(STATUS "AddressSanitizer enabled")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
|
@ -339,22 +334,18 @@ INCLUDE (PrecompiledHeader)
|
|||
# source tree. During an out-of-source build, however, do not litter this
|
||||
# directory, since that is probably what the user wanted to avoid.
|
||||
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
||||
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
|
||||
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
|
||||
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
|
||||
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
|
||||
ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
||||
|
||||
# Cache these to allow the user to override them manually.
|
||||
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
|
||||
"Path the built library files are installed to." )
|
||||
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
|
||||
"Path the header files are installed to." )
|
||||
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
|
||||
"Path the tool executables are installed to." )
|
||||
ELSE()
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
ENDIF ()
|
||||
|
||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
IF (ASSIMP_INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||
ELSE()
|
||||
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||
|
@ -367,7 +358,7 @@ IF (NOT TARGET uninstall)
|
|||
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
ENDIF()
|
||||
|
||||
IF(HUNTER_ENABLED)
|
||||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||
set(INCLUDE_INSTALL_DIR "include")
|
||||
|
||||
|
@ -404,13 +395,35 @@ IF(HUNTER_ENABLED)
|
|||
NAMESPACE "${NAMESPACE}"
|
||||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||
)
|
||||
ELSE(HUNTER_ENABLED)
|
||||
ELSE()
|
||||
# cmake configuration files
|
||||
if(${BUILD_SHARED_LIBS})
|
||||
set(BUILD_LIB_TYPE SHARED)
|
||||
else()
|
||||
set(BUILD_LIB_TYPE STATIC)
|
||||
endif()
|
||||
|
||||
IF( UNIX )
|
||||
# Use GNUInstallDirs for Unix predefined directories
|
||||
INCLUDE(GNUInstallDirs)
|
||||
|
||||
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
|
||||
ELSE()
|
||||
# Cache these to allow the user to override them on non-Unix platforms
|
||||
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
|
||||
"Path the built library files are installed to." )
|
||||
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
|
||||
"Path the header files are installed to." )
|
||||
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
|
||||
"Path the tool executables are installed to." )
|
||||
|
||||
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
|
||||
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
|
||||
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
|
||||
IF (is_multi_config)
|
||||
|
@ -432,22 +445,20 @@ ELSE(HUNTER_ENABLED)
|
|||
"${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
|
||||
${PACKAGE_TARGETS_FILE}
|
||||
DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||
ENDIF(HUNTER_ENABLED)
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE( DirectX )
|
||||
|
||||
IF( BUILD_DOCS )
|
||||
IF( ASSIMP_BUILD_DOCS )
|
||||
ADD_SUBDIRECTORY(doc)
|
||||
ENDIF( BUILD_DOCS )
|
||||
ENDIF()
|
||||
|
||||
# Look for system installed irrXML
|
||||
IF ( SYSTEM_IRRXML )
|
||||
IF ( ASSIMP_SYSTEM_IRRXML )
|
||||
FIND_PACKAGE( IrrXML REQUIRED )
|
||||
ENDIF( SYSTEM_IRRXML )
|
||||
ENDIF()
|
||||
|
||||
# Search for external dependencies, and build them from source if not found
|
||||
# Search for zlib
|
||||
IF(HUNTER_ENABLED)
|
||||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
hunter_add_package(ZLIB)
|
||||
find_package(ZLIB CONFIG REQUIRED)
|
||||
|
||||
|
@ -455,10 +466,10 @@ IF(HUNTER_ENABLED)
|
|||
set(ZLIB_FOUND TRUE)
|
||||
set(ZLIB_LIBRARIES ZLIB::zlib)
|
||||
set(ASSIMP_BUILD_MINIZIP TRUE)
|
||||
ELSE(HUNTER_ENABLED)
|
||||
ELSE()
|
||||
IF ( NOT ASSIMP_BUILD_ZLIB )
|
||||
FIND_PACKAGE(ZLIB)
|
||||
ENDIF( NOT ASSIMP_BUILD_ZLIB )
|
||||
ENDIF()
|
||||
|
||||
IF( NOT ZLIB_FOUND )
|
||||
MESSAGE(STATUS "compiling zlib from sources")
|
||||
|
@ -481,46 +492,46 @@ ELSE(HUNTER_ENABLED)
|
|||
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
|
||||
# need to ensure we don't link with system zlib or minizip as well.
|
||||
SET(ASSIMP_BUILD_MINIZIP 1)
|
||||
ELSE(NOT ZLIB_FOUND)
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
|
||||
SET(ZLIB_LIBRARIES_LINKED -lz)
|
||||
ENDIF(NOT ZLIB_FOUND)
|
||||
ENDIF()
|
||||
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
|
||||
ENDIF(HUNTER_ENABLED)
|
||||
ENDIF()
|
||||
|
||||
IF( NOT IOS )
|
||||
IF( NOT ASSIMP_BUILD_MINIZIP )
|
||||
use_pkgconfig(UNZIP minizip)
|
||||
ENDIF( NOT ASSIMP_BUILD_MINIZIP )
|
||||
ELSE ( NOT IOS )
|
||||
ENDIF()
|
||||
ELSE ()
|
||||
IF( NOT BUILD_SHARED_LIBS )
|
||||
IF( NOT ASSIMP_BUILD_MINIZIP )
|
||||
use_pkgconfig(UNZIP minizip)
|
||||
ENDIF( NOT ASSIMP_BUILD_MINIZIP )
|
||||
ENDIF ( NOT BUILD_SHARED_LIBS )
|
||||
ENDIF ( NOT IOS )
|
||||
ENDIF()
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
IF ( ASSIMP_NO_EXPORT )
|
||||
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
|
||||
MESSAGE( STATUS "Build an import-only version of Assimp." )
|
||||
ENDIF( ASSIMP_NO_EXPORT )
|
||||
ENDIF()
|
||||
|
||||
SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
|
||||
"describe the current architecture."
|
||||
)
|
||||
IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
||||
ELSE ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
||||
IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
||||
ELSE()
|
||||
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
|
||||
ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
|
||||
ENDIF()
|
||||
|
||||
# ${CMAKE_GENERATOR}
|
||||
SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
|
||||
"describe the current compiler."
|
||||
)
|
||||
IF ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
||||
ELSE ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
||||
IF( ASSIMP_BUILD_COMPILER STREQUAL "")
|
||||
ELSE()
|
||||
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
|
||||
ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
|
||||
|
||||
|
@ -566,45 +577,50 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
|||
MESSAGE( FATAL_ERROR
|
||||
"C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
|
||||
)
|
||||
ENDIF ( MSVC )
|
||||
ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
||||
ENDIF ()
|
||||
ELSE ()
|
||||
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
|
||||
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
||||
ENDIF ()
|
||||
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
IF(NOT ASSIMP_HUNTER_ENABLED)
|
||||
ADD_SUBDIRECTORY(contrib)
|
||||
ENDIF(NOT HUNTER_ENABLED)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY( code/ )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||
# The viewer for windows only
|
||||
IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
|
||||
IF ( WIN32 )
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
||||
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||
ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
||||
# Te command line tool
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
# The command line tool
|
||||
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
|
||||
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||
ENDIF ()
|
||||
|
||||
IF ( ASSIMP_BUILD_SAMPLES)
|
||||
SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples )
|
||||
SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode )
|
||||
IF ( WIN32 )
|
||||
ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
|
||||
ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 )
|
||||
ENDIF ( WIN32 )
|
||||
ENDIF ()
|
||||
ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
|
||||
ENDIF ( ASSIMP_BUILD_SAMPLES )
|
||||
ENDIF ()
|
||||
|
||||
IF ( ASSIMP_BUILD_TESTS )
|
||||
ADD_SUBDIRECTORY( test/ )
|
||||
ENDIF ( ASSIMP_BUILD_TESTS )
|
||||
ENDIF ()
|
||||
|
||||
# Generate a pkg-config .pc for the Assimp library.
|
||||
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
|
||||
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||
IF ( ASSIMP_INSTALL )
|
||||
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
||||
IF ( ASSIMP_INSTALL )
|
||||
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
||||
# Packing information
|
||||
SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
|
||||
SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
|
||||
|
@ -636,7 +652,7 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
|||
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
|
||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
|
||||
set(cPACK_DEBIAN_PACKAGE_NAME "assimp")
|
||||
SET(cPACK_DEBIAN_PACKAGE_NAME "assimp")
|
||||
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
|
||||
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
|
||||
SET(CPACK_DEBIAN_CHANGELOG)
|
||||
|
@ -651,6 +667,7 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
|||
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
|
||||
INCLUDE(CPack)
|
||||
INCLUDE(DebSourcePPA)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
if(WIN32)
|
||||
|
@ -671,7 +688,7 @@ if(WIN32)
|
|||
SET(ASSIMP_MSVC_VERSION "vc140")
|
||||
ELSEIF(MSVC15)
|
||||
SET(ASSIMP_MSVC_VERSION "vc141")
|
||||
ENDIF(MSVC12)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(MSVC12 OR MSVC14 OR MSVC15 )
|
||||
|
@ -696,5 +713,5 @@ if(WIN32)
|
|||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||
ENDIF()
|
||||
ENDIF(MSVC12 OR MSVC14 OR MSVC15 )
|
||||
ENDIF (WIN32)
|
||||
ENDIF()
|
||||
ENDIF ()
|
||||
|
|
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.
|
||||
### Current project status ###
|
||||
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
|
||||
![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
|
||||
[![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
|
||||
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
|
||||
<a href="https://scan.coverity.com/projects/5607">
|
||||
|
@ -178,6 +180,28 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a
|
|||
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
||||
a pull request with your changes against the main repository's `master` branch.
|
||||
|
||||
## Contributors
|
||||
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
<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 ###
|
||||
Our license is based on the modified, __3-clause BSD__-License.
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ matrix:
|
|||
|
||||
image:
|
||||
- Visual Studio 2013
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
#- Visual Studio 2015
|
||||
#- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
- MinGW
|
||||
#- MinGW
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@/
|
||||
libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
|
||||
includedir=@CMAKE_INSTALL_PREFIX@/../include/@ASSIMP_INCLUDE_INSTALL_DIR@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: @CMAKE_PROJECT_NAME@
|
||||
Description: Import various well-known 3D model formats in an uniform manner.
|
||||
|
|
|
@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
|
|||
|
||||
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
||||
|
||||
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
|
||||
|
||||
if(MSVC)
|
||||
if(MSVC_TOOLSET_VERSION)
|
||||
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
||||
|
@ -35,8 +37,6 @@ if(MSVC)
|
|||
endif()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
|
||||
|
||||
file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
|
||||
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
|
||||
|
@ -44,22 +44,22 @@ if(MSVC)
|
|||
# Import target "assimp::assimp" for configuration "Debug"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
|
||||
IMPORTED_IMPLIB_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
|
||||
else()
|
||||
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Debug"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
|
||||
endif()
|
||||
|
||||
else()
|
||||
|
@ -73,25 +73,28 @@ else()
|
|||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Debug"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
|
||||
else()
|
||||
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Debug"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
|
|||
|
||||
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
|
||||
|
||||
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
|
||||
|
||||
if(MSVC)
|
||||
if(MSVC_TOOLSET_VERSION)
|
||||
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
|
||||
|
@ -35,8 +37,6 @@ if(MSVC)
|
|||
endif()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
|
||||
|
||||
file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
|
||||
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
|
||||
|
@ -44,22 +44,22 @@ if(MSVC)
|
|||
# Import target "assimp::assimp" for configuration "Release"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
|
||||
IMPORTED_IMPLIB_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
|
||||
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
|
||||
else()
|
||||
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Release"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
||||
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}")
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
|
||||
endif()
|
||||
|
||||
else()
|
||||
|
@ -73,20 +73,25 @@ else()
|
|||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Release"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
|
||||
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
||||
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
|
||||
else()
|
||||
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
|
||||
# Import target "assimp::assimp" for configuration "Release"
|
||||
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
|
||||
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -43,23 +43,13 @@ unset(_targetsDefined)
|
|||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target assimp::assimp
|
||||
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
|
||||
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
|
||||
INTERFACE_assimp_MAJOR_VERSION "1"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "@CMAKE_INSTALL_FULL_INCLUDEDIR@"
|
||||
#INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
|
||||
)
|
||||
|
||||
|
@ -74,9 +64,6 @@ foreach(f ${CONFIG_FILES})
|
|||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||
|
|
|
@ -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
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -43,17 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file Implementation of the 3ds importer class */
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
// internal headers
|
||||
#include "3DSLoader.h"
|
||||
#include "Common/TargetAnimation.h"
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -61,42 +58,39 @@ static const unsigned int NotSet = 0xcdcdcdcd;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup final material indices, generae a default material if necessary
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial()
|
||||
{
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial() {
|
||||
// Try to find an existing material that matches the
|
||||
// typical default material setting:
|
||||
// - no textures
|
||||
// - diffuse color (in grey!)
|
||||
// NOTE: This is here to workaround the fact that some
|
||||
// exporters are writing a default material, too.
|
||||
unsigned int idx( NotSet );
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
|
||||
{
|
||||
unsigned int idx(NotSet);
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
|
||||
std::string s = mScene->mMaterials[i].mName;
|
||||
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
|
||||
*it = static_cast< char >( ::tolower( *it ) );
|
||||
for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
*it = static_cast<char>(::tolower(*it));
|
||||
}
|
||||
|
||||
if (std::string::npos == s.find("default"))continue;
|
||||
if (std::string::npos == s.find("default")) continue;
|
||||
|
||||
if (mScene->mMaterials[i].mDiffuse.r !=
|
||||
mScene->mMaterials[i].mDiffuse.g ||
|
||||
mScene->mMaterials[i].mDiffuse.r !=
|
||||
mScene->mMaterials[i].mDiffuse.b)continue;
|
||||
mScene->mMaterials[i].mDiffuse.b) continue;
|
||||
|
||||
if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
|
||||
{
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
|
||||
continue;
|
||||
}
|
||||
idx = i;
|
||||
}
|
||||
if ( NotSet == idx ) {
|
||||
idx = ( unsigned int )mScene->mMaterials.size();
|
||||
if (NotSet == idx) {
|
||||
idx = (unsigned int)mScene->mMaterials.size();
|
||||
}
|
||||
|
||||
// now iterate through all meshes and through all faces and
|
||||
|
@ -104,32 +98,26 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
unsigned int cnt = 0;
|
||||
for (std::vector<D3DS::Mesh>::iterator
|
||||
i = mScene->mMeshes.begin();
|
||||
i != mScene->mMeshes.end();++i)
|
||||
{
|
||||
i != mScene->mMeshes.end(); ++i) {
|
||||
for (std::vector<unsigned int>::iterator
|
||||
a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a) {
|
||||
// NOTE: The additional check seems to be necessary,
|
||||
// some exporters seem to generate invalid data here
|
||||
if (0xcdcdcdcd == (*a))
|
||||
{
|
||||
if (0xcdcdcdcd == (*a)) {
|
||||
(*a) = idx;
|
||||
++cnt;
|
||||
}
|
||||
else if ( (*a) >= mScene->mMaterials.size())
|
||||
{
|
||||
} else if ((*a) >= mScene->mMaterials.size()) {
|
||||
(*a) = idx;
|
||||
ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnt && idx == mScene->mMaterials.size())
|
||||
{
|
||||
if (cnt && idx == mScene->mMaterials.size()) {
|
||||
// We need to create our own default material
|
||||
D3DS::Material sMat("%%%DEFAULT");
|
||||
sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
|
||||
sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f);
|
||||
mScene->mMaterials.push_back(sMat);
|
||||
|
||||
ASSIMP_LOG_INFO("3DS: Generating default material");
|
||||
|
@ -138,22 +126,17 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
||||
{
|
||||
for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh &sMesh) {
|
||||
for (std::vector<D3DS::Face>::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) {
|
||||
// check whether all indices are in range
|
||||
for (unsigned int a = 0; a < 3;++a)
|
||||
{
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a) {
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size() - 1;
|
||||
}
|
||||
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
|
||||
{
|
||||
if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,24 +144,21 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate out unique verbose format representation
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
||||
{
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh &sMesh) {
|
||||
// TODO: really necessary? I don't think. Just a waste of memory and time
|
||||
// to do it now in a separate buffer.
|
||||
|
||||
// Allocate output storage
|
||||
std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3);
|
||||
std::vector<aiVector3D> vNew(sMesh.mFaces.size() * 3);
|
||||
std::vector<aiVector3D> vNew2;
|
||||
if (sMesh.mTexCoords.size())
|
||||
vNew2.resize(sMesh.mFaces.size() * 3);
|
||||
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
|
||||
{
|
||||
D3DS::Face& face = sMesh.mFaces[i];
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) {
|
||||
D3DS::Face &face = sMesh.mFaces[i];
|
||||
|
||||
// Positions
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
vNew[base] = sMesh.mPositions[face.mIndices[a]];
|
||||
if (sMesh.mTexCoords.size())
|
||||
vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
|
||||
|
@ -192,26 +172,24 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS texture to texture keys in an aiMaterial
|
||||
void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
||||
{
|
||||
void CopyTexture(aiMaterial &mat, D3DS::Texture &texture, aiTextureType type) {
|
||||
// Setup the texture name
|
||||
aiString tex;
|
||||
tex.Set( texture.mMapName);
|
||||
mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
|
||||
tex.Set(texture.mMapName);
|
||||
mat.AddProperty(&tex, AI_MATKEY_TEXTURE(type, 0));
|
||||
|
||||
// Setup the texture blend factor
|
||||
if (is_not_qnan(texture.mTextureBlend))
|
||||
mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
|
||||
mat.AddProperty<ai_real>(&texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type, 0));
|
||||
|
||||
// Setup the texture mapping mode
|
||||
int mapMode = static_cast<int>(texture.mMapMode);
|
||||
mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
|
||||
mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
|
||||
mat.AddProperty<int>(&mapMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0));
|
||||
mat.AddProperty<int>(&mapMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0));
|
||||
|
||||
// Mirroring - double the scaling values
|
||||
// FIXME: this is not really correct ...
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror)
|
||||
{
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror) {
|
||||
texture.mScaleU *= 2.0;
|
||||
texture.mScaleV *= 2.0;
|
||||
texture.mOffsetU /= 2.0;
|
||||
|
@ -219,21 +197,19 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
|||
}
|
||||
|
||||
// Setup texture UV transformations
|
||||
mat.AddProperty<ai_real>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
|
||||
mat.AddProperty<ai_real>(&texture.mOffsetU, 5, AI_MATKEY_UVTRANSFORM(type, 0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS material to an aiMaterial
|
||||
void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
||||
aiMaterial& mat)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
|
||||
aiMaterial &mat) {
|
||||
// NOTE: Pass the background image to the viewer by bypassing the
|
||||
// material system. This is an evil hack, never do it again!
|
||||
if (0 != mBackgroundImage.length() && bHasBG)
|
||||
{
|
||||
if (0 != mBackgroundImage.length() && bHasBG) {
|
||||
aiString tex;
|
||||
tex.Set( mBackgroundImage);
|
||||
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||
tex.Set(mBackgroundImage);
|
||||
mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||
|
||||
// Be sure this is only done for the first material
|
||||
mBackgroundImage = std::string("");
|
||||
|
@ -245,143 +221,138 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
oldMat.mAmbient.b += mClrAmbient.b;
|
||||
|
||||
aiString name;
|
||||
name.Set( oldMat.mName);
|
||||
mat.AddProperty( &name, AI_MATKEY_NAME);
|
||||
name.Set(oldMat.mName);
|
||||
mat.AddProperty(&name, AI_MATKEY_NAME);
|
||||
|
||||
// Material colors
|
||||
mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
mat.AddProperty(&oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
mat.AddProperty(&oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mat.AddProperty(&oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
mat.AddProperty(&oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
|
||||
// Phong shininess and shininess strength
|
||||
if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading)
|
||||
{
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
|
||||
{
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading) {
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) {
|
||||
oldMat.mShading = D3DS::Discreet3DS::Gouraud;
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
} else {
|
||||
mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Opacity
|
||||
mat.AddProperty<ai_real>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
|
||||
mat.AddProperty<ai_real>(&oldMat.mTransparency, 1, AI_MATKEY_OPACITY);
|
||||
|
||||
// Bump height scaling
|
||||
mat.AddProperty<ai_real>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
|
||||
mat.AddProperty<ai_real>(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING);
|
||||
|
||||
// Two sided rendering?
|
||||
if (oldMat.mTwoSided)
|
||||
{
|
||||
if (oldMat.mTwoSided) {
|
||||
int i = 1;
|
||||
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
||||
mat.AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
// Shading mode
|
||||
aiShadingMode eShading = aiShadingMode_NoShading;
|
||||
switch (oldMat.mShading)
|
||||
{
|
||||
switch (oldMat.mShading) {
|
||||
case D3DS::Discreet3DS::Flat:
|
||||
eShading = aiShadingMode_Flat; break;
|
||||
eShading = aiShadingMode_Flat;
|
||||
break;
|
||||
|
||||
// I don't know what "Wire" shading should be,
|
||||
// assume it is simple lambertian diffuse shading
|
||||
case D3DS::Discreet3DS::Wire:
|
||||
{
|
||||
case D3DS::Discreet3DS::Wire: {
|
||||
// Set the wireframe flag
|
||||
unsigned int iWire = 1;
|
||||
mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
|
||||
mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
|
||||
case D3DS::Discreet3DS::Gouraud:
|
||||
eShading = aiShadingMode_Gouraud; break;
|
||||
eShading = aiShadingMode_Gouraud;
|
||||
break;
|
||||
|
||||
// assume cook-torrance shading for metals.
|
||||
case D3DS::Discreet3DS::Phong :
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
case D3DS::Discreet3DS::Phong:
|
||||
eShading = aiShadingMode_Phong;
|
||||
break;
|
||||
|
||||
case D3DS::Discreet3DS::Metal :
|
||||
eShading = aiShadingMode_CookTorrance; break;
|
||||
case D3DS::Discreet3DS::Metal:
|
||||
eShading = aiShadingMode_CookTorrance;
|
||||
break;
|
||||
|
||||
// FIX to workaround a warning with GCC 4 who complained
|
||||
// about a missing case Blinn: here - Blinn isn't a valid
|
||||
// value in the 3DS Loader, it is just needed for ASE
|
||||
case D3DS::Discreet3DS::Blinn :
|
||||
eShading = aiShadingMode_Blinn; break;
|
||||
case D3DS::Discreet3DS::Blinn:
|
||||
eShading = aiShadingMode_Blinn;
|
||||
break;
|
||||
}
|
||||
int eShading_ = static_cast<int>(eShading);
|
||||
mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
// DIFFUSE texture
|
||||
if( oldMat.sTexDiffuse.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
|
||||
if (oldMat.sTexDiffuse.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
|
||||
|
||||
// SPECULAR texture
|
||||
if( oldMat.sTexSpecular.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
|
||||
if (oldMat.sTexSpecular.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexSpecular, aiTextureType_SPECULAR);
|
||||
|
||||
// OPACITY texture
|
||||
if( oldMat.sTexOpacity.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
|
||||
if (oldMat.sTexOpacity.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexOpacity, aiTextureType_OPACITY);
|
||||
|
||||
// EMISSIVE texture
|
||||
if( oldMat.sTexEmissive.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
|
||||
if (oldMat.sTexEmissive.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexEmissive, aiTextureType_EMISSIVE);
|
||||
|
||||
// BUMP texture
|
||||
if( oldMat.sTexBump.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
|
||||
if (oldMat.sTexBump.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexBump, aiTextureType_HEIGHT);
|
||||
|
||||
// SHININESS texture
|
||||
if( oldMat.sTexShininess.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
|
||||
if (oldMat.sTexShininess.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexShininess, aiTextureType_SHININESS);
|
||||
|
||||
// REFLECTION texture
|
||||
if( oldMat.sTexReflective.mMapName.length() > 0)
|
||||
CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
|
||||
if (oldMat.sTexReflective.mMapName.length() > 0)
|
||||
CopyTexture(mat, oldMat.sTexReflective, aiTextureType_REFLECTION);
|
||||
|
||||
// Store the name of the material itself, too
|
||||
if( oldMat.mName.length()) {
|
||||
if (oldMat.mName.length()) {
|
||||
aiString tex;
|
||||
tex.Set( oldMat.mName);
|
||||
mat.AddProperty( &tex, AI_MATKEY_NAME);
|
||||
tex.Set(oldMat.mName);
|
||||
mat.AddProperty(&tex, AI_MATKEY_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Split meshes by their materials and generate output aiMesh'es
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||
{
|
||||
std::vector<aiMesh*> avOutMeshes;
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
|
||||
std::vector<aiMesh *> avOutMeshes;
|
||||
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
|
||||
|
||||
unsigned int iFaceCnt = 0,num = 0;
|
||||
unsigned int iFaceCnt = 0, num = 0;
|
||||
aiString name;
|
||||
|
||||
// we need to split all meshes by their materials
|
||||
for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) {
|
||||
std::unique_ptr< std::vector<unsigned int>[] > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
|
||||
for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end(); ++i) {
|
||||
std::unique_ptr<std::vector<unsigned int>[]> aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
|
||||
|
||||
name.length = ASSIMP_itoa10(name.data,num++);
|
||||
name.length = ASSIMP_itoa10(name.data, num++);
|
||||
|
||||
unsigned int iNum = 0;
|
||||
for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a,++iNum)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a, ++iNum) {
|
||||
aiSplit[*a].push_back(iNum);
|
||||
}
|
||||
// now generate submeshes
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
|
||||
{
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) {
|
||||
if (aiSplit[p].empty()) {
|
||||
continue;
|
||||
}
|
||||
aiMesh* meshOut = new aiMesh();
|
||||
aiMesh *meshOut = new aiMesh();
|
||||
meshOut->mName = name;
|
||||
meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||
|
||||
|
@ -389,12 +360,12 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
meshOut->mMaterialIndex = p;
|
||||
|
||||
// use the color data as temporary storage
|
||||
meshOut->mColors[0] = (aiColor4D*)(&*i);
|
||||
meshOut->mColors[0] = (aiColor4D *)(&*i);
|
||||
avOutMeshes.push_back(meshOut);
|
||||
|
||||
// convert vertices
|
||||
meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
|
||||
meshOut->mNumVertices = meshOut->mNumFaces*3;
|
||||
meshOut->mNumVertices = meshOut->mNumFaces * 3;
|
||||
|
||||
// allocate enough storage for faces
|
||||
meshOut->mFaces = new aiFace[meshOut->mNumFaces];
|
||||
|
@ -402,23 +373,20 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
|
||||
meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
|
||||
if ((*i).mTexCoords.size())
|
||||
{
|
||||
if ((*i).mTexCoords.size()) {
|
||||
meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
|
||||
}
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
|
||||
{
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) {
|
||||
unsigned int index = aiSplit[p][q];
|
||||
aiFace& face = meshOut->mFaces[q];
|
||||
aiFace &face = meshOut->mFaces[q];
|
||||
|
||||
face.mIndices = new unsigned int[3];
|
||||
face.mNumIndices = 3;
|
||||
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
unsigned int idx = (*i).mFaces[index].mIndices[a];
|
||||
meshOut->mVertices[base] = (*i).mPositions[idx];
|
||||
meshOut->mNormals [base] = (*i).mNormals[idx];
|
||||
meshOut->mNormals[base] = (*i).mNormals[idx];
|
||||
|
||||
if ((*i).mTexCoords.size())
|
||||
meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
|
||||
|
@ -431,8 +399,8 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
// Copy them to the output array
|
||||
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
|
||||
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
|
||||
pcOut->mMeshes = new aiMesh *[pcOut->mNumMeshes]();
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
|
||||
pcOut->mMeshes[a] = avOutMeshes[a];
|
||||
}
|
||||
|
||||
|
@ -444,47 +412,44 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Add a node to the scenegraph and setup its final transformation
|
||||
void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
||||
D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
|
||||
{
|
||||
void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
|
||||
D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) {
|
||||
std::vector<unsigned int> iArray;
|
||||
iArray.reserve(3);
|
||||
|
||||
aiMatrix4x4 abs;
|
||||
|
||||
// Find all meshes with the same name as the node
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
|
||||
{
|
||||
const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
|
||||
ai_assert(NULL != pcMesh);
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) {
|
||||
const D3DS::Mesh *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0];
|
||||
ai_assert(nullptr != pcMesh);
|
||||
|
||||
if (pcIn->mName == pcMesh->mName)
|
||||
iArray.push_back(a);
|
||||
}
|
||||
if (!iArray.empty())
|
||||
{
|
||||
if (!iArray.empty()) {
|
||||
// The matrix should be identical for all meshes with the
|
||||
// same name. It HAS to be identical for all meshes .....
|
||||
D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
|
||||
D3DS::Mesh *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]);
|
||||
|
||||
// Compute the inverse of the transformation matrix to move the
|
||||
// vertices back to their relative and local space
|
||||
aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
|
||||
mInv.Inverse();mInvTransposed.Transpose();
|
||||
mInv.Inverse();
|
||||
mInvTransposed.Transpose();
|
||||
aiVector3D pivot = pcIn->vPivot;
|
||||
|
||||
pcOut->mNumMeshes = (unsigned int)iArray.size();
|
||||
pcOut->mMeshes = new unsigned int[iArray.size()];
|
||||
for (unsigned int i = 0;i < iArray.size();++i) {
|
||||
for (unsigned int i = 0; i < iArray.size(); ++i) {
|
||||
const unsigned int iIndex = iArray[i];
|
||||
aiMesh* const mesh = pcSOut->mMeshes[iIndex];
|
||||
aiMesh *const mesh = pcSOut->mMeshes[iIndex];
|
||||
|
||||
if (mesh->mColors[1] == NULL)
|
||||
{
|
||||
if (mesh->mColors[1] == nullptr) {
|
||||
// Transform the vertices back into their local space
|
||||
// fixme: consider computing normals after this, so we don't need to transform them
|
||||
const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices;
|
||||
aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
|
||||
const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices;
|
||||
aiVector3D *pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
|
||||
|
||||
for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
|
||||
*pvCurrent = mInv * (*pvCurrent);
|
||||
|
@ -492,8 +457,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle negative transformation matrix determinant -> invert vertex x
|
||||
if (imesh->mMat.Determinant() < 0.0f)
|
||||
{
|
||||
if (imesh->mMat.Determinant() < 0.0f) {
|
||||
/* we *must* have normals */
|
||||
for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
|
||||
pvCurrent->x *= -1.f;
|
||||
|
@ -503,17 +467,15 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle pivot point
|
||||
if (pivot.x || pivot.y || pivot.z)
|
||||
{
|
||||
if (pivot.x || pivot.y || pivot.z) {
|
||||
for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
|
||||
*pvCurrent -= pivot;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->mColors[1] = (aiColor4D*)1;
|
||||
}
|
||||
else
|
||||
mesh->mColors[1] = (aiColor4D*)1;
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
} else
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
|
||||
// Setup the mesh index
|
||||
pcOut->mMeshes[i] = iIndex;
|
||||
|
@ -522,48 +484,48 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// Setup the name of the node
|
||||
// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
|
||||
if (pcIn->mInstanceNumber > 1)
|
||||
{
|
||||
if (pcIn->mInstanceNumber > 1) {
|
||||
char tmp[12];
|
||||
ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
|
||||
std::string tempStr = pcIn->mName + "_inst_";
|
||||
tempStr += tmp;
|
||||
pcOut->mName.Set(tempStr);
|
||||
}
|
||||
else
|
||||
} else
|
||||
pcOut->mName.Set(pcIn->mName);
|
||||
|
||||
// Now build the transformation matrix of the node
|
||||
// ROTATION
|
||||
if (pcIn->aRotationKeys.size()){
|
||||
if (pcIn->aRotationKeys.size()) {
|
||||
|
||||
// FIX to get to Assimp's quaternion conventions
|
||||
for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
|
||||
(*it).mValue.w *= -1.f;
|
||||
}
|
||||
|
||||
pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
|
||||
}
|
||||
else if (pcIn->aCameraRollKeys.size())
|
||||
{
|
||||
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
|
||||
pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix());
|
||||
} else if (pcIn->aCameraRollKeys.size()) {
|
||||
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue),
|
||||
pcOut->mTransformation);
|
||||
}
|
||||
|
||||
// SCALING
|
||||
aiMatrix4x4& m = pcOut->mTransformation;
|
||||
if (pcIn->aScalingKeys.size())
|
||||
{
|
||||
const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
|
||||
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
|
||||
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
|
||||
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
|
||||
aiMatrix4x4 &m = pcOut->mTransformation;
|
||||
if (pcIn->aScalingKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aScalingKeys[0].mValue;
|
||||
m.a1 *= v.x;
|
||||
m.b1 *= v.x;
|
||||
m.c1 *= v.x;
|
||||
m.a2 *= v.y;
|
||||
m.b2 *= v.y;
|
||||
m.c2 *= v.y;
|
||||
m.a3 *= v.z;
|
||||
m.b3 *= v.z;
|
||||
m.c3 *= v.z;
|
||||
}
|
||||
|
||||
// TRANSLATION
|
||||
if (pcIn->aPositionKeys.size())
|
||||
{
|
||||
const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
|
||||
if (pcIn->aPositionKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aPositionKeys[0].mValue;
|
||||
m.a4 += v.x;
|
||||
m.b4 += v.y;
|
||||
m.c4 += v.z;
|
||||
|
@ -572,34 +534,31 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Generate animation channels for the node
|
||||
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
|
||||
pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
|
||||
pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
aiAnimation* anim = pcSOut->mAnimations[0];
|
||||
pcIn->aTargetPositionKeys.size() > 1) {
|
||||
aiAnimation *anim = pcSOut->mAnimations[0];
|
||||
ai_assert(nullptr != anim);
|
||||
|
||||
if (pcIn->aCameraRollKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
|
||||
if (pcIn->aCameraRollKeys.size() > 1) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ...");
|
||||
|
||||
// Camera roll keys - in fact they're just rotations
|
||||
// around the camera's z axis. The angles are given
|
||||
// in degrees (and they're clockwise).
|
||||
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
|
||||
{
|
||||
aiQuatKey& q = pcIn->aRotationKeys[i];
|
||||
aiFloatKey& f = pcIn->aCameraRollKeys[i];
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) {
|
||||
aiQuatKey &q = pcIn->aRotationKeys[i];
|
||||
aiFloatKey &f = pcIn->aCameraRollKeys[i];
|
||||
|
||||
q.mTime = f.mTime;
|
||||
|
||||
// FIX to get to Assimp quaternion conventions
|
||||
q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
|
||||
q.mValue = aiQuaternion(0.f, 0.f, AI_DEG_TO_RAD(/*-*/ f.mValue));
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ...");
|
||||
|
||||
// Camera or spot light - need to convert the separate
|
||||
// target position channel to our representation
|
||||
|
@ -639,41 +598,38 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Cameras or lights define their transformation in their parent node and in the
|
||||
// corresponding light or camera chunks. However, we read and process the latter
|
||||
// to to be able to return valid cameras/lights even if no scenegraph is given.
|
||||
for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) {
|
||||
for (unsigned int n = 0; n < pcSOut->mNumCameras; ++n) {
|
||||
if (pcSOut->mCameras[n]->mName == pcOut->mName) {
|
||||
pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
|
||||
pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f, 0.f, 1.f);
|
||||
}
|
||||
}
|
||||
for (unsigned int n = 0; n < pcSOut->mNumLights;++n) {
|
||||
for (unsigned int n = 0; n < pcSOut->mNumLights; ++n) {
|
||||
if (pcSOut->mLights[n]->mName == pcOut->mName) {
|
||||
pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
|
||||
pcSOut->mLights[n]->mDirection = aiVector3D(0.f, 0.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new node anim and setup its name
|
||||
aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
|
||||
aiNodeAnim *nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
|
||||
nda->mNodeName.Set(pcIn->mName);
|
||||
|
||||
// POSITION keys
|
||||
if (pcIn->aPositionKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aPositionKeys.size() > 0) {
|
||||
nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
|
||||
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
|
||||
::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
|
||||
sizeof(aiVectorKey)*nda->mNumPositionKeys);
|
||||
::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0],
|
||||
sizeof(aiVectorKey) * nda->mNumPositionKeys);
|
||||
}
|
||||
|
||||
// ROTATION keys
|
||||
if (pcIn->aRotationKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aRotationKeys.size() > 0) {
|
||||
nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
|
||||
nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
|
||||
|
||||
// Rotations are quaternion offsets
|
||||
aiQuaternion abs1;
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
|
||||
{
|
||||
const aiQuatKey& q = pcIn->aRotationKeys[n];
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) {
|
||||
const aiQuatKey &q = pcIn->aRotationKeys[n];
|
||||
|
||||
abs1 = (n ? abs1 * q.mValue : q.mValue);
|
||||
nda->mRotationKeys[n].mTime = q.mTime;
|
||||
|
@ -682,59 +638,53 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// SCALING keys
|
||||
if (pcIn->aScalingKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aScalingKeys.size() > 0) {
|
||||
nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
|
||||
nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
|
||||
::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
|
||||
sizeof(aiVectorKey)*nda->mNumScalingKeys);
|
||||
::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0],
|
||||
sizeof(aiVectorKey) * nda->mNumScalingKeys);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate storage for children
|
||||
pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
|
||||
pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
|
||||
pcOut->mChildren = new aiNode *[pcIn->mChildren.size()];
|
||||
|
||||
// Recursively process all children
|
||||
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
|
||||
for (unsigned int i = 0; i < size;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
pcOut->mChildren[i] = new aiNode();
|
||||
pcOut->mChildren[i]->mParent = pcOut;
|
||||
AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
|
||||
AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find out how many node animation channels we'll have finally
|
||||
void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
||||
{
|
||||
void CountTracks(D3DS::Node *node, unsigned int &cnt) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// We will never generate more than one channel for a node, so
|
||||
// this is rather easy here.
|
||||
|
||||
if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
|
||||
node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
|
||||
node->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
node->aTargetPositionKeys.size() > 1) {
|
||||
++cnt;
|
||||
|
||||
// account for the additional channel for the camera/spotlight target position
|
||||
if (node->aTargetPositionKeys.size() > 1)++cnt;
|
||||
if (node->aTargetPositionKeys.size() > 1) ++cnt;
|
||||
}
|
||||
|
||||
// Recursively process all children
|
||||
for (unsigned int i = 0; i < node->mChildren.size();++i)
|
||||
CountTracks(node->mChildren[i],cnt);
|
||||
for (unsigned int i = 0; i < node->mChildren.size(); ++i)
|
||||
CountTracks(node->mChildren[i], cnt);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate the output node graph
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
|
||||
pcOut->mRootNode = new aiNode();
|
||||
if (0 == mRootNode->mChildren.size())
|
||||
{
|
||||
if (0 == mRootNode->mChildren.size()) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// It seems the file is so messed up that it has not even a hierarchy.
|
||||
// generate a flat hiearachy which looks like this:
|
||||
|
@ -750,27 +700,25 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
|
||||
static_cast<unsigned int>(mScene->mCameras.size() + mScene->mLights.size());
|
||||
|
||||
pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
|
||||
pcOut->mRootNode->mChildren = new aiNode *[pcOut->mRootNode->mNumChildren];
|
||||
pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
|
||||
|
||||
// Build dummy nodes for all meshes
|
||||
unsigned int a = 0;
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
|
||||
{
|
||||
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
pcNode->mMeshes = new unsigned int[1];
|
||||
pcNode->mMeshes[0] = i;
|
||||
pcNode->mNumMeshes = 1;
|
||||
|
||||
// Build a name for the node
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i);
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u", i);
|
||||
}
|
||||
|
||||
// Build dummy nodes for all cameras
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
|
||||
{
|
||||
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
// Build a name for the node
|
||||
|
@ -778,75 +726,68 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// Build dummy nodes for all lights
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
|
||||
{
|
||||
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
// Build a name for the node
|
||||
pcNode->mName = mScene->mLights[i]->mName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// First of all: find out how many scaling, rotation and translation
|
||||
// animation tracks we'll have afterwards
|
||||
unsigned int numChannel = 0;
|
||||
CountTracks(mRootNode,numChannel);
|
||||
CountTracks(mRootNode, numChannel);
|
||||
|
||||
if (numChannel)
|
||||
{
|
||||
if (numChannel) {
|
||||
// Allocate a primary animation channel
|
||||
pcOut->mNumAnimations = 1;
|
||||
pcOut->mAnimations = new aiAnimation*[1];
|
||||
aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation();
|
||||
pcOut->mAnimations = new aiAnimation *[1];
|
||||
aiAnimation *anim = pcOut->mAnimations[0] = new aiAnimation();
|
||||
|
||||
anim->mName.Set("3DSMasterAnim");
|
||||
|
||||
// Allocate enough storage for all node animation channels,
|
||||
// but don't set the mNumChannels member - we'll use it to
|
||||
// index into the array
|
||||
anim->mChannels = new aiNodeAnim*[numChannel];
|
||||
anim->mChannels = new aiNodeAnim *[numChannel];
|
||||
}
|
||||
|
||||
aiMatrix4x4 m;
|
||||
AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
|
||||
AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode, m);
|
||||
}
|
||||
|
||||
// We used the first and second vertex color set to store some temporary values so we need to cleanup here
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
|
||||
{
|
||||
pcOut->mMeshes[a]->mColors[0] = NULL;
|
||||
pcOut->mMeshes[a]->mColors[1] = NULL;
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
|
||||
pcOut->mMeshes[a]->mColors[0] = nullptr;
|
||||
pcOut->mMeshes[a]->mColors[1] = nullptr;
|
||||
}
|
||||
|
||||
pcOut->mRootNode->mTransformation = aiMatrix4x4(
|
||||
1.f,0.f,0.f,0.f,
|
||||
0.f,0.f,1.f,0.f,
|
||||
0.f,-1.f,0.f,0.f,
|
||||
0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, -1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f) *
|
||||
pcOut->mRootNode->mTransformation;
|
||||
|
||||
// If the root node is unnamed name it "<3DSRoot>"
|
||||
if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
|
||||
{
|
||||
if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") ||
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) {
|
||||
pcOut->mRootNode->mName.Set("<3DSRoot>");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert all meshes in the scene and generate the final output scene.
|
||||
void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
|
||||
// Allocate enough storage for all output materials
|
||||
pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
|
||||
pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials];
|
||||
pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials];
|
||||
|
||||
// ... and convert the 3DS materials to aiMaterial's
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
|
||||
{
|
||||
aiMaterial* pcNew = new aiMaterial();
|
||||
ConvertMaterial(mScene->mMaterials[i],*pcNew);
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) {
|
||||
aiMaterial *pcNew = new aiMaterial();
|
||||
ConvertMaterial(mScene->mMaterials[i], *pcNew);
|
||||
pcOut->mMaterials[i] = pcNew;
|
||||
}
|
||||
|
||||
|
@ -855,18 +796,16 @@ void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
|||
|
||||
// Now copy all light sources to the output scene
|
||||
pcOut->mNumLights = (unsigned int)mScene->mLights.size();
|
||||
if (pcOut->mNumLights)
|
||||
{
|
||||
pcOut->mLights = new aiLight*[pcOut->mNumLights];
|
||||
::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
|
||||
if (pcOut->mNumLights) {
|
||||
pcOut->mLights = new aiLight *[pcOut->mNumLights];
|
||||
::memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights);
|
||||
}
|
||||
|
||||
// Now copy all cameras to the output scene
|
||||
pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
|
||||
if (pcOut->mNumCameras)
|
||||
{
|
||||
pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
|
||||
::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
|
||||
if (pcOut->mNumCameras) {
|
||||
pcOut->mCameras = new aiCamera *[pcOut->mNumCameras];
|
||||
::memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,16 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
|
||||
#include "3DS/3DSExporter.h"
|
||||
#include "3DS/3DSLoader.h"
|
||||
#include "3DS/3DSHelper.h"
|
||||
#include "AssetLib/3DS/3DSExporter.h"
|
||||
#include "AssetLib/3DS/3DSHelper.h"
|
||||
#include "AssetLib/3DS/3DSLoader.h"
|
||||
#include "PostProcessing/SplitLargeMeshes.h"
|
||||
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -62,25 +62,24 @@ using namespace D3DS;
|
|||
|
||||
namespace {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scope utility to write a 3DS file chunk.
|
||||
//
|
||||
// Upon construction, the chunk header is written with the chunk type (flags)
|
||||
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
||||
// size based on the then-position of the output stream cursor is filled in.
|
||||
class ChunkWriter {
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scope utility to write a 3DS file chunk.
|
||||
//
|
||||
// Upon construction, the chunk header is written with the chunk type (flags)
|
||||
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
||||
// size based on the then-position of the output stream cursor is filled in.
|
||||
class ChunkWriter {
|
||||
enum {
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef
|
||||
, SIZE_OFFSET = 2
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
|
||||
SIZE_OFFSET = 2
|
||||
};
|
||||
public:
|
||||
|
||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
||||
: writer(writer)
|
||||
{
|
||||
public:
|
||||
ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
|
||||
writer(writer) {
|
||||
chunk_start_pos = writer.GetCurrentPos();
|
||||
writer.PutU2(chunk_type);
|
||||
writer.PutU4(CHUNK_SIZE_NOT_SET);
|
||||
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
|
||||
}
|
||||
|
||||
~ChunkWriter() {
|
||||
|
@ -94,18 +93,17 @@ namespace {
|
|||
writer.SetCurrentPos(head_pos);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamWriterLE& writer;
|
||||
private:
|
||||
StreamWriterLE &writer;
|
||||
std::size_t chunk_start_pos;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Return an unique name for a given |mesh| attached to |node| that
|
||||
// preserves the mesh's given name if it has one. |index| is the index
|
||||
// of the mesh in |aiScene::mMeshes|.
|
||||
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
|
||||
// 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};
|
||||
char postfix[10] = { 0 };
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
|
||||
std::string result = node.mName.C_Str();
|
||||
|
@ -113,14 +111,14 @@ namespace {
|
|||
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) {
|
||||
// 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};
|
||||
char postfix[10] = { 0 };
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
|
||||
aiString mat_name;
|
||||
|
@ -129,34 +127,33 @@ namespace {
|
|||
}
|
||||
|
||||
return "Material" + underscore + postfix;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect world transformations for each node
|
||||
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
|
||||
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
||||
// Collect world transformations for each node
|
||||
void CollectTrafos(const aiNode *node, std::map<const aiNode *, aiMatrix4x4> &trafos) {
|
||||
const aiMatrix4x4 &parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
||||
trafos[node] = parent * node->mTransformation;
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
CollectTrafos(node->mChildren[i], trafos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a flat list of the meshes (by index) assigned to each node
|
||||
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
|
||||
// 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
|
||||
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
|
||||
{
|
||||
std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
|
||||
if(!outfile) {
|
||||
void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
|
||||
std::shared_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
|
||||
if (!outfile) {
|
||||
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
||||
}
|
||||
|
||||
|
@ -167,8 +164,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
|
|||
// SplitLargeMeshes can do this, but it requires the correct limit to be set
|
||||
// which is not possible with the current way of specifying preprocess steps
|
||||
// in |Exporter::ExportFormatEntry|.
|
||||
aiScene* scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
aiScene *scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp, pScene);
|
||||
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
|
||||
SplitLargeMeshesProcess_Triangle tri_splitter;
|
||||
|
@ -186,28 +183,26 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
|
|||
} // end of namespace Assimp
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
|
||||
: scene(scene)
|
||||
, writer(outfile)
|
||||
{
|
||||
Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene *scene) :
|
||||
scene(scene), writer(outfile) {
|
||||
CollectTrafos(scene->mRootNode, trafos);
|
||||
CollectMeshes(scene->mRootNode, meshes);
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
|
||||
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAIN);
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
||||
WriteMaterials();
|
||||
WriteMeshes();
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
||||
ChunkWriter curChunk1(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
||||
writer.PutF4(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
||||
WriteHierarchy(*scene->mRootNode, -1, -1);
|
||||
}
|
||||
}
|
||||
|
@ -217,15 +212,13 @@ Discreet3DSExporter::~Discreet3DSExporter() {
|
|||
// empty
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
|
||||
{
|
||||
int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) {
|
||||
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
|
||||
// Assimp node names are unique and distinct from all mesh-node
|
||||
// names we generate; thus we can use them as-is
|
||||
|
@ -237,7 +230,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
|||
|
||||
int16_t hierarchy_pos = static_cast<int16_t>(seq);
|
||||
if (sibling_level != -1) {
|
||||
hierarchy_pos = sibling_level;
|
||||
hierarchy_pos = (uint16_t)sibling_level;
|
||||
}
|
||||
|
||||
// Write the hierarchy position
|
||||
|
@ -260,9 +253,9 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
|||
const bool first_child = node.mNumChildren == 0 && i == 0;
|
||||
|
||||
const unsigned int mesh_idx = node.mMeshes[i];
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
WriteString(GetMeshName(mesh, mesh_idx, node));
|
||||
|
@ -276,36 +269,35 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteMaterials()
|
||||
{
|
||||
void Discreet3DSExporter::WriteMaterials() {
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||
const aiMaterial& mat = *scene->mMaterials[i];
|
||||
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||
const aiMaterial &mat = *scene->mMaterials[i];
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
|
||||
const std::string& name = GetMaterialName(mat, i);
|
||||
const std::string &name = GetMaterialName(mat, i);
|
||||
WriteString(name);
|
||||
}
|
||||
|
||||
aiColor3D color;
|
||||
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
|
@ -314,7 +306,7 @@ void Discreet3DSExporter::WriteMaterials()
|
|||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
|
||||
|
||||
Discreet3DS::shadetype3ds shading_mode_out;
|
||||
switch(shading_mode) {
|
||||
switch (shading_mode) {
|
||||
case aiShadingMode_Flat:
|
||||
case aiShadingMode_NoShading:
|
||||
shading_mode_out = Discreet3DS::Flat;
|
||||
|
@ -341,7 +333,6 @@ void Discreet3DSExporter::WriteMaterials()
|
|||
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
|
||||
}
|
||||
|
||||
|
||||
float f;
|
||||
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
|
||||
|
@ -370,8 +361,7 @@ void Discreet3DSExporter::WriteMaterials()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
|
||||
{
|
||||
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
||||
aiString path;
|
||||
aiTextureMapMode map_mode[2] = {
|
||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||
|
@ -389,19 +379,18 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
|
|||
|
||||
ChunkWriter chunk(writer, chunk_flags);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
||||
WriteString(path);
|
||||
}
|
||||
|
||||
WritePercentChunk(blend);
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
||||
uint16_t val = 0; // WRAP
|
||||
if (map_mode[0] == aiTextureMapMode_Mirror) {
|
||||
val = 0x2;
|
||||
}
|
||||
else if (map_mode[0] == aiTextureMapMode_Decal) {
|
||||
} else if (map_mode[0] == aiTextureMapMode_Decal) {
|
||||
val = 0x10;
|
||||
}
|
||||
writer.PutU2(val);
|
||||
|
@ -410,8 +399,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteMeshes()
|
||||
{
|
||||
void Discreet3DSExporter::WriteMeshes() {
|
||||
// NOTE: 3DS allows for instances. However:
|
||||
// i) not all importers support reading them
|
||||
// ii) instances are not as flexible as they are in assimp, in particular,
|
||||
|
@ -423,36 +411,35 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
// Furthermore, the TRIMESH is transformed into world space so that it will
|
||||
// appear correctly if importers don't read the scene hierarchy at all.
|
||||
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
|
||||
const aiNode& node = *(*it).first;
|
||||
const aiNode &node = *(*it).first;
|
||||
const unsigned int mesh_idx = (*it).second;
|
||||
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
|
||||
|
||||
// This should not happen if the SLM step is correctly executed
|
||||
// before the scene is handed to the exporter
|
||||
ai_assert(mesh.mNumVertices <= 0xffff);
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
|
||||
const aiMatrix4x4& trafo = trafos[&node];
|
||||
const aiMatrix4x4 &trafo = trafos[&node];
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
|
||||
|
||||
// Mesh name is tied to the node it is attached to so it can later be referenced
|
||||
const std::string& name = GetMeshName(mesh, mesh_idx, node);
|
||||
const std::string &name = GetMeshName(mesh, mesh_idx, node);
|
||||
WriteString(name);
|
||||
|
||||
|
||||
// TRIMESH chunk
|
||||
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
||||
|
||||
// Vertices in world space
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
||||
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = trafo * mesh.mVertices[i];
|
||||
const aiVector3D &v = trafo * mesh.mVertices[i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
writer.PutF4(v.z);
|
||||
|
@ -461,12 +448,12 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
|
||||
// UV coordinates
|
||||
if (mesh.HasTextureCoords(0)) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = mesh.mTextureCoords[0][i];
|
||||
const aiVector3D &v = mesh.mTextureCoords[0][i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
}
|
||||
|
@ -474,14 +461,14 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
|
||||
// Faces (indices)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
|
||||
// Count triangles, discard lines and points
|
||||
uint16_t count = 0;
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
const aiFace &f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
|
@ -492,7 +479,7 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
const aiFace &f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
|
@ -513,7 +500,7 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
|
||||
// Transformation matrix by which the mesh vertices have been pre-transformed with.
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
||||
for (unsigned int r = 0; r < 4; ++r) {
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
writer.PutF4(trafo[r][c]);
|
||||
|
@ -524,10 +511,9 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
||||
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) {
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||
const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
||||
WriteString(name);
|
||||
|
||||
// Because assimp splits meshes by material, only a single
|
||||
|
@ -542,7 +528,7 @@ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteString(const std::string& s) {
|
||||
void Discreet3DSExporter::WriteString(const std::string &s) {
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
writer.PutI1(*it);
|
||||
}
|
||||
|
@ -550,7 +536,7 @@ void Discreet3DSExporter::WriteString(const std::string& s) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteString(const aiString& s) {
|
||||
void Discreet3DSExporter::WriteString(const aiString &s) {
|
||||
for (std::size_t i = 0; i < s.length; ++i) {
|
||||
writer.PutI1(s.data[i]);
|
||||
}
|
||||
|
@ -558,8 +544,8 @@ void Discreet3DSExporter::WriteString(const aiString& s) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
void Discreet3DSExporter::WriteColor(const aiColor3D &color) {
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
writer.PutF4(color.r);
|
||||
writer.PutF4(color.g);
|
||||
writer.PutF4(color.b);
|
||||
|
@ -567,16 +553,15 @@ void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WritePercentChunk(float f) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
||||
writer.PutF4(f);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WritePercentChunk(double f) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTD);
|
||||
ChunkWriter ccurChunkhunk(writer, Discreet3DS::CHUNK_PERCENTD);
|
||||
writer.PutF8(f);
|
||||
}
|
||||
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -45,14 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AI_3DSFILEHELPER_H_INC
|
||||
#define AI_3DSFILEHELPER_H_INC
|
||||
|
||||
#include <assimp/SpatialSort.h>
|
||||
#include <assimp/SmoothingGroups.h>
|
||||
#include <assimp/SpatialSort.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/qnan.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/camera.h>
|
||||
#include <assimp/light.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/qnan.h>
|
||||
#include <stdio.h> //sprintf
|
||||
|
||||
namespace Assimp {
|
||||
|
@ -81,11 +81,9 @@ public:
|
|||
uint32_t Size;
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
//! Used for shading field in material3ds structure
|
||||
//! From AutoDesk 3ds SDK
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
// translated to gouraud shading with wireframe active
|
||||
Wire = 0x0,
|
||||
|
||||
|
@ -109,17 +107,15 @@ public:
|
|||
} shadetype3ds;
|
||||
|
||||
// Flags for animated keys
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
KEY_USE_TENS = 0x1,
|
||||
KEY_USE_CONT = 0x2,
|
||||
KEY_USE_BIAS = 0x4,
|
||||
KEY_USE_EASE_TO = 0x8,
|
||||
KEY_USE_EASE_FROM = 0x10
|
||||
} ;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
|
||||
// ********************************************************************
|
||||
// Basic chunks which can be found everywhere in the file
|
||||
|
@ -209,7 +205,7 @@ public:
|
|||
// Specifies the shininess of the material
|
||||
// followed by percentage chunk
|
||||
CHUNK_MAT_SHININESS = 0xA040,
|
||||
CHUNK_MAT_SHININESS_PERCENT = 0xA041 ,
|
||||
CHUNK_MAT_SHININESS_PERCENT = 0xA041,
|
||||
|
||||
// Specifies the shading mode to be used
|
||||
// followed by a short
|
||||
|
@ -322,26 +318,77 @@ public:
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a 3ds mesh face */
|
||||
struct Face : public FaceWithSmoothingGroup
|
||||
{
|
||||
struct Face : public FaceWithSmoothingGroup {
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4315)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a texture */
|
||||
struct Texture {
|
||||
//! Default constructor
|
||||
Texture() AI_NO_EXCEPT
|
||||
: mOffsetU (0.0)
|
||||
, mOffsetV (0.0)
|
||||
, mScaleU (1.0)
|
||||
, mScaleV (1.0)
|
||||
, mRotation (0.0)
|
||||
, mMapMode (aiTextureMapMode_Wrap)
|
||||
, bPrivate()
|
||||
, iUVSrc (0) {
|
||||
: mTextureBlend(0.0f),
|
||||
mMapName(),
|
||||
mOffsetU(0.0),
|
||||
mOffsetV(0.0),
|
||||
mScaleU(1.0),
|
||||
mScaleV(1.0),
|
||||
mRotation(0.0),
|
||||
mMapMode(aiTextureMapMode_Wrap),
|
||||
bPrivate(),
|
||||
iUVSrc(0) {
|
||||
mTextureBlend = get_qnan();
|
||||
}
|
||||
|
||||
Texture(const Texture &other) :
|
||||
mTextureBlend(other.mTextureBlend),
|
||||
mMapName(other.mMapName),
|
||||
mOffsetU(other.mOffsetU),
|
||||
mOffsetV(other.mOffsetV),
|
||||
mScaleU(other.mScaleU),
|
||||
mScaleV(other.mScaleV),
|
||||
mRotation(other.mRotation),
|
||||
mMapMode(other.mMapMode),
|
||||
bPrivate(other.bPrivate),
|
||||
iUVSrc(other.iUVSrc) {
|
||||
// empty
|
||||
}
|
||||
|
||||
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)),
|
||||
mMapName(std::move(other.mMapName)),
|
||||
mOffsetU(std::move(other.mOffsetU)),
|
||||
mOffsetV(std::move(other.mOffsetV)),
|
||||
mScaleU(std::move(other.mScaleU)),
|
||||
mScaleV(std::move(other.mScaleV)),
|
||||
mRotation(std::move(other.mRotation)),
|
||||
mMapMode(std::move(other.mMapMode)),
|
||||
bPrivate(std::move(other.bPrivate)),
|
||||
iUVSrc(std::move(other.iUVSrc)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
Texture &operator=(Texture &&other) AI_NO_EXCEPT {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
mTextureBlend = std::move(other.mTextureBlend);
|
||||
mMapName = std::move(other.mMapName);
|
||||
mOffsetU = std::move(other.mOffsetU);
|
||||
mOffsetV = std::move(other.mOffsetV);
|
||||
mScaleU = std::move(other.mScaleU);
|
||||
mScaleV = std::move(other.mScaleV);
|
||||
mRotation = std::move(other.mRotation);
|
||||
mMapMode = std::move(other.mMapMode);
|
||||
bPrivate = std::move(other.bPrivate);
|
||||
iUVSrc = std::move(other.iUVSrc);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Specifies the blend factor for the texture
|
||||
ai_real mTextureBlend;
|
||||
|
||||
|
@ -367,55 +414,81 @@ struct Texture {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a 3ds material */
|
||||
struct Material
|
||||
{
|
||||
struct Material {
|
||||
//! Default constructor has been deleted
|
||||
Material() = delete;
|
||||
|
||||
Material() :
|
||||
mName(),
|
||||
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||
mSpecularExponent(ai_real(0.0)),
|
||||
mShininessStrength(ai_real(1.0)),
|
||||
mShading(Discreet3DS::Gouraud),
|
||||
mTransparency(ai_real(1.0)),
|
||||
mBumpHeight(ai_real(1.0)),
|
||||
mTwoSided(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Constructor with explicit name
|
||||
explicit Material(const std::string &name)
|
||||
: mName(name)
|
||||
, mDiffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black
|
||||
, mSpecularExponent ( ai_real( 0.0 ) )
|
||||
, mShininessStrength ( ai_real( 1.0 ) )
|
||||
, mShading(Discreet3DS::Gouraud)
|
||||
, mTransparency ( ai_real( 1.0 ) )
|
||||
, mBumpHeight ( ai_real( 1.0 ) )
|
||||
, mTwoSided (false)
|
||||
{
|
||||
explicit Material(const std::string &name) :
|
||||
mName(name),
|
||||
mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
|
||||
mSpecularExponent(ai_real(0.0)),
|
||||
mShininessStrength(ai_real(1.0)),
|
||||
mShading(Discreet3DS::Gouraud),
|
||||
mTransparency(ai_real(1.0)),
|
||||
mBumpHeight(ai_real(1.0)),
|
||||
mTwoSided(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
Material(const Material &other) :
|
||||
mName(other.mName),
|
||||
mDiffuse(other.mDiffuse),
|
||||
mSpecularExponent(other.mSpecularExponent),
|
||||
mShininessStrength(other.mShininessStrength),
|
||||
mSpecular(other.mSpecular),
|
||||
mAmbient(other.mAmbient),
|
||||
mShading(other.mShading),
|
||||
mTransparency(other.mTransparency),
|
||||
sTexDiffuse(other.sTexDiffuse),
|
||||
sTexOpacity(other.sTexOpacity),
|
||||
sTexSpecular(other.sTexSpecular),
|
||||
sTexReflective(other.sTexReflective),
|
||||
sTexBump(other.sTexBump),
|
||||
sTexEmissive(other.sTexEmissive),
|
||||
sTexShininess(other.sTexShininess),
|
||||
mBumpHeight(other.mBumpHeight),
|
||||
mEmissive(other.mEmissive),
|
||||
sTexAmbient(other.sTexAmbient),
|
||||
mTwoSided(other.mTwoSided) {
|
||||
// empty
|
||||
|
||||
Material(const Material &other) = default;
|
||||
Material &operator=(const Material &other) = default;
|
||||
|
||||
}
|
||||
|
||||
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
||||
Material(Material &&other) AI_NO_EXCEPT
|
||||
: mName(std::move(other.mName))
|
||||
, mDiffuse(std::move(other.mDiffuse))
|
||||
, mSpecularExponent(std::move(other.mSpecularExponent))
|
||||
, mShininessStrength(std::move(other.mShininessStrength))
|
||||
, mSpecular(std::move(other.mSpecular))
|
||||
, mAmbient(std::move(other.mAmbient))
|
||||
, mShading(std::move(other.mShading))
|
||||
, mTransparency(std::move(other.mTransparency))
|
||||
, sTexDiffuse(std::move(other.sTexDiffuse))
|
||||
, sTexOpacity(std::move(other.sTexOpacity))
|
||||
, sTexSpecular(std::move(other.sTexSpecular))
|
||||
, sTexReflective(std::move(other.sTexReflective))
|
||||
, sTexBump(std::move(other.sTexBump))
|
||||
, sTexEmissive(std::move(other.sTexEmissive))
|
||||
, sTexShininess(std::move(other.sTexShininess))
|
||||
, mBumpHeight(std::move(other.mBumpHeight))
|
||||
, mEmissive(std::move(other.mEmissive))
|
||||
, sTexAmbient(std::move(other.sTexAmbient))
|
||||
, mTwoSided(std::move(other.mTwoSided))
|
||||
{
|
||||
Material(Material &&other) AI_NO_EXCEPT :
|
||||
mName(std::move(other.mName)),
|
||||
mDiffuse(std::move(other.mDiffuse)),
|
||||
mSpecularExponent(std::move(other.mSpecularExponent)),
|
||||
mShininessStrength(std::move(other.mShininessStrength)),
|
||||
mSpecular(std::move(other.mSpecular)),
|
||||
mAmbient(std::move(other.mAmbient)),
|
||||
mShading(std::move(other.mShading)),
|
||||
mTransparency(std::move(other.mTransparency)),
|
||||
sTexDiffuse(std::move(other.sTexDiffuse)),
|
||||
sTexOpacity(std::move(other.sTexOpacity)),
|
||||
sTexSpecular(std::move(other.sTexSpecular)),
|
||||
sTexReflective(std::move(other.sTexReflective)),
|
||||
sTexBump(std::move(other.sTexBump)),
|
||||
sTexEmissive(std::move(other.sTexEmissive)),
|
||||
sTexShininess(std::move(other.sTexShininess)),
|
||||
mBumpHeight(std::move(other.mBumpHeight)),
|
||||
mEmissive(std::move(other.mEmissive)),
|
||||
sTexAmbient(std::move(other.sTexAmbient)),
|
||||
mTwoSided(std::move(other.mTwoSided)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
Material &operator=(Material &&other) AI_NO_EXCEPT {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
|
@ -444,9 +517,9 @@ struct Material
|
|||
return *this;
|
||||
}
|
||||
|
||||
|
||||
virtual ~Material() {}
|
||||
|
||||
virtual ~Material() {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Name of the material
|
||||
std::string mName;
|
||||
|
@ -491,18 +564,15 @@ struct Material
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent a 3ds file mesh */
|
||||
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
||||
{
|
||||
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face> {
|
||||
//! Default constructor has been deleted
|
||||
Mesh() = delete;
|
||||
|
||||
//! Constructor with explicit name
|
||||
explicit Mesh(const std::string &name)
|
||||
: mName(name)
|
||||
{
|
||||
explicit Mesh(const std::string &name) :
|
||||
mName(name) {
|
||||
}
|
||||
|
||||
|
||||
//! Name of the mesh
|
||||
std::string mName;
|
||||
|
||||
|
@ -519,62 +589,48 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
|||
// ---------------------------------------------------------------------------
|
||||
/** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the
|
||||
C-API, so it would be difficult to make them a template. */
|
||||
struct aiFloatKey
|
||||
{
|
||||
struct aiFloatKey {
|
||||
double mTime; ///< The time of this key
|
||||
ai_real mValue; ///< The value of this key
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// time is not compared
|
||||
bool operator == (const aiFloatKey& o) const
|
||||
{return o.mValue == this->mValue;}
|
||||
bool operator==(const aiFloatKey &o) const { return o.mValue == this->mValue; }
|
||||
|
||||
bool operator != (const aiFloatKey& o) const
|
||||
{return o.mValue != this->mValue;}
|
||||
bool operator!=(const aiFloatKey &o) const { return o.mValue != this->mValue; }
|
||||
|
||||
// Only time is compared. This operator is defined
|
||||
// for use with std::sort
|
||||
bool operator < (const aiFloatKey& o) const
|
||||
{return mTime < o.mTime;}
|
||||
bool operator<(const aiFloatKey &o) const { return mTime < o.mTime; }
|
||||
|
||||
bool operator > (const aiFloatKey& o) const
|
||||
{return mTime > o.mTime;}
|
||||
bool operator>(const aiFloatKey &o) const { return mTime > o.mTime; }
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent a 3ds file node */
|
||||
struct Node
|
||||
{
|
||||
struct Node {
|
||||
Node() = delete;
|
||||
|
||||
explicit Node(const std::string &name)
|
||||
: mParent(NULL)
|
||||
, mName(name)
|
||||
, mInstanceNumber(0)
|
||||
, mHierarchyPos (0)
|
||||
, mHierarchyIndex (0)
|
||||
, mInstanceCount (1)
|
||||
{
|
||||
aRotationKeys.reserve (20);
|
||||
aPositionKeys.reserve (20);
|
||||
aScalingKeys.reserve (20);
|
||||
explicit Node(const std::string &name) :
|
||||
mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) {
|
||||
aRotationKeys.reserve(20);
|
||||
aPositionKeys.reserve(20);
|
||||
aScalingKeys.reserve(20);
|
||||
}
|
||||
|
||||
|
||||
~Node()
|
||||
{
|
||||
for (unsigned int i = 0; i < mChildren.size();++i)
|
||||
~Node() {
|
||||
for (unsigned int i = 0; i < mChildren.size(); ++i)
|
||||
delete mChildren[i];
|
||||
}
|
||||
|
||||
//! Pointer to the parent node
|
||||
Node* mParent;
|
||||
Node *mParent;
|
||||
|
||||
//! Holds all child nodes
|
||||
std::vector<Node*> mChildren;
|
||||
std::vector<Node *> mChildren;
|
||||
|
||||
//! Name of the node
|
||||
std::string mName;
|
||||
|
@ -600,13 +656,12 @@ struct Node
|
|||
//! Scaling keys loaded from the file
|
||||
std::vector<aiVectorKey> aScalingKeys;
|
||||
|
||||
|
||||
// For target lights (spot lights and directional lights):
|
||||
// The position of the target
|
||||
std::vector< aiVectorKey > aTargetPositionKeys;
|
||||
std::vector<aiVectorKey> aTargetPositionKeys;
|
||||
|
||||
// For cameras: the camera roll angle
|
||||
std::vector< aiFloatKey > aCameraRollKeys;
|
||||
std::vector<aiFloatKey> aCameraRollKeys;
|
||||
|
||||
//! Pivot position loaded from the file
|
||||
aiVector3D vPivot;
|
||||
|
@ -616,8 +671,7 @@ struct Node
|
|||
|
||||
//! Add a child node, setup the right parent node for it
|
||||
//! \param pc Node to be 'adopted'
|
||||
inline Node& push_back(Node* pc)
|
||||
{
|
||||
inline Node &push_back(Node *pc) {
|
||||
mChildren.push_back(pc);
|
||||
pc->mParent = this;
|
||||
return *this;
|
||||
|
@ -625,8 +679,7 @@ struct Node
|
|||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure analogue to aiScene */
|
||||
struct Scene
|
||||
{
|
||||
struct Scene {
|
||||
//! List of all materials loaded
|
||||
//! NOTE: 3ds references materials globally
|
||||
std::vector<Material> mMaterials;
|
||||
|
@ -635,17 +688,16 @@ struct Scene
|
|||
std::vector<Mesh> mMeshes;
|
||||
|
||||
//! List of all cameras loaded
|
||||
std::vector<aiCamera*> mCameras;
|
||||
std::vector<aiCamera *> mCameras;
|
||||
|
||||
//! List of all lights loaded
|
||||
std::vector<aiLight*> mLights;
|
||||
std::vector<aiLight *> mLights;
|
||||
|
||||
//! Pointer to the root node of the scene
|
||||
// --- moved to main class
|
||||
// Node* pcRootNode;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace D3DS
|
||||
} // 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
|
||||
*/
|
||||
class Discreet3DSImporter : public BaseImporter
|
||||
{
|
||||
class Discreet3DSImporter : public BaseImporter {
|
||||
public:
|
||||
|
||||
Discreet3DSImporter();
|
||||
~Discreet3DSImporter();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
|
@ -44,81 +44,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "D3MFExporter.h"
|
||||
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include "3MFXmlTags.h"
|
||||
#include "D3MFOpcPackage.h"
|
||||
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <zip/zip.h>
|
||||
#include <zip/zip.h>
|
||||
#else
|
||||
# include <contrib/zip/src/zip.h>
|
||||
#include <contrib/zip/src/zip.h>
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) {
|
||||
if ( nullptr == pIOSystem ) {
|
||||
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
|
||||
void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
|
||||
if (nullptr == pIOSystem) {
|
||||
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
|
||||
}
|
||||
D3MF::D3MFExporter myExporter( pFile, pScene );
|
||||
if ( myExporter.validate() ) {
|
||||
if ( pIOSystem->Exists( pFile ) ) {
|
||||
if ( !pIOSystem->DeleteFile( pFile ) ) {
|
||||
throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) );
|
||||
D3MF::D3MFExporter myExporter(pFile, pScene);
|
||||
if (myExporter.validate()) {
|
||||
if (pIOSystem->Exists(pFile)) {
|
||||
if (!pIOSystem->DeleteFile(pFile)) {
|
||||
throw DeadlyExportError("File exists, cannot override : " + std::string(pFile));
|
||||
}
|
||||
}
|
||||
bool ok = myExporter.exportArchive(pFile);
|
||||
if ( !ok ) {
|
||||
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
|
||||
if (!ok) {
|
||||
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace D3MF {
|
||||
|
||||
D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
|
||||
: mArchiveName( pFile )
|
||||
, m_zipArchive( nullptr )
|
||||
, mScene( pScene )
|
||||
, mModelOutput()
|
||||
, mRelOutput()
|
||||
, mContentOutput()
|
||||
, mBuildItems()
|
||||
, mRelations() {
|
||||
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
|
||||
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
|
||||
// empty
|
||||
}
|
||||
|
||||
D3MFExporter::~D3MFExporter() {
|
||||
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
||||
delete mRelations[ i ];
|
||||
for (size_t i = 0; i < mRelations.size(); ++i) {
|
||||
delete mRelations[i];
|
||||
}
|
||||
mRelations.clear();
|
||||
}
|
||||
|
||||
bool D3MFExporter::validate() {
|
||||
if ( mArchiveName.empty() ) {
|
||||
if (mArchiveName.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( nullptr == mScene ) {
|
||||
if (nullptr == mScene) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3MFExporter::exportArchive( const char *file ) {
|
||||
bool ok( true );
|
||||
bool D3MFExporter::exportArchive(const char *file) {
|
||||
bool ok(true);
|
||||
|
||||
m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' );
|
||||
if ( nullptr == m_zipArchive ) {
|
||||
m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
if (nullptr == m_zipArchive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -126,7 +119,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
|
|||
ok |= export3DModel();
|
||||
ok |= exportRelations();
|
||||
|
||||
zip_close( m_zipArchive );
|
||||
zip_close(m_zipArchive);
|
||||
m_zipArchive = nullptr;
|
||||
|
||||
return ok;
|
||||
|
@ -145,7 +138,7 @@ bool D3MFExporter::exportContentTypes() {
|
|||
mContentOutput << std::endl;
|
||||
mContentOutput << "</Types>";
|
||||
mContentOutput << std::endl;
|
||||
exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
|
||||
exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -157,20 +150,20 @@ bool D3MFExporter::exportRelations() {
|
|||
mRelOutput << std::endl;
|
||||
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
||||
|
||||
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
||||
if ( mRelations[ i ]->target[ 0 ] == '/' ) {
|
||||
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
|
||||
for (size_t i = 0; i < mRelations.size(); ++i) {
|
||||
if (mRelations[i]->target[0] == '/') {
|
||||
mRelOutput << "<Relationship Target=\"" << mRelations[i]->target << "\" ";
|
||||
} else {
|
||||
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
|
||||
mRelOutput << "<Relationship Target=\"/" << mRelations[i]->target << "\" ";
|
||||
}
|
||||
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
|
||||
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
|
||||
mRelOutput << "Type=\"" << mRelations[i]->type << "\" />";
|
||||
mRelOutput << std::endl;
|
||||
}
|
||||
mRelOutput << "</Relationships>";
|
||||
mRelOutput << std::endl;
|
||||
|
||||
writeRelInfoToFile( "_rels", ".rels" );
|
||||
writeRelInfoToFile("_rels", ".rels");
|
||||
mRelOutput.flush();
|
||||
|
||||
return true;
|
||||
|
@ -181,7 +174,7 @@ bool D3MFExporter::export3DModel() {
|
|||
|
||||
writeHeader();
|
||||
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;
|
||||
mModelOutput << "<" << XmlTag::resources << ">";
|
||||
mModelOutput << std::endl;
|
||||
|
@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
|
|||
|
||||
writeObjects();
|
||||
|
||||
|
||||
mModelOutput << "</" << XmlTag::resources << ">";
|
||||
mModelOutput << std::endl;
|
||||
writeBuild();
|
||||
|
@ -203,36 +195,36 @@ bool D3MFExporter::export3DModel() {
|
|||
info->id = "rel0";
|
||||
info->target = "/3D/3DModel.model";
|
||||
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
|
||||
mRelations.push_back( info );
|
||||
mRelations.push_back(info);
|
||||
|
||||
writeModelToArchive( "3D", "3DModel.model" );
|
||||
writeModelToArchive("3D", "3DModel.model");
|
||||
mModelOutput.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3MFExporter::writeHeader() {
|
||||
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
|
||||
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
|
||||
void D3MFExporter::writeMetaData() {
|
||||
if ( nullptr == mScene->mMetaData ) {
|
||||
if (nullptr == mScene->mMetaData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
|
||||
if ( 0 == numMetaEntries ) {
|
||||
const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties);
|
||||
if (0 == numMetaEntries) {
|
||||
return;
|
||||
}
|
||||
|
||||
const aiString *key = nullptr;
|
||||
const aiMetadataEntry *entry(nullptr);
|
||||
for ( size_t i = 0; i < numMetaEntries; ++i ) {
|
||||
mScene->mMetaData->Get( i, key, entry );
|
||||
std::string k( key->C_Str() );
|
||||
for (size_t i = 0; i < numMetaEntries; ++i) {
|
||||
mScene->mMetaData->Get(i, key, entry);
|
||||
std::string k(key->C_Str());
|
||||
aiString value;
|
||||
mScene->mMetaData->Get( k, value );
|
||||
mScene->mMetaData->Get(k, value);
|
||||
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
|
||||
mModelOutput << value.C_Str();
|
||||
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
|
||||
|
@ -241,103 +233,114 @@ void D3MFExporter::writeMetaData() {
|
|||
|
||||
void D3MFExporter::writeBaseMaterials() {
|
||||
mModelOutput << "<basematerials id=\"1\">\n";
|
||||
std::string strName, hexDiffuseColor , tmp;
|
||||
for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
|
||||
aiMaterial *mat = mScene->mMaterials[ i ];
|
||||
std::string strName, hexDiffuseColor, tmp;
|
||||
for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
|
||||
aiMaterial *mat = mScene->mMaterials[i];
|
||||
aiString name;
|
||||
if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
|
||||
strName = "basemat_" + to_string( i );
|
||||
if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
|
||||
strName = "basemat_" + to_string(i);
|
||||
} else {
|
||||
strName = name.C_Str();
|
||||
}
|
||||
aiColor4D color;
|
||||
if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
|
||||
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
|
||||
hexDiffuseColor.clear();
|
||||
tmp.clear();
|
||||
hexDiffuseColor = "#";
|
||||
// rgbs %
|
||||
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
|
||||
|
||||
tmp = DecimalToHexa( color.r );
|
||||
hexDiffuseColor = Rgba2Hex(
|
||||
(int)((ai_real)color.r) * 255,
|
||||
(int)((ai_real)color.g) * 255,
|
||||
(int)((ai_real)color.b) * 255,
|
||||
(int)((ai_real)color.a) * 255,
|
||||
true);
|
||||
|
||||
} else {
|
||||
hexDiffuseColor = "#";
|
||||
tmp = DecimalToHexa((ai_real)color.r);
|
||||
hexDiffuseColor += tmp;
|
||||
tmp = DecimalToHexa( color.g );
|
||||
tmp = DecimalToHexa((ai_real)color.g);
|
||||
hexDiffuseColor += tmp;
|
||||
tmp = DecimalToHexa( color.b );
|
||||
tmp = DecimalToHexa((ai_real)color.b);
|
||||
hexDiffuseColor += tmp;
|
||||
tmp = DecimalToHexa( color.a );
|
||||
tmp = DecimalToHexa((ai_real)color.a);
|
||||
hexDiffuseColor += tmp;
|
||||
}
|
||||
} else {
|
||||
hexDiffuseColor = "#FFFFFFFF";
|
||||
}
|
||||
|
||||
mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
|
||||
mModelOutput << "<base name=\"" + strName + "\" " + " displaycolor=\"" + hexDiffuseColor + "\" />\n";
|
||||
}
|
||||
mModelOutput << "</basematerials>\n";
|
||||
}
|
||||
|
||||
void D3MFExporter::writeObjects() {
|
||||
if ( nullptr == mScene->mRootNode ) {
|
||||
if (nullptr == mScene->mRootNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
aiNode *root = mScene->mRootNode;
|
||||
for ( unsigned int i = 0; i < root->mNumChildren; ++i ) {
|
||||
aiNode *currentNode( root->mChildren[ i ] );
|
||||
if ( nullptr == currentNode ) {
|
||||
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||
aiNode *currentNode(root->mChildren[i]);
|
||||
if (nullptr == currentNode) {
|
||||
continue;
|
||||
}
|
||||
mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
|
||||
mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
|
||||
mModelOutput << std::endl;
|
||||
for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) {
|
||||
aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ];
|
||||
if ( nullptr == currentMesh ) {
|
||||
for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
|
||||
aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
|
||||
if (nullptr == currentMesh) {
|
||||
continue;
|
||||
}
|
||||
writeMesh( currentMesh );
|
||||
writeMesh(currentMesh);
|
||||
}
|
||||
mBuildItems.push_back( i );
|
||||
mBuildItems.push_back(i);
|
||||
|
||||
mModelOutput << "</" << XmlTag::object << ">";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void D3MFExporter::writeMesh( aiMesh *mesh ) {
|
||||
if ( nullptr == mesh ) {
|
||||
void D3MFExporter::writeMesh(aiMesh *mesh) {
|
||||
if (nullptr == mesh) {
|
||||
return;
|
||||
}
|
||||
|
||||
mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
|
||||
mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
|
||||
for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) {
|
||||
writeVertex( mesh->mVertices[ i ] );
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
writeVertex(mesh->mVertices[i]);
|
||||
}
|
||||
mModelOutput << "</" << 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;
|
||||
}
|
||||
|
||||
void D3MFExporter::writeVertex( const aiVector3D &pos ) {
|
||||
void D3MFExporter::writeVertex(const aiVector3D &pos) {
|
||||
mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
|
||||
void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
|
||||
if ( nullptr == mesh ) {
|
||||
void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
|
||||
if (nullptr == mesh) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !mesh->HasFaces() ) {
|
||||
if (!mesh->HasFaces()) {
|
||||
return;
|
||||
}
|
||||
mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
|
||||
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
|
||||
aiFace ¤tFace = mesh->mFaces[ i ];
|
||||
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
|
||||
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
|
||||
<< "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
aiFace ¤tFace = mesh->mFaces[i];
|
||||
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
|
||||
<< currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
|
||||
<< "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
mModelOutput << "</" << XmlTag::triangles << ">";
|
||||
|
@ -347,54 +350,53 @@ void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
|
|||
void D3MFExporter::writeBuild() {
|
||||
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
|
||||
|
||||
for ( size_t i = 0; i < mBuildItems.size(); ++i ) {
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
|
||||
for (size_t i = 0; i < mBuildItems.size(); ++i) {
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
mModelOutput << "</" << XmlTag::build << ">";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
|
||||
void D3MFExporter::exportContentTyp( const std::string &filename ) {
|
||||
if ( nullptr == m_zipArchive ) {
|
||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
||||
void D3MFExporter::exportContentTyp(const std::string &filename) {
|
||||
if (nullptr == m_zipArchive) {
|
||||
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||
}
|
||||
const std::string entry = filename;
|
||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
||||
zip_entry_open(m_zipArchive, entry.c_str());
|
||||
|
||||
const std::string &exportTxt( mContentOutput.str() );
|
||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
||||
const std::string &exportTxt(mContentOutput.str());
|
||||
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||
|
||||
zip_entry_close( m_zipArchive );
|
||||
zip_entry_close(m_zipArchive);
|
||||
}
|
||||
|
||||
void D3MFExporter::writeModelToArchive( const std::string &folder, const std::string &modelName ) {
|
||||
if ( nullptr == m_zipArchive ) {
|
||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
||||
void D3MFExporter::writeModelToArchive(const std::string &folder, const std::string &modelName) {
|
||||
if (nullptr == m_zipArchive) {
|
||||
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||
}
|
||||
const std::string entry = folder + "/" + modelName;
|
||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
||||
zip_entry_open(m_zipArchive, entry.c_str());
|
||||
|
||||
const std::string &exportTxt( mModelOutput.str() );
|
||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
||||
const std::string &exportTxt(mModelOutput.str());
|
||||
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||
|
||||
zip_entry_close( m_zipArchive );
|
||||
zip_entry_close(m_zipArchive);
|
||||
}
|
||||
|
||||
void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) {
|
||||
if ( nullptr == m_zipArchive ) {
|
||||
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
|
||||
void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) {
|
||||
if (nullptr == m_zipArchive) {
|
||||
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
|
||||
}
|
||||
const std::string entry = folder + "/" + relName;
|
||||
zip_entry_open( m_zipArchive, entry.c_str() );
|
||||
zip_entry_open(m_zipArchive, entry.c_str());
|
||||
|
||||
const std::string &exportTxt( mRelOutput.str() );
|
||||
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
|
||||
const std::string &exportTxt(mRelOutput.str());
|
||||
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
|
||||
|
||||
zip_entry_close( m_zipArchive );
|
||||
zip_entry_close(m_zipArchive);
|
||||
}
|
||||
|
||||
|
||||
} // Namespace D3MF
|
||||
} // Namespace Assimp
|
||||
|
|
@ -44,24 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "D3MFImporter.h"
|
||||
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/ZipArchiveIOSystem.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "D3MFOpcPackage.h"
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include "3MFXmlTags.h"
|
||||
#include "D3MFOpcPackage.h"
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
|
@ -70,15 +70,15 @@ namespace D3MF {
|
|||
|
||||
class XmlSerializer {
|
||||
public:
|
||||
using MatArray = std::vector<aiMaterial*>;
|
||||
using MatArray = std::vector<aiMaterial *>;
|
||||
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
|
||||
|
||||
XmlSerializer(XmlReader* xmlReader)
|
||||
: mMeshes()
|
||||
, mMatArray()
|
||||
, mActiveMatGroup( 99999999 )
|
||||
, mMatId2MatArray()
|
||||
, xmlReader(xmlReader){
|
||||
XmlSerializer(XmlReader *xmlReader) :
|
||||
mMeshes(),
|
||||
mMatArray(),
|
||||
mActiveMatGroup(99999999),
|
||||
mMatId2MatArray(),
|
||||
xmlReader(xmlReader) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -86,74 +86,74 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
void ImportXml(aiScene* scene) {
|
||||
if ( nullptr == scene ) {
|
||||
void ImportXml(aiScene *scene) {
|
||||
if (nullptr == scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
scene->mRootNode = new aiNode();
|
||||
std::vector<aiNode*> children;
|
||||
std::vector<aiNode *> children;
|
||||
|
||||
std::string nodeName;
|
||||
while(ReadToEndElement(D3MF::XmlTag::model)) {
|
||||
while (ReadToEndElement(D3MF::XmlTag::model)) {
|
||||
nodeName = xmlReader->getNodeName();
|
||||
if( nodeName == D3MF::XmlTag::object) {
|
||||
if (nodeName == D3MF::XmlTag::object) {
|
||||
children.push_back(ReadObject(scene));
|
||||
} else if( nodeName == D3MF::XmlTag::build) {
|
||||
} else if (nodeName == D3MF::XmlTag::build) {
|
||||
//
|
||||
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
|
||||
} else if (nodeName == D3MF::XmlTag::basematerials) {
|
||||
ReadBaseMaterials();
|
||||
} else if ( nodeName == D3MF::XmlTag::meta ) {
|
||||
} else if (nodeName == D3MF::XmlTag::meta) {
|
||||
ReadMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
if ( scene->mRootNode->mName.length == 0 ) {
|
||||
scene->mRootNode->mName.Set( "3MF" );
|
||||
if (scene->mRootNode->mName.length == 0) {
|
||||
scene->mRootNode->mName.Set("3MF");
|
||||
}
|
||||
|
||||
// import the metadata
|
||||
if ( !mMetaData.empty() ) {
|
||||
const size_t numMeta( mMetaData.size() );
|
||||
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>( numMeta ) );
|
||||
for ( size_t i = 0; i < numMeta; ++i ) {
|
||||
aiString val( mMetaData[ i ].value );
|
||||
scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
|
||||
if (!mMetaData.empty()) {
|
||||
const size_t numMeta(mMetaData.size());
|
||||
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
|
||||
for (size_t i = 0; i < numMeta; ++i) {
|
||||
aiString val(mMetaData[i].value);
|
||||
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
|
||||
}
|
||||
}
|
||||
|
||||
// import the meshes
|
||||
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
|
||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
|
||||
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
|
||||
scene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
|
||||
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
|
||||
std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes);
|
||||
|
||||
// import the materials
|
||||
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
|
||||
if ( 0 != scene->mNumMaterials ) {
|
||||
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
|
||||
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
|
||||
scene->mNumMaterials = static_cast<unsigned int>(mMatArray.size());
|
||||
if (0 != scene->mNumMaterials) {
|
||||
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
|
||||
std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
|
||||
}
|
||||
|
||||
// create the scenegraph
|
||||
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
||||
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
|
||||
scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
|
||||
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
||||
}
|
||||
|
||||
private:
|
||||
aiNode* ReadObject(aiScene* scene) {
|
||||
aiNode *ReadObject(aiScene *scene) {
|
||||
std::unique_ptr<aiNode> node(new aiNode());
|
||||
|
||||
std::vector<unsigned long> meshIds;
|
||||
|
||||
const char *attrib( nullptr );
|
||||
const char *attrib(nullptr);
|
||||
std::string name, type;
|
||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
|
||||
if ( nullptr != attrib ) {
|
||||
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
|
||||
if (nullptr != attrib) {
|
||||
name = attrib;
|
||||
}
|
||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
|
||||
if ( nullptr != attrib ) {
|
||||
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
|
||||
if (nullptr != attrib) {
|
||||
type = attrib;
|
||||
}
|
||||
|
||||
|
@ -162,8 +162,8 @@ private:
|
|||
|
||||
size_t meshIdx = mMeshes.size();
|
||||
|
||||
while(ReadToEndElement(D3MF::XmlTag::object)) {
|
||||
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
|
||||
while (ReadToEndElement(D3MF::XmlTag::object)) {
|
||||
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
|
||||
auto mesh = ReadMesh();
|
||||
|
||||
mesh->mName.Set(name);
|
||||
|
@ -183,11 +183,11 @@ private:
|
|||
}
|
||||
|
||||
aiMesh *ReadMesh() {
|
||||
aiMesh* mesh = new aiMesh();
|
||||
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
|
||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
|
||||
aiMesh *mesh = new aiMesh();
|
||||
while (ReadToEndElement(D3MF::XmlTag::mesh)) {
|
||||
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
|
||||
ImportVertices(mesh);
|
||||
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
|
||||
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
|
||||
ImportTriangles(mesh);
|
||||
}
|
||||
}
|
||||
|
@ -196,24 +196,24 @@ private:
|
|||
}
|
||||
|
||||
void ReadMetadata() {
|
||||
const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
|
||||
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
|
||||
xmlReader->read();
|
||||
const std::string value = xmlReader->getNodeData();
|
||||
|
||||
if ( name.empty() ) {
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaEntry entry;
|
||||
entry.name = name;
|
||||
entry.value = value;
|
||||
mMetaData.push_back( entry );
|
||||
mMetaData.push_back(entry);
|
||||
}
|
||||
|
||||
void ImportVertices(aiMesh* mesh) {
|
||||
void ImportVertices(aiMesh *mesh) {
|
||||
std::vector<aiVector3D> vertices;
|
||||
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
|
||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
|
||||
while (ReadToEndElement(D3MF::XmlTag::vertices)) {
|
||||
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
|
||||
vertices.push_back(ReadVertex());
|
||||
}
|
||||
}
|
||||
|
@ -233,16 +233,16 @@ private:
|
|||
return vertex;
|
||||
}
|
||||
|
||||
void ImportTriangles(aiMesh* mesh) {
|
||||
void ImportTriangles(aiMesh *mesh) {
|
||||
std::vector<aiFace> faces;
|
||||
|
||||
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
|
||||
const std::string nodeName( xmlReader->getNodeName() );
|
||||
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
|
||||
while (ReadToEndElement(D3MF::XmlTag::triangles)) {
|
||||
const std::string nodeName(xmlReader->getNodeName());
|
||||
if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
|
||||
faces.push_back(ReadTriangle());
|
||||
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
|
||||
if ( nullptr != pidToken ) {
|
||||
int matIdx( std::atoi( pidToken ) );
|
||||
const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
|
||||
if (nullptr != pidToken) {
|
||||
int matIdx(std::atoi(pidToken));
|
||||
mesh->mMaterialIndex = matIdx;
|
||||
}
|
||||
}
|
||||
|
@ -269,117 +269,115 @@ private:
|
|||
|
||||
void ReadBaseMaterials() {
|
||||
std::vector<unsigned int> MatIdArray;
|
||||
const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
|
||||
if ( nullptr != baseMaterialId ) {
|
||||
unsigned int id = std::atoi( baseMaterialId );
|
||||
const size_t newMatIdx( mMatArray.size() );
|
||||
if ( id != mActiveMatGroup ) {
|
||||
const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str()));
|
||||
if (nullptr != baseMaterialId) {
|
||||
unsigned int id = std::atoi(baseMaterialId);
|
||||
const size_t newMatIdx(mMatArray.size());
|
||||
if (id != mActiveMatGroup) {
|
||||
mActiveMatGroup = id;
|
||||
MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
|
||||
if ( mMatId2MatArray.end() == it ) {
|
||||
MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
|
||||
if (mMatId2MatArray.end() == it) {
|
||||
MatIdArray.clear();
|
||||
mMatId2MatArray[ id ] = MatIdArray;
|
||||
mMatId2MatArray[id] = MatIdArray;
|
||||
} else {
|
||||
MatIdArray = it->second;
|
||||
}
|
||||
}
|
||||
MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
|
||||
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
|
||||
MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
|
||||
mMatId2MatArray[mActiveMatGroup] = MatIdArray;
|
||||
}
|
||||
|
||||
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
|
||||
mMatArray.push_back( readMaterialDef() );
|
||||
while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
|
||||
mMatArray.push_back(readMaterialDef());
|
||||
}
|
||||
}
|
||||
|
||||
bool parseColor( const char *color, aiColor4D &diffuse ) {
|
||||
if ( nullptr == color ) {
|
||||
bool parseColor(const char *color, aiColor4D &diffuse) {
|
||||
if (nullptr == color) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
|
||||
const size_t len( strlen( color ) );
|
||||
if ( 9 != len && 7 != len) {
|
||||
const size_t len(strlen(color));
|
||||
if (9 != len && 7 != len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *buf( color );
|
||||
if ( '#' != *buf ) {
|
||||
const char *buf(color);
|
||||
if ('#' != *buf) {
|
||||
return false;
|
||||
}
|
||||
++buf;
|
||||
char comp[ 3 ] = { 0,0,'\0' };
|
||||
char comp[3] = { 0, 0, '\0' };
|
||||
|
||||
comp[ 0 ] = *buf;
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[ 1 ] = *buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.r = static_cast<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;
|
||||
comp[ 1 ] = *buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
||||
diffuse.b = static_cast<ai_real>(strtol(comp, NULL, 16)) / ai_real(255.0);
|
||||
|
||||
comp[ 0 ] = *buf;
|
||||
++buf;
|
||||
comp[ 1 ] = *buf;
|
||||
++buf;
|
||||
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
||||
|
||||
if(7 == len)
|
||||
if (7 == len)
|
||||
return true;
|
||||
comp[ 0 ] = *buf;
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[ 1 ] = *buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
||||
diffuse.a = static_cast<ai_real>(strtol(comp, NULL, 16)) / ai_real(255.0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void assignDiffuseColor( aiMaterial *mat ) {
|
||||
const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
|
||||
void assignDiffuseColor(aiMaterial *mat) {
|
||||
const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
|
||||
aiColor4D diffuse;
|
||||
if ( parseColor( color, diffuse ) ) {
|
||||
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
|
||||
if (parseColor(color, diffuse)) {
|
||||
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
}
|
||||
aiMaterial *readMaterialDef() {
|
||||
aiMaterial *mat( nullptr );
|
||||
const char *name( nullptr );
|
||||
const std::string nodeName( xmlReader->getNodeName() );
|
||||
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
|
||||
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
|
||||
aiMaterial *mat(nullptr);
|
||||
const char *name(nullptr);
|
||||
const std::string nodeName(xmlReader->getNodeName());
|
||||
if (nodeName == D3MF::XmlTag::basematerials_base) {
|
||||
name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str());
|
||||
std::string stdMatName;
|
||||
aiString matName;
|
||||
std::string strId( to_string( mActiveMatGroup ) );
|
||||
std::string strId(to_string(mActiveMatGroup));
|
||||
stdMatName += "id";
|
||||
stdMatName += strId;
|
||||
stdMatName += "_";
|
||||
if ( nullptr != name ) {
|
||||
stdMatName += std::string( name );
|
||||
if (nullptr != name) {
|
||||
stdMatName += std::string(name);
|
||||
} else {
|
||||
stdMatName += "basemat";
|
||||
}
|
||||
matName.Set( stdMatName );
|
||||
matName.Set(stdMatName);
|
||||
|
||||
mat = new aiMaterial;
|
||||
mat->AddProperty( &matName, AI_MATKEY_NAME );
|
||||
mat->AddProperty(&matName, AI_MATKEY_NAME);
|
||||
|
||||
assignDiffuseColor( mat );
|
||||
assignDiffuseColor(mat);
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
private:
|
||||
bool ReadToStartElement(const std::string& startTag) {
|
||||
while(xmlReader->read()) {
|
||||
const std::string &nodeName( xmlReader->getNodeName() );
|
||||
bool ReadToStartElement(const std::string &startTag) {
|
||||
while (xmlReader->read()) {
|
||||
const std::string &nodeName(xmlReader->getNodeName());
|
||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
|
||||
return true;
|
||||
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
|
||||
|
@ -390,9 +388,9 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ReadToEndElement(const std::string& closeTag) {
|
||||
while(xmlReader->read()) {
|
||||
const std::string &nodeName( xmlReader->getNodeName() );
|
||||
bool ReadToEndElement(const std::string &closeTag) {
|
||||
while (xmlReader->read()) {
|
||||
const std::string &nodeName(xmlReader->getNodeName());
|
||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
||||
return true;
|
||||
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
|
||||
|
@ -410,11 +408,11 @@ private:
|
|||
std::string value;
|
||||
};
|
||||
std::vector<MetaEntry> mMetaData;
|
||||
std::vector<aiMesh*> mMeshes;
|
||||
std::vector<aiMesh *> mMeshes;
|
||||
MatArray mMatArray;
|
||||
unsigned int mActiveMatGroup;
|
||||
MatId2MatArray mMatId2MatArray;
|
||||
XmlReader* xmlReader;
|
||||
XmlReader *xmlReader;
|
||||
};
|
||||
|
||||
} //namespace D3MF
|
||||
|
@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
|
|||
"3mf"
|
||||
};
|
||||
|
||||
D3MFImporter::D3MFImporter()
|
||||
: BaseImporter() {
|
||||
D3MFImporter::D3MFImporter() :
|
||||
BaseImporter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -442,17 +440,17 @@ D3MFImporter::~D3MFImporter() {
|
|||
}
|
||||
|
||||
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string extension( GetExtension( filename ) );
|
||||
if(extension == desc.mFileExtensions ) {
|
||||
const std::string extension(GetExtension(filename));
|
||||
if (extension == desc.mFileExtensions) {
|
||||
return true;
|
||||
} else if ( !extension.length() || checkSig ) {
|
||||
if ( nullptr == pIOHandler ) {
|
||||
} else if (!extension.length() || checkSig) {
|
||||
if (nullptr == pIOHandler) {
|
||||
return false;
|
||||
}
|
||||
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
|
||||
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
|
||||
return false;
|
||||
}
|
||||
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
|
||||
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
||||
return opcPackage.validate();
|
||||
}
|
||||
|
||||
|
@ -467,7 +465,7 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
|
|||
return &desc;
|
||||
}
|
||||
|
||||
void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
|
||||
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
||||
|
||||
std::unique_ptr<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);
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -56,29 +56,20 @@ struct aiMesh;
|
|||
struct aiMaterial;
|
||||
struct aiLight;
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** AC3D (*.ac) importer class
|
||||
*/
|
||||
class AC3DImporter : public BaseImporter
|
||||
{
|
||||
class AC3DImporter : public BaseImporter {
|
||||
public:
|
||||
AC3DImporter();
|
||||
~AC3DImporter();
|
||||
|
||||
|
||||
|
||||
// Represents an AC3D material
|
||||
struct Material
|
||||
{
|
||||
Material()
|
||||
: rgb (0.6f,0.6f,0.6f)
|
||||
, spec (1.f,1.f,1.f)
|
||||
, shin (0.f)
|
||||
, trans (0.f)
|
||||
{}
|
||||
struct Material {
|
||||
Material() :
|
||||
rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {}
|
||||
|
||||
// base color of the material
|
||||
aiColor3D rgb;
|
||||
|
@ -103,41 +94,23 @@ public:
|
|||
};
|
||||
|
||||
// Represents an AC3D surface
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: mat (0)
|
||||
, flags (0)
|
||||
{}
|
||||
struct Surface {
|
||||
Surface() :
|
||||
mat(0), flags(0) {}
|
||||
|
||||
unsigned int mat,flags;
|
||||
unsigned int mat, flags;
|
||||
|
||||
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
|
||||
std::vector< SurfaceEntry > entries;
|
||||
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
|
||||
std::vector<SurfaceEntry> entries;
|
||||
};
|
||||
|
||||
// Represents an AC3D object
|
||||
struct Object
|
||||
{
|
||||
Object()
|
||||
: type (World)
|
||||
, name( "" )
|
||||
, children()
|
||||
, texture( "" )
|
||||
, texRepeat( 1.f, 1.f )
|
||||
, texOffset( 0.0f, 0.0f )
|
||||
, rotation()
|
||||
, translation()
|
||||
, vertices()
|
||||
, surfaces()
|
||||
, numRefs (0)
|
||||
, subDiv (0)
|
||||
, crease()
|
||||
{}
|
||||
struct Object {
|
||||
Object() :
|
||||
type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {}
|
||||
|
||||
// Type description
|
||||
enum Type
|
||||
{
|
||||
enum Type {
|
||||
World = 0x0,
|
||||
Poly = 0x1,
|
||||
Group = 0x2,
|
||||
|
@ -179,37 +152,33 @@ public:
|
|||
float crease;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details */
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
const aiImporterDesc *GetInfo() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||
IOSystem *pIOHandler);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer *pImp);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached*/
|
||||
|
@ -220,7 +189,7 @@ private:
|
|||
* load subobjects, the method returns after a 'kids 0' was
|
||||
* encountered.
|
||||
* @objects List of output objects*/
|
||||
void LoadObjectSection(std::vector<Object>& objects);
|
||||
void LoadObjectSection(std::vector<Object> &objects);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert all objects into meshes and nodes.
|
||||
|
@ -229,26 +198,24 @@ private:
|
|||
* @param outMaterials List of output materials
|
||||
* @param materials Material list
|
||||
* @param Scenegraph node for the object */
|
||||
aiNode* ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiMaterial*>& outMaterials,
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent = NULL);
|
||||
aiNode *ConvertObjectSection(Object &object,
|
||||
std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiMaterial *> &outMaterials,
|
||||
const std::vector<Material> &materials,
|
||||
aiNode *parent = nullptr);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
||||
* @param object Current object
|
||||
* @param matSrc Source material description
|
||||
* @param matDest Destination material to be filled */
|
||||
void ConvertMaterial(const Object& object,
|
||||
const Material& matSrc,
|
||||
aiMaterial& matDest);
|
||||
void ConvertMaterial(const Object &object,
|
||||
const Material &matSrc,
|
||||
aiMaterial &matDest);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// points to the next data line
|
||||
const char* buffer;
|
||||
const char *buffer;
|
||||
|
||||
// Configuration option: if enabled, up to two meshes
|
||||
// are generated per material: those faces who have
|
||||
|
@ -265,10 +232,10 @@ private:
|
|||
unsigned int mNumMeshes;
|
||||
|
||||
// current list of light sources
|
||||
std::vector<aiLight*>* mLights;
|
||||
std::vector<aiLight *> *mLights;
|
||||
|
||||
// name counters
|
||||
unsigned int lights, groups, polys, worlds;
|
||||
unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter;
|
||||
};
|
||||
|
||||
} // 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)
|
||||
---------------------------------------------------------------------------
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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>
|
||||
|
||||
// ASE is quite similar to 3ds. We can reuse some structures
|
||||
#include "3DS/3DSLoader.h"
|
||||
#include "AssetLib/3DS/3DSLoader.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace ASE {
|
||||
|
@ -80,7 +80,18 @@ struct Material : public D3DS::Material
|
|||
}
|
||||
|
||||
Material(const Material &other) = default;
|
||||
Material &operator=(const Material &other) = default;
|
||||
|
||||
Material &operator=(const Material &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
avSubMaterials = other.avSubMaterials;
|
||||
pcInstance = other.pcInstance;
|
||||
bNeed = other.bNeed;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
||||
|
@ -94,12 +105,12 @@ struct Material : public D3DS::Material
|
|||
}
|
||||
|
||||
|
||||
Material &operator=(Material &&other) AI_NO_EXCEPT {
|
||||
Material &operator=( Material &&other) AI_NO_EXCEPT {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
D3DS::Material::operator=(std::move(other));
|
||||
//D3DS::Material::operator=(std::move(other));
|
||||
|
||||
avSubMaterials = std::move(other.avSubMaterials);
|
||||
pcInstance = std::move(other.pcInstance);
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -50,19 +48,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||
|
||||
// internal headers
|
||||
#include "Assbin/AssbinLoader.h"
|
||||
#include "AssetLib/Assbin/AssbinLoader.h"
|
||||
#include "Common/assbin_chunks.h"
|
||||
#include <assimp/MemoryIOWrapper.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
||||
# include <zlib.h>
|
||||
#include <zlib.h>
|
||||
#else
|
||||
# include <contrib/zlib/zlib.h>
|
||||
#include <contrib/zlib/zlib.h>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -81,94 +79,97 @@ static const aiImporterDesc desc = {
|
|||
};
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
const aiImporterDesc* AssbinImporter::GetInfo() const {
|
||||
const aiImporterDesc *AssbinImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
|
||||
IOStream * in = pIOHandler->Open(pFile);
|
||||
bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||
IOStream *in = pIOHandler->Open(pFile);
|
||||
if (nullptr == in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char s[32];
|
||||
in->Read( s, sizeof(char), 32 );
|
||||
in->Read(s, sizeof(char), 32);
|
||||
|
||||
pIOHandler->Close(in);
|
||||
|
||||
return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
|
||||
return strncmp(s, "ASSIMP.binary-dump.", 19) == 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
T Read(IOStream * stream) {
|
||||
T Read(IOStream *stream) {
|
||||
T t;
|
||||
size_t res = stream->Read( &t, sizeof(T), 1 );
|
||||
if(res != 1)
|
||||
size_t res = stream->Read(&t, sizeof(T), 1);
|
||||
if (res != 1) {
|
||||
throw DeadlyImportError("Unexpected EOF");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiVector3D Read<aiVector3D>(IOStream * stream) {
|
||||
aiVector3D Read<aiVector3D>(IOStream *stream) {
|
||||
aiVector3D v;
|
||||
v.x = Read<float>(stream);
|
||||
v.y = Read<float>(stream);
|
||||
v.z = Read<float>(stream);
|
||||
v.x = Read<ai_real>(stream);
|
||||
v.y = Read<ai_real>(stream);
|
||||
v.z = Read<ai_real>(stream);
|
||||
return v;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiColor4D Read<aiColor4D>(IOStream * stream) {
|
||||
aiColor4D Read<aiColor4D>(IOStream *stream) {
|
||||
aiColor4D c;
|
||||
c.r = Read<float>(stream);
|
||||
c.g = Read<float>(stream);
|
||||
c.b = Read<float>(stream);
|
||||
c.a = Read<float>(stream);
|
||||
c.r = Read<ai_real>(stream);
|
||||
c.g = Read<ai_real>(stream);
|
||||
c.b = Read<ai_real>(stream);
|
||||
c.a = Read<ai_real>(stream);
|
||||
return c;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiQuaternion Read<aiQuaternion>(IOStream * stream) {
|
||||
aiQuaternion Read<aiQuaternion>(IOStream *stream) {
|
||||
aiQuaternion v;
|
||||
v.w = Read<float>(stream);
|
||||
v.x = Read<float>(stream);
|
||||
v.y = Read<float>(stream);
|
||||
v.z = Read<float>(stream);
|
||||
v.w = Read<ai_real>(stream);
|
||||
v.x = Read<ai_real>(stream);
|
||||
v.y = Read<ai_real>(stream);
|
||||
v.z = Read<ai_real>(stream);
|
||||
return v;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiString Read<aiString>(IOStream * stream) {
|
||||
aiString Read<aiString>(IOStream *stream) {
|
||||
aiString s;
|
||||
stream->Read(&s.length,4,1);
|
||||
if(s.length)
|
||||
stream->Read(s.data,s.length,1);
|
||||
stream->Read(&s.length, 4, 1);
|
||||
if (s.length) {
|
||||
stream->Read(s.data, s.length, 1);
|
||||
}
|
||||
s.data[s.length] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiVertexWeight Read<aiVertexWeight>(IOStream * stream) {
|
||||
aiVertexWeight Read<aiVertexWeight>(IOStream *stream) {
|
||||
aiVertexWeight w;
|
||||
w.mVertexId = Read<unsigned int>(stream);
|
||||
w.mWeight = Read<float>(stream);
|
||||
w.mWeight = Read<ai_real>(stream);
|
||||
return w;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
|
||||
aiMatrix4x4 Read<aiMatrix4x4>(IOStream *stream) {
|
||||
aiMatrix4x4 m;
|
||||
for (unsigned int i = 0; i < 4;++i) {
|
||||
for (unsigned int i2 = 0; i2 < 4;++i2) {
|
||||
m[i][i2] = Read<float>(stream);
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
for (unsigned int i2 = 0; i2 < 4; ++i2) {
|
||||
m[i][i2] = Read<ai_real>(stream);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
|
@ -176,7 +177,7 @@ aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
|
|||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiVectorKey Read<aiVectorKey>(IOStream * stream) {
|
||||
aiVectorKey Read<aiVectorKey>(IOStream *stream) {
|
||||
aiVectorKey v;
|
||||
v.mTime = Read<double>(stream);
|
||||
v.mValue = Read<aiVector3D>(stream);
|
||||
|
@ -185,7 +186,7 @@ aiVectorKey Read<aiVectorKey>(IOStream * stream) {
|
|||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <>
|
||||
aiQuatKey Read<aiQuatKey>(IOStream * stream) {
|
||||
aiQuatKey Read<aiQuatKey>(IOStream *stream) {
|
||||
aiQuatKey v;
|
||||
v.mTime = Read<double>(stream);
|
||||
v.mValue = Read<aiQuaternion>(stream);
|
||||
|
@ -194,27 +195,27 @@ aiQuatKey Read<aiQuatKey>(IOStream * stream) {
|
|||
|
||||
// -----------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
void ReadArray( IOStream *stream, T * out, unsigned int size) {
|
||||
ai_assert( nullptr != stream );
|
||||
ai_assert( nullptr != out );
|
||||
void ReadArray(IOStream *stream, T *out, unsigned int size) {
|
||||
ai_assert(nullptr != stream);
|
||||
ai_assert(nullptr != out);
|
||||
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
out[i] = Read<T>(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
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.
|
||||
stream->Seek( sizeof(T) * n, aiOrigin_CUR );
|
||||
stream->Seek(sizeof(T) * n, aiOrigin_CUR);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* parent ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
|
||||
void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
|
||||
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());
|
||||
|
||||
|
@ -224,12 +225,11 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
|||
unsigned numMeshes = Read<unsigned int>(stream);
|
||||
unsigned int nb_metadata = Read<unsigned int>(stream);
|
||||
|
||||
if(parent) {
|
||||
if (parent) {
|
||||
node->mParent = parent;
|
||||
}
|
||||
|
||||
if (numMeshes)
|
||||
{
|
||||
if (numMeshes) {
|
||||
node->mMeshes = new unsigned int[numMeshes];
|
||||
for (unsigned int i = 0; i < numMeshes; ++i) {
|
||||
node->mMeshes[i] = Read<unsigned int>(stream);
|
||||
|
@ -238,19 +238,19 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
|||
}
|
||||
|
||||
if (numChildren) {
|
||||
node->mChildren = new aiNode*[numChildren];
|
||||
node->mChildren = new aiNode *[numChildren];
|
||||
for (unsigned int i = 0; i < numChildren; ++i) {
|
||||
ReadBinaryNode( stream, &node->mChildren[i], node.get() );
|
||||
ReadBinaryNode(stream, &node->mChildren[i], node.get());
|
||||
node->mNumChildren++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nb_metadata > 0 ) {
|
||||
if (nb_metadata > 0) {
|
||||
node->mMetaData = aiMetadata::Alloc(nb_metadata);
|
||||
for (unsigned int i = 0; i < nb_metadata; ++i) {
|
||||
node->mMetaData->mKeys[i] = Read<aiString>(stream);
|
||||
node->mMetaData->mValues[i].mType = (aiMetadataType) Read<uint16_t>(stream);
|
||||
void* data = nullptr;
|
||||
node->mMetaData->mValues[i].mType = (aiMetadataType)Read<uint16_t>(stream);
|
||||
void *data = nullptr;
|
||||
|
||||
switch (node->mMetaData->mValues[i].mType) {
|
||||
case AI_BOOL:
|
||||
|
@ -263,7 +263,7 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
|||
data = new uint64_t(Read<uint64_t>(stream));
|
||||
break;
|
||||
case AI_FLOAT:
|
||||
data = new float(Read<float>(stream));
|
||||
data = new ai_real(Read<ai_real>(stream));
|
||||
break;
|
||||
case AI_DOUBLE:
|
||||
data = new double(Read<double>(stream));
|
||||
|
@ -288,10 +288,10 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
|
||||
void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
|
||||
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->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.
|
||||
// maybe I'll add a better, hash-like solution later
|
||||
if (shortened) {
|
||||
ReadBounds(stream,b->mWeights,b->mNumWeights);
|
||||
ReadBounds(stream, b->mWeights, b->mNumWeights);
|
||||
} else {
|
||||
// else write as usual
|
||||
b->mWeights = new aiVertexWeight[b->mNumWeights];
|
||||
ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
|
||||
ReadArray<aiVertexWeight>(stream, b->mWeights, b->mNumWeights);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
static bool fitsIntoUI16(unsigned int mNumVertices) {
|
||||
return ( mNumVertices < (1u<<16) );
|
||||
return (mNumVertices < (1u << 16));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
|
||||
void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
|
||||
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->mNumVertices = Read<unsigned int>(stream);
|
||||
|
@ -329,48 +330,48 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
|||
|
||||
if (c & ASSBIN_MESH_HAS_POSITIONS) {
|
||||
if (shortened) {
|
||||
ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mVertices, mesh->mNumVertices);
|
||||
} else {
|
||||
// else write as usual
|
||||
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 (shortened) {
|
||||
ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mNormals, mesh->mNumVertices);
|
||||
} else {
|
||||
// else write as usual
|
||||
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 (shortened) {
|
||||
ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
|
||||
ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mTangents, mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices);
|
||||
} else {
|
||||
// else write as usual
|
||||
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];
|
||||
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))) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (shortened) {
|
||||
ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices);
|
||||
} else {
|
||||
// else write as usual
|
||||
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))) {
|
||||
break;
|
||||
}
|
||||
|
@ -379,11 +380,11 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
|||
mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
|
||||
|
||||
if (shortened) {
|
||||
ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
|
||||
ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||
} else {
|
||||
// else write as usual
|
||||
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
|
||||
ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
|
||||
ReadArray<aiVector3D>(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,16 +398,16 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
|||
// else write as usual
|
||||
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
|
||||
aiFace& f = mesh->mFaces[i];
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
aiFace &f = mesh->mFaces[i];
|
||||
|
||||
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
|
||||
f.mNumIndices = Read<uint16_t>(stream);
|
||||
f.mIndices = new unsigned int[f.mNumIndices];
|
||||
|
||||
for (unsigned int a = 0; a < f.mNumIndices;++a) {
|
||||
for (unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||
// Check if unsigned short ( 16 bit ) are big enought for the indices
|
||||
if ( fitsIntoUI16( mesh->mNumVertices ) ) {
|
||||
if (fitsIntoUI16(mesh->mNumVertices)) {
|
||||
f.mIndices[a] = Read<uint16_t>(stream);
|
||||
} else {
|
||||
f.mIndices[a] = Read<unsigned int>(stream);
|
||||
|
@ -417,19 +418,19 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
|
|||
|
||||
// write bones
|
||||
if (mesh->mNumBones) {
|
||||
mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
|
||||
for (unsigned int a = 0; a < mesh->mNumBones;++a) {
|
||||
mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones];
|
||||
for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
|
||||
mesh->mBones[a] = new aiBone();
|
||||
ReadBinaryBone(stream,mesh->mBones[a]);
|
||||
ReadBinaryBone(stream, mesh->mBones[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
|
||||
void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
|
||||
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->mSemantic = Read<unsigned int>(stream);
|
||||
|
@ -437,36 +438,34 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro
|
|||
|
||||
prop->mDataLength = Read<unsigned int>(stream);
|
||||
prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
|
||||
prop->mData = new char [ prop->mDataLength ];
|
||||
stream->Read(prop->mData,1,prop->mDataLength);
|
||||
prop->mData = new char[prop->mDataLength];
|
||||
stream->Read(prop->mData, 1, prop->mDataLength);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
|
||||
void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
|
||||
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);
|
||||
if (mat->mNumProperties)
|
||||
{
|
||||
if (mat->mProperties)
|
||||
{
|
||||
if (mat->mNumProperties) {
|
||||
if (mat->mProperties) {
|
||||
delete[] mat->mProperties;
|
||||
}
|
||||
mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
|
||||
for (unsigned int i = 0; i < mat->mNumProperties;++i) {
|
||||
mat->mProperties = new aiMaterialProperty *[mat->mNumProperties];
|
||||
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
||||
mat->mProperties[i] = new aiMaterialProperty();
|
||||
ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
|
||||
ReadBinaryMaterialProperty(stream, mat->mProperties[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
|
||||
void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
|
||||
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->mNumPositionKeys = Read<unsigned int>(stream);
|
||||
|
@ -477,82 +476,82 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) {
|
|||
|
||||
if (nd->mNumPositionKeys) {
|
||||
if (shortened) {
|
||||
ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
|
||||
ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||
|
||||
} // else write as usual
|
||||
else {
|
||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||
ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
|
||||
ReadArray<aiVectorKey>(stream, nd->mPositionKeys, nd->mNumPositionKeys);
|
||||
}
|
||||
}
|
||||
if (nd->mNumRotationKeys) {
|
||||
if (shortened) {
|
||||
ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
|
||||
ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||
|
||||
} else {
|
||||
// else write as usual
|
||||
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
|
||||
ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
|
||||
ReadArray<aiQuatKey>(stream, nd->mRotationKeys, nd->mNumRotationKeys);
|
||||
}
|
||||
}
|
||||
if (nd->mNumScalingKeys) {
|
||||
if (shortened) {
|
||||
ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
|
||||
ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys);
|
||||
|
||||
} else {
|
||||
// else write as usual
|
||||
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 ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
|
||||
void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
|
||||
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->mDuration = Read<double> (stream);
|
||||
anim->mTicksPerSecond = Read<double> (stream);
|
||||
anim->mName = Read<aiString>(stream);
|
||||
anim->mDuration = Read<double>(stream);
|
||||
anim->mTicksPerSecond = Read<double>(stream);
|
||||
anim->mNumChannels = Read<unsigned int>(stream);
|
||||
|
||||
if (anim->mNumChannels) {
|
||||
anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
|
||||
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
|
||||
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
|
||||
for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
|
||||
anim->mChannels[a] = new aiNodeAnim();
|
||||
ReadBinaryNodeAnim(stream,anim->mChannels[a]);
|
||||
ReadBinaryNodeAnim(stream, anim->mChannels[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
|
||||
void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
|
||||
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->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) {
|
||||
tex->pcData = new aiTexel[ tex->mWidth ];
|
||||
stream->Read(tex->pcData,1,tex->mWidth);
|
||||
tex->pcData = new aiTexel[tex->mWidth];
|
||||
stream->Read(tex->pcData, 1, tex->mWidth);
|
||||
} else {
|
||||
tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
|
||||
stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
|
||||
tex->pcData = new aiTexel[tex->mWidth * tex->mHeight];
|
||||
stream->Read(tex->pcData, 1, tex->mWidth * tex->mHeight * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
|
||||
void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
|
||||
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->mType = (aiLightSourceType)Read<unsigned int>(stream);
|
||||
|
@ -574,10 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
|
||||
void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
|
||||
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->mPosition = Read<aiVector3D>(stream);
|
||||
|
@ -590,10 +589,10 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
|
||||
if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
|
||||
void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
|
||||
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->mNumMeshes = Read<unsigned int>(stream);
|
||||
|
@ -605,126 +604,124 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
|
|||
|
||||
// Read node graph
|
||||
//scene->mRootNode = new aiNode[1];
|
||||
ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL );
|
||||
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL);
|
||||
|
||||
// Read all meshes
|
||||
if (scene->mNumMeshes) {
|
||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes];
|
||||
memset(scene->mMeshes, 0, scene->mNumMeshes*sizeof(aiMesh*));
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
|
||||
scene->mMeshes = new aiMesh *[scene->mNumMeshes];
|
||||
memset(scene->mMeshes, 0, scene->mNumMeshes * sizeof(aiMesh *));
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
scene->mMeshes[i] = new aiMesh();
|
||||
ReadBinaryMesh( stream,scene->mMeshes[i]);
|
||||
ReadBinaryMesh(stream, scene->mMeshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read materials
|
||||
if (scene->mNumMaterials) {
|
||||
scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
|
||||
memset(scene->mMaterials, 0, scene->mNumMaterials*sizeof(aiMaterial*));
|
||||
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
|
||||
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
|
||||
memset(scene->mMaterials, 0, scene->mNumMaterials * sizeof(aiMaterial *));
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
scene->mMaterials[i] = new aiMaterial();
|
||||
ReadBinaryMaterial(stream,scene->mMaterials[i]);
|
||||
ReadBinaryMaterial(stream, scene->mMaterials[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read all animations
|
||||
if (scene->mNumAnimations) {
|
||||
scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
|
||||
memset(scene->mAnimations, 0, scene->mNumAnimations*sizeof(aiAnimation*));
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
|
||||
scene->mAnimations = new aiAnimation *[scene->mNumAnimations];
|
||||
memset(scene->mAnimations, 0, scene->mNumAnimations * sizeof(aiAnimation *));
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||
scene->mAnimations[i] = new aiAnimation();
|
||||
ReadBinaryAnim(stream,scene->mAnimations[i]);
|
||||
ReadBinaryAnim(stream, scene->mAnimations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read all textures
|
||||
if (scene->mNumTextures) {
|
||||
scene->mTextures = new aiTexture*[scene->mNumTextures];
|
||||
memset(scene->mTextures, 0, scene->mNumTextures*sizeof(aiTexture*));
|
||||
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
|
||||
scene->mTextures = new aiTexture *[scene->mNumTextures];
|
||||
memset(scene->mTextures, 0, scene->mNumTextures * sizeof(aiTexture *));
|
||||
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
|
||||
scene->mTextures[i] = new aiTexture();
|
||||
ReadBinaryTexture(stream,scene->mTextures[i]);
|
||||
ReadBinaryTexture(stream, scene->mTextures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read lights
|
||||
if (scene->mNumLights) {
|
||||
scene->mLights = new aiLight*[scene->mNumLights];
|
||||
memset(scene->mLights, 0, scene->mNumLights*sizeof(aiLight*));
|
||||
for (unsigned int i = 0; i < scene->mNumLights;++i) {
|
||||
scene->mLights = new aiLight *[scene->mNumLights];
|
||||
memset(scene->mLights, 0, scene->mNumLights * sizeof(aiLight *));
|
||||
for (unsigned int i = 0; i < scene->mNumLights; ++i) {
|
||||
scene->mLights[i] = new aiLight();
|
||||
ReadBinaryLight(stream,scene->mLights[i]);
|
||||
ReadBinaryLight(stream, scene->mLights[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read cameras
|
||||
if (scene->mNumCameras) {
|
||||
scene->mCameras = new aiCamera*[scene->mNumCameras];
|
||||
memset(scene->mCameras, 0, scene->mNumCameras*sizeof(aiCamera*));
|
||||
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
|
||||
scene->mCameras = new aiCamera *[scene->mNumCameras];
|
||||
memset(scene->mCameras, 0, scene->mNumCameras * sizeof(aiCamera *));
|
||||
for (unsigned int i = 0; i < scene->mNumCameras; ++i) {
|
||||
scene->mCameras[i] = new aiCamera();
|
||||
ReadBinaryCamera(stream,scene->mCameras[i]);
|
||||
ReadBinaryCamera(stream, scene->mCameras[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) {
|
||||
IOStream * stream = pIOHandler->Open(pFile,"rb");
|
||||
void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
IOStream *stream = pIOHandler->Open(pFile, "rb");
|
||||
if (nullptr == stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
// signature
|
||||
stream->Seek( 44, aiOrigin_CUR );
|
||||
stream->Seek(44, aiOrigin_CUR);
|
||||
|
||||
unsigned int versionMajor = Read<unsigned int>(stream);
|
||||
unsigned int versionMinor = Read<unsigned int>(stream);
|
||||
if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
|
||||
throw DeadlyImportError( "Invalid version, data format not compatible!" );
|
||||
throw DeadlyImportError("Invalid version, data format not compatible!");
|
||||
}
|
||||
|
||||
/*unsigned int versionRevision =*/ Read<unsigned int>(stream);
|
||||
/*unsigned int compileFlags =*/ Read<unsigned int>(stream);
|
||||
/*unsigned int versionRevision =*/Read<unsigned int>(stream);
|
||||
/*unsigned int compileFlags =*/Read<unsigned int>(stream);
|
||||
|
||||
shortened = Read<uint16_t>(stream) > 0;
|
||||
compressed = Read<uint16_t>(stream) > 0;
|
||||
|
||||
if (shortened)
|
||||
throw DeadlyImportError( "Shortened binaries are not supported!" );
|
||||
throw DeadlyImportError("Shortened binaries are not supported!");
|
||||
|
||||
stream->Seek( 256, aiOrigin_CUR ); // original filename
|
||||
stream->Seek( 128, aiOrigin_CUR ); // options
|
||||
stream->Seek( 64, aiOrigin_CUR ); // padding
|
||||
stream->Seek(256, aiOrigin_CUR); // original filename
|
||||
stream->Seek(128, aiOrigin_CUR); // options
|
||||
stream->Seek(64, aiOrigin_CUR); // padding
|
||||
|
||||
if (compressed) {
|
||||
uLongf uncompressedSize = Read<uint32_t>(stream);
|
||||
uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
|
||||
|
||||
unsigned char * compressedData = new unsigned char[ compressedSize ];
|
||||
size_t len = stream->Read( compressedData, 1, compressedSize );
|
||||
unsigned char *compressedData = new unsigned char[compressedSize];
|
||||
size_t len = stream->Read(compressedData, 1, compressedSize);
|
||||
ai_assert(len == compressedSize);
|
||||
|
||||
unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
|
||||
unsigned char *uncompressedData = new unsigned char[uncompressedSize];
|
||||
|
||||
int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len );
|
||||
if(res != Z_OK)
|
||||
{
|
||||
delete [] uncompressedData;
|
||||
delete [] compressedData;
|
||||
int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len);
|
||||
if (res != Z_OK) {
|
||||
delete[] uncompressedData;
|
||||
delete[] compressedData;
|
||||
pIOHandler->Close(stream);
|
||||
throw DeadlyImportError("Zlib decompression failed.");
|
||||
}
|
||||
|
||||
MemoryIOStream io( uncompressedData, uncompressedSize );
|
||||
MemoryIOStream io(uncompressedData, uncompressedSize);
|
||||
|
||||
ReadBinaryScene(&io,pScene);
|
||||
ReadBinaryScene(&io, pScene);
|
||||
|
||||
delete[] uncompressedData;
|
||||
delete[] compressedData;
|
||||
} else {
|
||||
ReadBinaryScene(stream,pScene);
|
||||
ReadBinaryScene(stream, pScene);
|
||||
}
|
||||
|
||||
pIOHandler->Close(stream);
|
|
@ -9,6 +9,9 @@ For details, see http://sourceforge.net/projects/libb64
|
|||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
state_in->step = step_A;
|
||||
|
@ -107,3 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
|||
return (int)(codechar - code_out);
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
|
@ -8,6 +8,10 @@ For details, see http://sourceforge.net/projects/libb64
|
|||
#ifndef BASE64_CENCODE_H
|
||||
#define BASE64_CENCODE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4127 )
|
||||
#endif // _WIN32
|
||||
|
||||
typedef enum
|
||||
{
|
||||
step_A, step_B, step_C
|
|
@ -9,16 +9,17 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
|
|||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#define CURRENT_FORMAT_VERSION 100
|
||||
|
||||
|
@ -28,11 +29,11 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
|
|||
#include "mesh_splitter.h"
|
||||
|
||||
extern "C" {
|
||||
#include "cencode.h"
|
||||
#include "cencode.h"
|
||||
}
|
||||
namespace Assimp {
|
||||
|
||||
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
|
||||
void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
|
||||
|
||||
// small utility class to simplify serializing the aiScene to Json
|
||||
class JSONWriter {
|
||||
|
@ -42,10 +43,8 @@ public:
|
|||
Flag_WriteSpecialFloats = 0x2,
|
||||
};
|
||||
|
||||
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
|
||||
: out(out)
|
||||
, first()
|
||||
, flags(flags) {
|
||||
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
|
||||
out(out), first(), flags(flags) {
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
buff.imbue(std::locale("C"));
|
||||
}
|
||||
|
@ -68,43 +67,43 @@ public:
|
|||
indent.erase(indent.end() - 1);
|
||||
}
|
||||
|
||||
void Key(const std::string& name) {
|
||||
void Key(const std::string &name) {
|
||||
AddIndentation();
|
||||
Delimit();
|
||||
buff << '\"' + name + "\": ";
|
||||
}
|
||||
|
||||
template<typename Literal>
|
||||
void Element(const Literal& name) {
|
||||
template <typename Literal>
|
||||
void Element(const Literal &name) {
|
||||
AddIndentation();
|
||||
Delimit();
|
||||
|
||||
LiteralToString(buff, name) << '\n';
|
||||
}
|
||||
|
||||
template<typename Literal>
|
||||
void SimpleValue(const Literal& s) {
|
||||
template <typename Literal>
|
||||
void SimpleValue(const Literal &s) {
|
||||
LiteralToString(buff, s) << '\n';
|
||||
}
|
||||
|
||||
void SimpleValue(const void* buffer, size_t len) {
|
||||
void SimpleValue(const void *buffer, size_t len) {
|
||||
base64_encodestate s;
|
||||
base64_init_encodestate(&s);
|
||||
|
||||
char* const out = new char[std::max(len * 2, static_cast<size_t>(16u))];
|
||||
const int n = base64_encode_block(reinterpret_cast<const char*>(buffer), static_cast<int>(len), out, &s);
|
||||
out[n + base64_encode_blockend(out + n, &s)] = '\0';
|
||||
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), cur_out, &s);
|
||||
cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
|
||||
|
||||
// base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
|
||||
// (only escaped ones). Remove any newlines in out.
|
||||
for (char* cur = out; *cur; ++cur) {
|
||||
for (char *cur = cur_out; *cur; ++cur) {
|
||||
if (*cur == '\n') {
|
||||
*cur = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
buff << '\"' << out << "\"\n";
|
||||
delete[] out;
|
||||
buff << '\"' << cur_out << "\"\n";
|
||||
delete[] cur_out;
|
||||
}
|
||||
|
||||
void StartObj(bool is_element = false) {
|
||||
|
@ -156,21 +155,20 @@ public:
|
|||
void Delimit() {
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buff << ' ';
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Literal>
|
||||
std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
|
||||
template <typename Literal>
|
||||
std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
|
||||
stream << s;
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
|
||||
std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
|
||||
std::string t;
|
||||
|
||||
// escape backslashes and single quotes, both would render the JSON invalid if left as is
|
||||
|
@ -189,7 +187,7 @@ private:
|
|||
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) {
|
||||
// on a non IEEE-754 platform, we make no assumptions about the representation or existence
|
||||
// of special floating-point numbers.
|
||||
|
@ -228,7 +226,7 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
Assimp::IOStream& out;
|
||||
Assimp::IOStream &out;
|
||||
std::string indent, newline;
|
||||
std::stringstream buff;
|
||||
bool first;
|
||||
|
@ -236,7 +234,7 @@ private:
|
|||
unsigned int flags;
|
||||
};
|
||||
|
||||
void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.x);
|
||||
out.Element(ai.y);
|
||||
|
@ -244,7 +242,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
|
|||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.w);
|
||||
out.Element(ai.x);
|
||||
|
@ -253,7 +251,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
|
|||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.r);
|
||||
out.Element(ai.g);
|
||||
|
@ -261,7 +259,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
|
|||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
for (unsigned int x = 0; x < 4; ++x) {
|
||||
for (unsigned int y = 0; y < 4; ++y) {
|
||||
|
@ -271,7 +269,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
|
|||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -292,7 +290,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
|
||||
out.Element(ai.mIndices[i]);
|
||||
|
@ -300,7 +298,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
|
|||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -411,7 +409,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -441,13 +439,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("properties");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
|
||||
const aiMaterialProperty* const prop = ai.mProperties[i];
|
||||
const aiMaterialProperty *const prop = ai.mProperties[i];
|
||||
out.StartObj(true);
|
||||
out.Key("key");
|
||||
out.SimpleValue(prop->mKey);
|
||||
|
@ -464,41 +462,36 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
case aiPTI_Float:
|
||||
if (prop->mDataLength / sizeof(float) > 1) {
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) {
|
||||
out.Element(reinterpret_cast<float*>(prop->mData)[i]);
|
||||
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
|
||||
out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
else {
|
||||
out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
|
||||
} else {
|
||||
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
||||
case aiPTI_Integer:
|
||||
if (prop->mDataLength / sizeof(int) > 1) {
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) {
|
||||
out.Element(reinterpret_cast<int*>(prop->mData)[i]);
|
||||
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
|
||||
out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
|
||||
}
|
||||
out.EndArray();
|
||||
} else {
|
||||
out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
|
||||
out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
||||
case aiPTI_String:
|
||||
{
|
||||
case aiPTI_String: {
|
||||
aiString s;
|
||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||
out.SimpleValue(s);
|
||||
}
|
||||
break;
|
||||
case aiPTI_Buffer:
|
||||
{
|
||||
} break;
|
||||
case aiPTI_Buffer: {
|
||||
// binary data is written as series of hex-encoded octets
|
||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
@ -510,7 +503,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("width");
|
||||
|
@ -525,13 +518,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
|||
out.Key("data");
|
||||
if (!ai.mHeight) {
|
||||
out.SimpleValue(ai.pcData, ai.mWidth);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out.StartArray();
|
||||
for (unsigned int y = 0; y < ai.mHeight; ++y) {
|
||||
out.StartArray(true);
|
||||
for (unsigned int x = 0; x < ai.mWidth; ++x) {
|
||||
const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
|
||||
const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
|
||||
out.StartArray(true);
|
||||
out.Element(static_cast<unsigned int>(tx.r));
|
||||
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();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
|||
if (ai.mType != aiLightSource_POINT) {
|
||||
out.Key("direction");
|
||||
Write(out, ai.mDirection, false);
|
||||
|
||||
}
|
||||
|
||||
if (ai.mType != aiLightSource_DIRECTIONAL) {
|
||||
|
@ -596,7 +587,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -612,7 +603,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
|||
out.Key("positionkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
|
||||
const aiVectorKey& pos = ai.mPositionKeys[n];
|
||||
const aiVectorKey &pos = ai.mPositionKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(pos.mTime);
|
||||
Write(out, pos.mValue);
|
||||
|
@ -625,7 +616,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
|||
out.Key("rotationkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
|
||||
const aiQuatKey& rot = ai.mRotationKeys[n];
|
||||
const aiQuatKey &rot = ai.mRotationKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(rot.mTime);
|
||||
Write(out, rot.mValue);
|
||||
|
@ -638,7 +629,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
|||
out.Key("scalingkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
|
||||
const aiVectorKey& scl = ai.mScalingKeys[n];
|
||||
const aiVectorKey &scl = ai.mScalingKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(scl.mTime);
|
||||
Write(out, scl.mValue);
|
||||
|
@ -649,7 +640,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -670,7 +661,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
|
||||
void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
|
@ -697,7 +688,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void WriteFormatInfo(JSONWriter& out) {
|
||||
void WriteFormatInfo(JSONWriter &out) {
|
||||
out.StartObj();
|
||||
out.Key("format");
|
||||
out.SimpleValue("\"assimp2json\"");
|
||||
|
@ -706,7 +697,7 @@ void WriteFormatInfo(JSONWriter& out) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiScene& ai) {
|
||||
void Write(JSONWriter &out, const aiScene &ai) {
|
||||
out.StartObj();
|
||||
|
||||
out.Key("__metadata__");
|
||||
|
@ -774,15 +765,14 @@ void Write(JSONWriter& out, const aiScene& ai) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
|
||||
void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
|
||||
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
|
||||
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
|
||||
if (!str) {
|
||||
//throw Assimp::DeadlyExportError("could not open output file");
|
||||
throw DeadlyExportError("could not open output file");
|
||||
}
|
||||
|
||||
// get a copy of the scene so we can modify it
|
||||
aiScene* scenecopy_tmp;
|
||||
aiScene *scenecopy_tmp;
|
||||
aiCopyScene(scene, &scenecopy_tmp);
|
||||
|
||||
try {
|
||||
|
@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
|
|||
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
|
||||
Write(s, *scenecopy_tmp);
|
||||
|
||||
}
|
||||
catch (...) {
|
||||
} catch (...) {
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
throw;
|
||||
}
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -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 ReadChunk();
|
||||
void ExitChunk();
|
||||
unsigned ChunkSize();
|
||||
size_t ChunkSize();
|
||||
|
||||
template<class T>
|
||||
T *to_array( const std::vector<T> &v );
|
||||
|
@ -112,10 +112,10 @@ private:
|
|||
|
||||
void ReadBB3D( aiScene *scene );
|
||||
|
||||
unsigned _pos;
|
||||
size_t _pos;
|
||||
// unsigned _size;
|
||||
std::vector<unsigned char> _buf;
|
||||
std::vector<unsigned> _stack;
|
||||
std::vector<size_t> _stack;
|
||||
|
||||
std::vector<std::string> _textures;
|
||||
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
|
||||
|
||||
#include "BVHLoader.h"
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <memory>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
@ -74,104 +73,98 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BVHLoader::BVHLoader()
|
||||
: mLine(),
|
||||
BVHLoader::BVHLoader() :
|
||||
mLine(),
|
||||
mAnimTickDuration(),
|
||||
mAnimNumFrames(),
|
||||
noSkeletonMesh()
|
||||
{}
|
||||
noSkeletonMesh() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BVHLoader::~BVHLoader()
|
||||
{}
|
||||
BVHLoader::~BVHLoader() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
|
||||
{
|
||||
bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
|
||||
// check file extension
|
||||
const std::string extension = GetExtension(pFile);
|
||||
|
||||
if( extension == "bvh")
|
||||
if (extension == "bvh")
|
||||
return true;
|
||||
|
||||
if ((!extension.length() || cs) && pIOHandler) {
|
||||
const char* tokens[] = {"HIERARCHY"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
const char *tokens[] = { "HIERARCHY" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
void BVHLoader::SetupProperties(const Importer *pImp) {
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* BVHLoader::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *BVHLoader::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
mFileName = pFile;
|
||||
|
||||
// read file into memory
|
||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||
if( file.get() == NULL)
|
||||
throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||
if (file.get() == nullptr) {
|
||||
throw DeadlyImportError("Failed to open file " + pFile + ".");
|
||||
}
|
||||
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize == 0)
|
||||
throw DeadlyImportError( "File is too small.");
|
||||
if (fileSize == 0) {
|
||||
throw DeadlyImportError("File is too small.");
|
||||
}
|
||||
|
||||
mBuffer.resize( fileSize);
|
||||
file->Read( &mBuffer.front(), 1, fileSize);
|
||||
mBuffer.resize(fileSize);
|
||||
file->Read(&mBuffer.front(), 1, fileSize);
|
||||
|
||||
// start reading
|
||||
mReader = mBuffer.begin();
|
||||
mLine = 1;
|
||||
ReadStructure( pScene);
|
||||
ReadStructure(pScene);
|
||||
|
||||
if (!noSkeletonMesh) {
|
||||
// build a dummy mesh for the skeleton so that we see something at least
|
||||
SkeletonMeshBuilder meshBuilder( pScene);
|
||||
SkeletonMeshBuilder meshBuilder(pScene);
|
||||
}
|
||||
|
||||
// construct an animation from all the motion data we read
|
||||
CreateAnimation( pScene);
|
||||
CreateAnimation(pScene);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the file
|
||||
void BVHLoader::ReadStructure( aiScene* pScene)
|
||||
{
|
||||
void BVHLoader::ReadStructure(aiScene *pScene) {
|
||||
// first comes hierarchy
|
||||
std::string header = GetNextToken();
|
||||
if( header != "HIERARCHY")
|
||||
ThrowException( "Expected header string \"HIERARCHY\".");
|
||||
ReadHierarchy( pScene);
|
||||
if (header != "HIERARCHY")
|
||||
ThrowException("Expected header string \"HIERARCHY\".");
|
||||
ReadHierarchy(pScene);
|
||||
|
||||
// then comes the motion data
|
||||
std::string motion = GetNextToken();
|
||||
if( motion != "MOTION")
|
||||
ThrowException( "Expected beginning of motion data \"MOTION\".");
|
||||
ReadMotion( pScene);
|
||||
if (motion != "MOTION")
|
||||
ThrowException("Expected beginning of motion data \"MOTION\".");
|
||||
ReadMotion(pScene);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the hierarchy
|
||||
void BVHLoader::ReadHierarchy( aiScene* pScene)
|
||||
{
|
||||
void BVHLoader::ReadHierarchy(aiScene *pScene) {
|
||||
std::string root = GetNextToken();
|
||||
if( root != "ROOT")
|
||||
ThrowException( "Expected root node \"ROOT\".");
|
||||
if (root != "ROOT")
|
||||
ThrowException("Expected root node \"ROOT\".");
|
||||
|
||||
// Go read the hierarchy from here
|
||||
pScene->mRootNode = ReadNode();
|
||||
|
@ -179,73 +172,64 @@ void BVHLoader::ReadHierarchy( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node and recursively its childs and returns the created node;
|
||||
aiNode* BVHLoader::ReadNode()
|
||||
{
|
||||
aiNode *BVHLoader::ReadNode() {
|
||||
// first token is name
|
||||
std::string nodeName = GetNextToken();
|
||||
if( nodeName.empty() || nodeName == "{")
|
||||
ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." );
|
||||
if (nodeName.empty() || nodeName == "{")
|
||||
ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
|
||||
|
||||
// then an opening brace should follow
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." );
|
||||
if (openBrace != "{")
|
||||
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
||||
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( nodeName);
|
||||
std::vector<aiNode*> childNodes;
|
||||
aiNode *node = new aiNode(nodeName);
|
||||
std::vector<aiNode *> childNodes;
|
||||
|
||||
// and create an bone entry for it
|
||||
mNodes.push_back( Node( node));
|
||||
Node& internNode = mNodes.back();
|
||||
mNodes.push_back(Node(node));
|
||||
Node &internNode = mNodes.back();
|
||||
|
||||
// now read the node's contents
|
||||
std::string siteToken;
|
||||
while( 1)
|
||||
{
|
||||
while (1) {
|
||||
std::string token = GetNextToken();
|
||||
|
||||
// node offset to parent node
|
||||
if( token == "OFFSET")
|
||||
ReadNodeOffset( node);
|
||||
else if( token == "CHANNELS")
|
||||
ReadNodeChannels( internNode);
|
||||
else if( token == "JOINT")
|
||||
{
|
||||
if (token == "OFFSET")
|
||||
ReadNodeOffset(node);
|
||||
else if (token == "CHANNELS")
|
||||
ReadNodeChannels(internNode);
|
||||
else if (token == "JOINT") {
|
||||
// child node follows
|
||||
aiNode* child = ReadNode();
|
||||
aiNode *child = ReadNode();
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "End")
|
||||
{
|
||||
childNodes.push_back(child);
|
||||
} else if (token == "End") {
|
||||
// The real symbol is "End Site". Second part comes in a separate token
|
||||
siteToken.clear();
|
||||
siteToken = GetNextToken();
|
||||
if( siteToken != "Site")
|
||||
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
|
||||
if (siteToken != "Site")
|
||||
ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
|
||||
|
||||
aiNode* child = ReadEndSite( nodeName);
|
||||
aiNode *child = ReadEndSite(nodeName);
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
childNodes.push_back(child);
|
||||
} else if (token == "}") {
|
||||
// we're done with that part of the hierarchy
|
||||
break;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
// everything else is a parse error
|
||||
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
||||
ThrowException(format() << "Unknown keyword \"" << token << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
// add the child nodes if there are any
|
||||
if( childNodes.size() > 0)
|
||||
{
|
||||
if (childNodes.size() > 0) {
|
||||
node->mNumChildren = static_cast<unsigned int>(childNodes.size());
|
||||
node->mChildren = new aiNode*[node->mNumChildren];
|
||||
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
|
||||
node->mChildren = new aiNode *[node->mNumChildren];
|
||||
std::copy(childNodes.begin(), childNodes.end(), node->mChildren);
|
||||
}
|
||||
|
||||
// and return the sub-hierarchy we built here
|
||||
|
@ -254,31 +238,30 @@ aiNode* BVHLoader::ReadNode()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads an end node and returns the created node.
|
||||
aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
||||
{
|
||||
aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
|
||||
// check opening brace
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
||||
if (openBrace != "{")
|
||||
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
|
||||
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
||||
aiNode *node = new aiNode("EndSite_" + pParentName);
|
||||
|
||||
// now read the node's contents. Only possible entry is "OFFSET"
|
||||
std::string token;
|
||||
while( 1) {
|
||||
while (1) {
|
||||
token.clear();
|
||||
token = GetNextToken();
|
||||
|
||||
// end node's offset
|
||||
if( token == "OFFSET") {
|
||||
ReadNodeOffset( node);
|
||||
} else if( token == "}") {
|
||||
if (token == "OFFSET") {
|
||||
ReadNodeOffset(node);
|
||||
} else if (token == "}") {
|
||||
// we're done with the end node
|
||||
break;
|
||||
} else {
|
||||
// everything else is a parse error
|
||||
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
||||
ThrowException(format() << "Unknown keyword \"" << token << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,8 +270,7 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
|||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node offset for the given node
|
||||
void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||
{
|
||||
void BVHLoader::ReadNodeOffset(aiNode *pNode) {
|
||||
// Offset consists of three floats to read
|
||||
aiVector3D offset;
|
||||
offset.x = GetNextTokenAsFloat();
|
||||
|
@ -296,7 +278,7 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
|||
offset.z = GetNextTokenAsFloat();
|
||||
|
||||
// build a transformation matrix from it
|
||||
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
|
||||
pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x,
|
||||
0.0f, 1.0f, 0.0f, offset.y,
|
||||
0.0f, 0.0f, 1.0f, offset.z,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
@ -304,66 +286,61 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the animation channels for the given node
|
||||
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
||||
{
|
||||
void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
|
||||
// number of channels. Use the float reader because we're lazy
|
||||
float numChannelsFloat = GetNextTokenAsFloat();
|
||||
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
||||
unsigned int numChannels = (unsigned int)numChannelsFloat;
|
||||
|
||||
for( unsigned int a = 0; a < numChannels; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numChannels; a++) {
|
||||
std::string channelToken = GetNextToken();
|
||||
|
||||
if( channelToken == "Xposition")
|
||||
pNode.mChannels.push_back( Channel_PositionX);
|
||||
else if( channelToken == "Yposition")
|
||||
pNode.mChannels.push_back( Channel_PositionY);
|
||||
else if( channelToken == "Zposition")
|
||||
pNode.mChannels.push_back( Channel_PositionZ);
|
||||
else if( channelToken == "Xrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationX);
|
||||
else if( channelToken == "Yrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationY);
|
||||
else if( channelToken == "Zrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationZ);
|
||||
if (channelToken == "Xposition")
|
||||
pNode.mChannels.push_back(Channel_PositionX);
|
||||
else if (channelToken == "Yposition")
|
||||
pNode.mChannels.push_back(Channel_PositionY);
|
||||
else if (channelToken == "Zposition")
|
||||
pNode.mChannels.push_back(Channel_PositionZ);
|
||||
else if (channelToken == "Xrotation")
|
||||
pNode.mChannels.push_back(Channel_RotationX);
|
||||
else if (channelToken == "Yrotation")
|
||||
pNode.mChannels.push_back(Channel_RotationY);
|
||||
else if (channelToken == "Zrotation")
|
||||
pNode.mChannels.push_back(Channel_RotationZ);
|
||||
else
|
||||
ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." );
|
||||
ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the motion data
|
||||
void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
||||
{
|
||||
void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
|
||||
// Read number of frames
|
||||
std::string tokenFrames = GetNextToken();
|
||||
if( tokenFrames != "Frames:")
|
||||
ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
|
||||
if (tokenFrames != "Frames:")
|
||||
ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
|
||||
|
||||
float numFramesFloat = GetNextTokenAsFloat();
|
||||
mAnimNumFrames = (unsigned int) numFramesFloat;
|
||||
mAnimNumFrames = (unsigned int)numFramesFloat;
|
||||
|
||||
// Read frame duration
|
||||
std::string tokenDuration1 = GetNextToken();
|
||||
std::string tokenDuration2 = GetNextToken();
|
||||
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||
ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." );
|
||||
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||
ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
|
||||
|
||||
mAnimTickDuration = GetNextTokenAsFloat();
|
||||
|
||||
// resize value vectors for each node
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
|
||||
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames);
|
||||
|
||||
// now read all the data and store it in the corresponding node's value vector
|
||||
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
|
||||
{
|
||||
for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) {
|
||||
// on each line read the values for all nodes
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
{
|
||||
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) {
|
||||
// get as many values as the node has channels
|
||||
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
|
||||
it->mChannelValues.push_back( GetNextTokenAsFloat());
|
||||
for (unsigned int c = 0; c < it->mChannels.size(); ++c)
|
||||
it->mChannelValues.push_back(GetNextTokenAsFloat());
|
||||
}
|
||||
|
||||
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
|
||||
|
@ -372,16 +349,14 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Retrieves the next token
|
||||
std::string BVHLoader::GetNextToken()
|
||||
{
|
||||
std::string BVHLoader::GetNextToken() {
|
||||
// skip any preceding whitespace
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( !isspace( *mReader))
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (!isspace(*mReader))
|
||||
break;
|
||||
|
||||
// count lines
|
||||
if( *mReader == '\n')
|
||||
if (*mReader == '\n')
|
||||
mLine++;
|
||||
|
||||
++mReader;
|
||||
|
@ -389,16 +364,15 @@ std::string BVHLoader::GetNextToken()
|
|||
|
||||
// collect all chars till the next whitespace. BVH is easy in respect to that.
|
||||
std::string token;
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( isspace( *mReader))
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (isspace(*mReader))
|
||||
break;
|
||||
|
||||
token.push_back( *mReader);
|
||||
token.push_back(*mReader);
|
||||
++mReader;
|
||||
|
||||
// little extra logic to make sure braces are counted correctly
|
||||
if( token == "{" || token == "}")
|
||||
if (token == "{" || token == "}")
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -408,81 +382,73 @@ std::string BVHLoader::GetNextToken()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the next token as a float
|
||||
float BVHLoader::GetNextTokenAsFloat()
|
||||
{
|
||||
float BVHLoader::GetNextTokenAsFloat() {
|
||||
std::string token = GetNextToken();
|
||||
if( token.empty())
|
||||
ThrowException( "Unexpected end of file while trying to read a float");
|
||||
if (token.empty())
|
||||
ThrowException("Unexpected end of file while trying to read a float");
|
||||
|
||||
// check if the float is valid by testing if the atof() function consumed every char of the token
|
||||
const char* ctoken = token.c_str();
|
||||
const char *ctoken = token.c_str();
|
||||
float result = 0.0f;
|
||||
ctoken = fast_atoreal_move<float>( ctoken, result);
|
||||
ctoken = fast_atoreal_move<float>(ctoken, result);
|
||||
|
||||
if( ctoken != token.c_str() + token.length())
|
||||
ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." );
|
||||
if (ctoken != token.c_str() + token.length())
|
||||
ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aborts the file reading with an exception
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
|
||||
{
|
||||
throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError);
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
|
||||
throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs an animation for the motion data and stores it in the given scene
|
||||
void BVHLoader::CreateAnimation( aiScene* pScene)
|
||||
{
|
||||
void BVHLoader::CreateAnimation(aiScene *pScene) {
|
||||
// create the animation
|
||||
pScene->mNumAnimations = 1;
|
||||
pScene->mAnimations = new aiAnimation*[1];
|
||||
aiAnimation* anim = new aiAnimation;
|
||||
pScene->mAnimations = new aiAnimation *[1];
|
||||
aiAnimation *anim = new aiAnimation;
|
||||
pScene->mAnimations[0] = anim;
|
||||
|
||||
// put down the basic parameters
|
||||
anim->mName.Set( "Motion");
|
||||
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
|
||||
anim->mDuration = double( mAnimNumFrames - 1);
|
||||
anim->mName.Set("Motion");
|
||||
anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration);
|
||||
anim->mDuration = double(mAnimNumFrames - 1);
|
||||
|
||||
// now generate the tracks for all nodes
|
||||
anim->mNumChannels = static_cast<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
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
||||
for (unsigned int i = 0; i < anim->mNumChannels; ++i)
|
||||
anim->mChannels[i] = NULL;
|
||||
|
||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||
{
|
||||
const Node& node = mNodes[a];
|
||||
const std::string nodeName = std::string( node.mNode->mName.data );
|
||||
aiNodeAnim* nodeAnim = new aiNodeAnim;
|
||||
for (unsigned int a = 0; a < anim->mNumChannels; a++) {
|
||||
const Node &node = mNodes[a];
|
||||
const std::string nodeName = std::string(node.mNode->mName.data);
|
||||
aiNodeAnim *nodeAnim = new aiNodeAnim;
|
||||
anim->mChannels[a] = nodeAnim;
|
||||
nodeAnim->mNodeName.Set( nodeName);
|
||||
nodeAnim->mNodeName.Set(nodeName);
|
||||
std::map<BVHLoader::ChannelType, int> channelMap;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
// translational part, if given
|
||||
if( node.mChannels.size() == 6)
|
||||
{
|
||||
if (node.mChannels.size() == 6) {
|
||||
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
||||
aiVectorKey* poskey = nodeAnim->mPositionKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
poskey->mTime = double( fr);
|
||||
aiVectorKey *poskey = nodeAnim->mPositionKeys;
|
||||
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
|
||||
poskey->mTime = double(fr);
|
||||
|
||||
// Now compute all translations
|
||||
for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
|
||||
{
|
||||
for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
|
||||
//Find channel in node
|
||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
||||
|
||||
|
@ -504,15 +470,13 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
++poskey;
|
||||
}
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
// if no translation part is given, put a default sequence
|
||||
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
||||
aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
||||
nodeAnim->mNumPositionKeys = 1;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[1];
|
||||
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
||||
|
@ -525,42 +489,36 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
// Then create the number of rotation keys
|
||||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
|
||||
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
|
||||
aiMatrix4x4 temp;
|
||||
aiMatrix3x3 rotMatrix;
|
||||
for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
|
||||
{
|
||||
//Find channel in node
|
||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
||||
|
||||
if (mapIter == channelMap.end())
|
||||
throw DeadlyImportError("Missing rotation channel in node " + nodeName);
|
||||
else {
|
||||
int channelIdx = mapIter->second;
|
||||
// translate ZXY euler angels into a quaternion
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
|
||||
// Compute rotation transformations in the right order
|
||||
switch (channel)
|
||||
{
|
||||
for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) {
|
||||
switch (node.mChannels[channelIdx]) {
|
||||
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;
|
||||
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||
}
|
||||
break;
|
||||
case Channel_RotationY:
|
||||
aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
||||
{
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||
}
|
||||
break;
|
||||
case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
||||
case Channel_RotationZ:
|
||||
{
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rotkey->mTime = double( fr);
|
||||
rotkey->mValue = aiQuaternion( rotMatrix);
|
||||
rotkey->mTime = double(fr);
|
||||
rotkey->mValue = aiQuaternion(rotMatrix);
|
||||
++rotkey;
|
||||
}
|
||||
}
|
||||
|
@ -570,7 +528,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
nodeAnim->mNumScalingKeys = 1;
|
||||
nodeAnim->mScalingKeys = new aiVectorKey[1];
|
||||
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
||||
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
|
||||
nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
/** Loader class to read Motion Capturing data from a .bvh file.
|
||||
|
@ -63,12 +62,10 @@ namespace Assimp
|
|||
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
|
||||
* inside the loader just to be able to see something.
|
||||
*/
|
||||
class BVHLoader : public BaseImporter
|
||||
{
|
||||
class BVHLoader : public BaseImporter {
|
||||
|
||||
/** Possible animation channels for which the motion data holds the values */
|
||||
enum ChannelType
|
||||
{
|
||||
enum ChannelType {
|
||||
Channel_PositionX,
|
||||
Channel_PositionY,
|
||||
Channel_PositionZ,
|
||||
|
@ -78,61 +75,57 @@ class BVHLoader : public BaseImporter
|
|||
};
|
||||
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
const aiNode* mNode;
|
||||
struct Node {
|
||||
const aiNode *mNode;
|
||||
std::vector<ChannelType> mChannels;
|
||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||
|
||||
Node()
|
||||
: mNode(nullptr)
|
||||
{ }
|
||||
Node() :
|
||||
mNode(nullptr) {}
|
||||
|
||||
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
||||
explicit Node(const aiNode *pNode) :
|
||||
mNode(pNode) {}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
BVHLoader();
|
||||
~BVHLoader();
|
||||
|
||||
public:
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
|
||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const;
|
||||
|
||||
void SetupProperties(const Importer* pImp);
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
void SetupProperties(const Importer *pImp);
|
||||
const aiImporterDesc *GetInfo() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
||||
|
||||
protected:
|
||||
/** Reads the file */
|
||||
void ReadStructure( aiScene* pScene);
|
||||
void ReadStructure(aiScene *pScene);
|
||||
|
||||
/** Reads the hierarchy */
|
||||
void ReadHierarchy( aiScene* pScene);
|
||||
void ReadHierarchy(aiScene *pScene);
|
||||
|
||||
/** Reads a node and recursively its childs and returns the created node. */
|
||||
aiNode* ReadNode();
|
||||
aiNode *ReadNode();
|
||||
|
||||
/** Reads an end node and returns the created node. */
|
||||
aiNode* ReadEndSite( const std::string& pParentName);
|
||||
aiNode *ReadEndSite(const std::string &pParentName);
|
||||
|
||||
/** Reads a node offset for the given node */
|
||||
void ReadNodeOffset( aiNode* pNode);
|
||||
void ReadNodeOffset(aiNode *pNode);
|
||||
|
||||
/** Reads the animation channels into the given node */
|
||||
void ReadNodeChannels( BVHLoader::Node& pNode);
|
||||
void ReadNodeChannels(BVHLoader::Node &pNode);
|
||||
|
||||
/** Reads the motion data */
|
||||
void ReadMotion( aiScene* pScene);
|
||||
void ReadMotion(aiScene *pScene);
|
||||
|
||||
/** Retrieves the next token */
|
||||
std::string GetNextToken();
|
||||
|
@ -141,10 +134,10 @@ protected:
|
|||
float GetNextTokenAsFloat();
|
||||
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||
void CreateAnimation( aiScene* pScene);
|
||||
void CreateAnimation(aiScene *pScene);
|
||||
|
||||
protected:
|
||||
/** Filename, for a verbose error message */
|
|
@ -42,165 +42,143 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Conversion of Blender's new BMesh stuff
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
|
||||
#include "BlenderBMesh.h"
|
||||
#include "BlenderDNA.h"
|
||||
#include "BlenderScene.h"
|
||||
#include "BlenderBMesh.h"
|
||||
#include "BlenderTessellator.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
|
||||
{
|
||||
namespace Assimp {
|
||||
template <>
|
||||
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
|
||||
static auto prefix = "BLEND_BMESH: ";
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
|
||||
BMesh( mesh ),
|
||||
triMesh( NULL )
|
||||
{
|
||||
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
|
||||
BMesh(mesh),
|
||||
triMesh(nullptr) {
|
||||
ai_assert(nullptr != mesh);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter( )
|
||||
{
|
||||
DestroyTriMesh( );
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter() {
|
||||
DestroyTriMesh();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderBMeshConverter::ContainsBMesh( ) const
|
||||
{
|
||||
bool BlenderBMeshConverter::ContainsBMesh() const {
|
||||
// TODO - Should probably do some additional verification here
|
||||
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
||||
{
|
||||
AssertValidMesh( );
|
||||
AssertValidSizes( );
|
||||
PrepareTriMesh( );
|
||||
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
|
||||
AssertValidMesh();
|
||||
AssertValidSizes();
|
||||
PrepareTriMesh();
|
||||
|
||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
||||
{
|
||||
const MPoly& poly = BMesh->mpoly[ i ];
|
||||
ConvertPolyToFaces( poly );
|
||||
for (int i = 0; i < BMesh->totpoly; ++i) {
|
||||
const MPoly &poly = BMesh->mpoly[i];
|
||||
ConvertPolyToFaces(poly);
|
||||
}
|
||||
|
||||
return triMesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidMesh( )
|
||||
{
|
||||
if ( !ContainsBMesh( ) )
|
||||
{
|
||||
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
|
||||
void BlenderBMeshConverter::AssertValidMesh() {
|
||||
if (!ContainsBMesh()) {
|
||||
ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidSizes( )
|
||||
{
|
||||
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh poly array has incorrect size" );
|
||||
void BlenderBMeshConverter::AssertValidSizes() {
|
||||
if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
|
||||
ThrowException("BMesh poly array has incorrect size");
|
||||
}
|
||||
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh loop array has incorrect size" );
|
||||
if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
|
||||
ThrowException("BMesh loop array has incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::PrepareTriMesh( )
|
||||
{
|
||||
if ( triMesh )
|
||||
{
|
||||
DestroyTriMesh( );
|
||||
void BlenderBMeshConverter::PrepareTriMesh() {
|
||||
if (triMesh) {
|
||||
DestroyTriMesh();
|
||||
}
|
||||
|
||||
triMesh = new Mesh( *BMesh );
|
||||
triMesh = new Mesh(*BMesh);
|
||||
triMesh->totface = 0;
|
||||
triMesh->mface.clear( );
|
||||
triMesh->mface.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::DestroyTriMesh( )
|
||||
{
|
||||
void BlenderBMeshConverter::DestroyTriMesh() {
|
||||
delete triMesh;
|
||||
triMesh = NULL;
|
||||
triMesh = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
||||
{
|
||||
const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
|
||||
const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
|
||||
|
||||
if ( poly.totloop == 3 || poly.totloop == 4 )
|
||||
{
|
||||
AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
|
||||
if (poly.totloop == 3 || poly.totloop == 4) {
|
||||
AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0);
|
||||
|
||||
// UVs are optional, so only convert when present.
|
||||
if ( BMesh->mloopuv.size() )
|
||||
{
|
||||
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
|
||||
{
|
||||
ThrowException( "BMesh uv loop array has incorrect size" );
|
||||
if (BMesh->mloopuv.size()) {
|
||||
if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
|
||||
ThrowException("BMesh uv loop array has incorrect size");
|
||||
}
|
||||
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
|
||||
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
|
||||
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
|
||||
AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0);
|
||||
}
|
||||
}
|
||||
else if ( poly.totloop > 4 )
|
||||
{
|
||||
} else if (poly.totloop > 4) {
|
||||
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
BlenderTessellatorGL tessGL( *this );
|
||||
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
BlenderTessellatorGL tessGL(*this);
|
||||
tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
|
||||
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||
BlenderTessellatorP2T tessP2T( *this );
|
||||
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
BlenderTessellatorP2T tessP2T(*this);
|
||||
tessP2T.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
||||
{
|
||||
void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
|
||||
MFace face;
|
||||
face.v1 = v1;
|
||||
face.v2 = v2;
|
||||
face.v3 = v3;
|
||||
face.v4 = v4;
|
||||
face.flag = 0;
|
||||
// TODO - Work out how materials work
|
||||
face.mat_nr = 0;
|
||||
triMesh->mface.push_back( face );
|
||||
triMesh->totface = static_cast<int>(triMesh->mface.size( ));
|
||||
triMesh->mface.push_back(face);
|
||||
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;
|
||||
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
|
||||
memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
|
||||
memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
|
||||
memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
|
||||
|
||||
if ( uv4 )
|
||||
{
|
||||
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
|
||||
if (uv4) {
|
||||
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
|
||||
}
|
||||
|
||||
triMesh->mtface.push_back( mtface );
|
||||
triMesh->mtface.push_back(mtface);
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
#include "BlenderDNA.h"
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
static bool match4(StreamReaderAny& stream, const char* string) {
|
||||
ai_assert( nullptr != string );
|
||||
static bool match4(StreamReaderAny &stream, const char *string) {
|
||||
ai_assert(nullptr != string);
|
||||
char tmp[4];
|
||||
tmp[ 0 ] = ( stream ).GetI1();
|
||||
tmp[ 1 ] = ( stream ).GetI1();
|
||||
tmp[ 2 ] = ( stream ).GetI1();
|
||||
tmp[ 3 ] = ( stream ).GetI1();
|
||||
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
||||
tmp[0] = (stream).GetI1();
|
||||
tmp[1] = (stream).GetI1();
|
||||
tmp[2] = (stream).GetI1();
|
||||
tmp[3] = (stream).GetI1();
|
||||
return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]);
|
||||
}
|
||||
|
||||
struct Type {
|
||||
|
@ -72,74 +71,75 @@ struct Type {
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNAParser::Parse ()
|
||||
{
|
||||
StreamReaderAny& stream = *db.reader.get();
|
||||
DNA& dna = db.dna;
|
||||
void DNAParser::Parse() {
|
||||
StreamReaderAny &stream = *db.reader.get();
|
||||
DNA &dna = db.dna;
|
||||
|
||||
if(!match4(stream,"SDNA")) {
|
||||
if (!match4(stream, "SDNA")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
|
||||
}
|
||||
|
||||
// name dictionary
|
||||
if(!match4(stream,"NAME")) {
|
||||
if (!match4(stream, "NAME")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected NAME field");
|
||||
}
|
||||
|
||||
std::vector<std::string> names (stream.GetI4());
|
||||
for(std::string& s : names) {
|
||||
std::vector<std::string> names(stream.GetI4());
|
||||
for (std::string &s : names) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
|
||||
// type dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TYPE")) {
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TYPE")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||
}
|
||||
|
||||
std::vector<Type> types (stream.GetI4());
|
||||
for(Type& s : types) {
|
||||
std::vector<Type> types(stream.GetI4());
|
||||
for (Type &s : types) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s.name += c;
|
||||
}
|
||||
}
|
||||
|
||||
// type length dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TLEN")) {
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TLEN")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||
}
|
||||
|
||||
for(Type& s : types) {
|
||||
for (Type &s : types) {
|
||||
s.size = stream.GetI2();
|
||||
}
|
||||
|
||||
// structures dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"STRC")) {
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "STRC")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||
}
|
||||
|
||||
size_t end = stream.GetI4(), fields = 0;
|
||||
|
||||
dna.structures.reserve(end);
|
||||
for(size_t i = 0; i != end; ++i) {
|
||||
for (size_t i = 0; i != end; ++i) {
|
||||
|
||||
uint16_t n = stream.GetI2();
|
||||
if (n >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure name" ,n,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
"BlenderDNA: Invalid type index in structure name", n,
|
||||
" (there are only ", types.size(), " entries)"));
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
dna.indices[types[n].name] = dna.structures.size();
|
||||
|
||||
dna.structures.push_back(Structure());
|
||||
Structure& s = dna.structures.back();
|
||||
Structure &s = dna.structures.back();
|
||||
s.name = types[n].name;
|
||||
//s.index = dna.structures.size()-1;
|
||||
|
||||
|
@ -153,11 +153,10 @@ void DNAParser::Parse ()
|
|||
if (j >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"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());
|
||||
Field& f = s.fields.back();
|
||||
Field &f = s.fields.back();
|
||||
f.offset = offset;
|
||||
|
||||
f.type = types[j].name;
|
||||
|
@ -167,8 +166,7 @@ void DNAParser::Parse ()
|
|||
if (j >= names.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid name index in structure field ", j,
|
||||
" (there are only ", names.size(), " entries)"
|
||||
));
|
||||
" (there are only ", names.size(), " entries)"));
|
||||
}
|
||||
|
||||
f.name = names[j];
|
||||
|
@ -192,25 +190,24 @@ void DNAParser::Parse ()
|
|||
if (rb == std::string::npos) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Encountered invalid array declaration ",
|
||||
f.name
|
||||
));
|
||||
f.name));
|
||||
}
|
||||
|
||||
f.flags |= FieldFlag_Array;
|
||||
DNA::ExtractArraySize(f.name,f.array_sizes);
|
||||
f.name = f.name.substr(0,rb);
|
||||
DNA::ExtractArraySize(f.name, f.array_sizes);
|
||||
f.name = f.name.substr(0, rb);
|
||||
|
||||
f.size *= f.array_sizes[0] * f.array_sizes[1];
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
s.indices[f.name] = s.fields.size()-1;
|
||||
s.indices[f.name] = s.fields.size() - 1;
|
||||
offset += f.size;
|
||||
}
|
||||
s.size = offset;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
|
||||
ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
dna.DumpToFile();
|
||||
|
@ -220,13 +217,11 @@ void DNAParser::Parse ()
|
|||
dna.RegisterConverters();
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
|
||||
#include <fstream>
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNA :: DumpToFile()
|
||||
{
|
||||
void DNA ::DumpToFile() {
|
||||
// we don't bother using the VFS here for this is only for debugging.
|
||||
// (and all your bases are belong to us).
|
||||
|
||||
|
@ -235,12 +230,14 @@ void DNA :: DumpToFile()
|
|||
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
|
||||
return;
|
||||
}
|
||||
f << "Field format: type name offset size" << "\n";
|
||||
f << "Structure format: name size" << "\n";
|
||||
f << "Field format: type name offset size"
|
||||
<< "\n";
|
||||
f << "Structure format: name size"
|
||||
<< "\n";
|
||||
|
||||
for(const Structure& s : structures) {
|
||||
for (const Structure &s : structures) {
|
||||
f << s.name << " " << s.size << "\n\n";
|
||||
for(const Field& ff : s.fields) {
|
||||
for (const Field &ff : s.fields) {
|
||||
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
|
||||
}
|
||||
f << "\n";
|
||||
|
@ -252,11 +249,9 @@ void DNA :: DumpToFile()
|
|||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void DNA :: ExtractArraySize(
|
||||
const std::string& out,
|
||||
size_t array_sizes[2]
|
||||
)
|
||||
{
|
||||
/*static*/ void DNA ::ExtractArraySize(
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]) {
|
||||
array_sizes[0] = array_sizes[1] = 1;
|
||||
std::string::size_type pos = out.find('[');
|
||||
if (pos++ == std::string::npos) {
|
||||
|
@ -264,7 +259,7 @@ void DNA :: DumpToFile()
|
|||
}
|
||||
array_sizes[0] = strtoul10(&out[pos]);
|
||||
|
||||
pos = out.find('[',pos);
|
||||
pos = out.find('[', pos);
|
||||
if (pos++ == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
@ -272,36 +267,32 @@ void DNA :: DumpToFile()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
|
||||
const Structure& structure,
|
||||
const FileDatabase& db
|
||||
) const
|
||||
{
|
||||
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
|
||||
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase &db) const {
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
if (it == converters.end()) {
|
||||
return std::shared_ptr< ElemBase >();
|
||||
return std::shared_ptr<ElemBase>();
|
||||
}
|
||||
|
||||
std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
|
||||
(structure.*((*it).second.second))(ret,db);
|
||||
std::shared_ptr<ElemBase> ret = (structure.*((*it).second.first))();
|
||||
(structure.*((*it).second.second))(ret, db);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
DNA::FactoryPair DNA :: GetBlobToStructureConverter(
|
||||
const Structure& structure,
|
||||
const FileDatabase& /*db*/
|
||||
) const
|
||||
{
|
||||
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
|
||||
const Structure &structure,
|
||||
const FileDatabase & /*db*/
|
||||
) const {
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
return it == converters.end() ? FactoryPair() : (*it).second;
|
||||
}
|
||||
|
||||
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNA :: AddPrimitiveStructures()
|
||||
{
|
||||
void DNA ::AddPrimitiveStructures() {
|
||||
// NOTE: these are just dummies. Their presence enforces
|
||||
// Structure::Convert<target_type> to be called on these
|
||||
// empty structures. These converters are special
|
||||
|
@ -311,30 +302,27 @@ void DNA :: AddPrimitiveStructures()
|
|||
// in question.
|
||||
|
||||
indices["int"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "int";
|
||||
structures.back().size = 4;
|
||||
|
||||
indices["short"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "short";
|
||||
structures.back().size = 2;
|
||||
|
||||
|
||||
indices["char"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "char";
|
||||
structures.back().size = 1;
|
||||
|
||||
|
||||
indices["float"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "float";
|
||||
structures.back().size = 4;
|
||||
|
||||
|
||||
indices["double"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "double";
|
||||
structures.back().size = 8;
|
||||
|
||||
|
@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SectionParser :: Next()
|
||||
{
|
||||
void SectionParser ::Next() {
|
||||
stream.SetCurrentPos(current.start + current.size);
|
||||
|
||||
const char tmp[] = {
|
||||
|
@ -352,7 +339,7 @@ void SectionParser :: Next()
|
|||
(const char)stream.GetI1(),
|
||||
(const char)stream.GetI1()
|
||||
};
|
||||
current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
|
||||
current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
|
||||
|
||||
current.size = stream.GetI4();
|
||||
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
|
||||
|
@ -366,10 +353,8 @@ void SectionParser :: Next()
|
|||
}
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
ASSIMP_LOG_DEBUG(current.id);
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(current.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -49,22 +49,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// enable verbose log output. really verbose, so be careful.
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
# define ASSIMP_BUILD_BLENDER_DEBUG
|
||||
#define ASSIMP_BUILD_BLENDER_DEBUG
|
||||
#endif
|
||||
|
||||
// #define ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
template <bool,bool> class StreamReader;
|
||||
typedef StreamReader<true,true> StreamReaderAny;
|
||||
template <bool, bool>
|
||||
class StreamReader;
|
||||
typedef StreamReader<true, true> StreamReaderAny;
|
||||
|
||||
namespace Blender {
|
||||
|
||||
|
@ -82,8 +83,8 @@ class ObjectCache;
|
|||
* ancestry. */
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Error : DeadlyImportError {
|
||||
Error (const std::string& s)
|
||||
: DeadlyImportError(s) {
|
||||
Error(const std::string &s) :
|
||||
DeadlyImportError(s) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -93,9 +94,8 @@ struct Error : DeadlyImportError {
|
|||
* descendents. It serves as base class for all data structure fields. */
|
||||
// -------------------------------------------------------------------------------
|
||||
struct ElemBase {
|
||||
ElemBase()
|
||||
: dna_type(nullptr)
|
||||
{
|
||||
ElemBase() :
|
||||
dna_type(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ struct ElemBase {
|
|||
* data type is not static, i.e. a std::shared_ptr<ElemBase>
|
||||
* in the scene description would have its type resolved
|
||||
* 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.*/
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Pointer {
|
||||
Pointer()
|
||||
: val() {
|
||||
Pointer() :
|
||||
val() {
|
||||
// empty
|
||||
}
|
||||
uint64_t val;
|
||||
|
@ -131,8 +131,8 @@ struct Pointer {
|
|||
/** Represents a generic offset within a BLEND file */
|
||||
// -------------------------------------------------------------------------------
|
||||
struct FileOffset {
|
||||
FileOffset()
|
||||
: val() {
|
||||
FileOffset() :
|
||||
val() {
|
||||
// empty
|
||||
}
|
||||
uint64_t val;
|
||||
|
@ -154,7 +154,7 @@ public:
|
|||
resize(0);
|
||||
}
|
||||
|
||||
operator bool () const {
|
||||
operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
};
|
||||
|
@ -200,7 +200,7 @@ enum ErrorPolicy {
|
|||
};
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
# define ErrorPolicy_Igno ErrorPolicy_Warn
|
||||
#define ErrorPolicy_Igno ErrorPolicy_Warn
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -212,47 +212,42 @@ enum ErrorPolicy {
|
|||
* meaningful contents. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class Structure {
|
||||
template <template <typename> class> friend class ObjectCache;
|
||||
template <template <typename> class>
|
||||
friend class ObjectCache;
|
||||
|
||||
public:
|
||||
Structure()
|
||||
: cache_idx(static_cast<size_t>(-1) ){
|
||||
Structure() :
|
||||
cache_idx(static_cast<size_t>(-1)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// publicly accessible members
|
||||
std::string name;
|
||||
vector< Field > fields;
|
||||
vector<Field> fields;
|
||||
std::map<std::string, size_t> indices;
|
||||
|
||||
size_t size;
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Access a field of the structure by its canonical name. The pointer version
|
||||
* returns NULL on failure while the reference version raises an import error. */
|
||||
inline const Field& operator [] (const std::string& ss) const;
|
||||
inline const Field* Get (const std::string& ss) const;
|
||||
inline const Field &operator[](const std::string &ss) const;
|
||||
inline const Field *Get(const std::string &ss) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** 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
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
inline bool operator!= (const Structure& other) const {
|
||||
inline bool operator!=(const Structure &other) const {
|
||||
return name != other.name;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Try to read an instance of the structure from the stream
|
||||
* and attempt to convert to `T`. This is done by
|
||||
|
@ -260,38 +255,38 @@ public:
|
|||
* a compiler complain is the result.
|
||||
* @param dest Destination value to be written
|
||||
* @param db File database, including input stream. */
|
||||
template <typename T> void Convert (T& dest, const FileDatabase& db) const;
|
||||
template <typename T>
|
||||
void Convert(T &dest, const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// generic converter
|
||||
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
|
||||
template <typename T> std::shared_ptr<ElemBase> Allocate() const;
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<ElemBase> Allocate() const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// field parsing for 1d arrays
|
||||
template <int error_policy, typename T, size_t M>
|
||||
void ReadFieldArray(T (& out)[M], const char* name,
|
||||
const FileDatabase& db) const;
|
||||
void ReadFieldArray(T (&out)[M], const char *name,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// field parsing for 2d arrays
|
||||
template <int error_policy, typename T, size_t M, size_t N>
|
||||
void ReadFieldArray2(T (& out)[M][N], const char* name,
|
||||
const FileDatabase& db) const;
|
||||
void ReadFieldArray2(T (&out)[M][N], const char *name,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// field parsing for pointer or dynamic array types
|
||||
// (std::shared_ptr)
|
||||
// The return value indicates whether the data was already cached.
|
||||
template <int error_policy, template <typename> class TOUT, typename T>
|
||||
bool ReadFieldPtr(TOUT<T>& out, const char* name,
|
||||
const FileDatabase& db,
|
||||
bool ReadFieldPtr(TOUT<T> &out, const char *name,
|
||||
const FileDatabase &db,
|
||||
bool non_recursive = false) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
@ -299,15 +294,15 @@ public:
|
|||
// array types (std::shared_ptr[])
|
||||
// The return value indicates whether the data was already cached.
|
||||
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
|
||||
bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
|
||||
const FileDatabase& db) const;
|
||||
bool ReadFieldPtr(TOUT<T> (&out)[N], const char *name,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// field parsing for `normal` values
|
||||
// The return value indicates whether the data was already cached.
|
||||
template <int error_policy, typename T>
|
||||
void ReadField(T& out, const char* name,
|
||||
const FileDatabase& db) const;
|
||||
void ReadField(T &out, const char *name,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/**
|
||||
|
@ -318,7 +313,7 @@ public:
|
|||
* @return true when read was successful
|
||||
*/
|
||||
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
|
||||
|
@ -329,40 +324,40 @@ public:
|
|||
* @return true when read was successful
|
||||
*/
|
||||
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:
|
||||
|
||||
// --------------------------------------------------------
|
||||
template <template <typename> class TOUT, typename T>
|
||||
bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
|
||||
const FileDatabase& db, const Field& f,
|
||||
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>
|
||||
bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
|
||||
const FileDatabase& db, const Field& f, bool) const;
|
||||
bool ResolvePointer(vector<TOUT<T>> &out, const Pointer &ptrval,
|
||||
const FileDatabase &db, const Field &f, bool) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
|
||||
const FileDatabase& db, const Field& f, bool) const;
|
||||
bool ResolvePointer(std::shared_ptr<FileOffset> &out, const Pointer &ptrval,
|
||||
const FileDatabase &db, const Field &f, bool) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
inline const FileBlockHead* LocateFileBlockForAddress(
|
||||
const Pointer & ptrval,
|
||||
const FileDatabase& db) const;
|
||||
inline const FileBlockHead *LocateFileBlockForAddress(
|
||||
const Pointer &ptrval,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
private:
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
|
||||
template <typename T>
|
||||
T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
|
||||
out = std::shared_ptr<T>(new T());
|
||||
s = 1;
|
||||
return out.get();
|
||||
}
|
||||
|
||||
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
|
||||
template <typename T>
|
||||
T *_allocate(vector<T> &out, size_t &s) const {
|
||||
out.resize(s);
|
||||
return s ? &out.front() : NULL;
|
||||
}
|
||||
|
@ -372,14 +367,14 @@ private:
|
|||
struct _defaultInitializer {
|
||||
|
||||
template <typename T, unsigned int N>
|
||||
void operator ()(T (& out)[N], const char* = NULL) {
|
||||
void operator()(T (&out)[N], const char * = NULL) {
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
out[i] = T();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, unsigned int N, unsigned int M>
|
||||
void operator ()(T (& out)[N][M], const char* = NULL) {
|
||||
void operator()(T (&out)[N][M], const char * = NULL) {
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
for (unsigned int j = 0; j < M; ++j) {
|
||||
out[i][j] = T();
|
||||
|
@ -388,21 +383,21 @@ private:
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void operator ()(T& out, const char* = NULL) {
|
||||
void operator()(T &out, const char * = NULL) {
|
||||
out = T();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
mutable size_t cache_idx;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------
|
||||
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
|
||||
template <>
|
||||
struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
|
||||
|
||||
template <typename T>
|
||||
void operator ()(T& out, const char* reason = "<add reason>") {
|
||||
void operator()(T &out, const char *reason = "<add reason>") {
|
||||
ASSIMP_LOG_WARN(reason);
|
||||
|
||||
// ... 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>
|
||||
void operator ()(T& /*out*/,const char* = "") {
|
||||
void operator()(T & /*out*/, const char * = "") {
|
||||
// obviously, it is crucial that _DefaultInitializer is used
|
||||
// only from within a catch clause.
|
||||
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,
|
||||
const Pointer & ptrval,
|
||||
const FileDatabase& db,
|
||||
const Field& f,
|
||||
bool
|
||||
) const;
|
||||
|
||||
template <>
|
||||
inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
|
||||
const Pointer &ptrval,
|
||||
const FileDatabase &db,
|
||||
const Field &f,
|
||||
bool) const;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** 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
|
||||
* DNA is altered.*/
|
||||
// -------------------------------------------------------------------------------
|
||||
class DNA
|
||||
{
|
||||
class DNA {
|
||||
public:
|
||||
|
||||
typedef void (Structure::*ConvertProcPtr) (
|
||||
typedef void (Structure::*ConvertProcPtr)(
|
||||
std::shared_ptr<ElemBase> in,
|
||||
const FileDatabase&
|
||||
) const;
|
||||
const FileDatabase &) const;
|
||||
|
||||
typedef std::shared_ptr<ElemBase> (
|
||||
Structure::*AllocProcPtr) () const;
|
||||
Structure::*AllocProcPtr)() const;
|
||||
|
||||
typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
|
||||
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
|
||||
|
||||
public:
|
||||
|
||||
std::map<std::string, FactoryPair > converters;
|
||||
vector<Structure > structures;
|
||||
std::map<std::string, FactoryPair> converters;
|
||||
vector<Structure> structures;
|
||||
std::map<std::string, size_t> indices;
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Access a structure by its canonical name, the pointer version returns NULL on failure
|
||||
* while the reference version raises an error. */
|
||||
inline const Structure& operator [] (const std::string& ss) const;
|
||||
inline const Structure* Get (const std::string& ss) const;
|
||||
inline const Structure &operator[](const std::string &ss) const;
|
||||
inline const Structure *Get(const std::string &ss) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** 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:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Add structure definitions for all the primitive types,
|
||||
* i.e. integer, short, char, float */
|
||||
|
@ -483,7 +472,6 @@ public:
|
|||
* known at compile time (consier Object::data).*/
|
||||
void RegisterConverters();
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Take an input blob from the stream, interpret it according to
|
||||
* a its structure name and convert it to the intermediate
|
||||
|
@ -491,10 +479,9 @@ public:
|
|||
* @param structure Destination structure definition
|
||||
* @param db File database.
|
||||
* @return A null pointer if no appropriate converter is available.*/
|
||||
std::shared_ptr< ElemBase > ConvertBlobToStructure(
|
||||
const Structure& structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
std::shared_ptr<ElemBase> ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Find a suitable conversion function for a given Structure.
|
||||
|
@ -505,10 +492,8 @@ public:
|
|||
* @param db File database.
|
||||
* @return A null pointer in .first if no appropriate converter is available.*/
|
||||
FactoryPair GetBlobToStructureConverter(
|
||||
const Structure& structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
|
||||
const Structure &structure,
|
||||
const FileDatabase &db) const;
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
// --------------------------------------------------------
|
||||
|
@ -527,25 +512,29 @@ public:
|
|||
* @throw DeadlyImportError if more than 2 dimensions are
|
||||
* encountered. */
|
||||
static void ExtractArraySize(
|
||||
const std::string& out,
|
||||
size_t array_sizes[2]
|
||||
);
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]);
|
||||
};
|
||||
|
||||
// special converters for primitive types
|
||||
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<int>(int &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<short>(short &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<char>(char &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<float>(float &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<double>(double &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<Pointer>(Pointer &dest, const FileDatabase &db) const;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Describes a master file block header. Each master file sections holds n
|
||||
* elements of a certain SDNA structure (or otherwise unspecified data). */
|
||||
// -------------------------------------------------------------------------------
|
||||
struct FileBlockHead
|
||||
{
|
||||
struct FileBlockHead {
|
||||
// points right after the header of the file block
|
||||
StreamReaderAny::pos start;
|
||||
|
||||
|
@ -561,66 +550,55 @@ struct FileBlockHead
|
|||
// number of structure instances to follow
|
||||
size_t num;
|
||||
|
||||
|
||||
|
||||
// file blocks are sorted by address to quickly locate specific memory addresses
|
||||
bool operator < (const FileBlockHead& o) const {
|
||||
bool operator<(const FileBlockHead &o) const {
|
||||
return address.val < o.address.val;
|
||||
}
|
||||
|
||||
// for std::upper_bound
|
||||
operator const Pointer& () const {
|
||||
operator const Pointer &() const {
|
||||
return address;
|
||||
}
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Utility to read all master file blocks in turn. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class SectionParser
|
||||
{
|
||||
class SectionParser {
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** @param stream Inout stream, must point to the
|
||||
* first section in the file. Call Next() once
|
||||
* to have it read.
|
||||
* @param ptr64 Pointer size in file is 64 bits? */
|
||||
SectionParser(StreamReaderAny& stream,bool ptr64)
|
||||
: stream(stream)
|
||||
, ptr64(ptr64)
|
||||
{
|
||||
SectionParser(StreamReaderAny &stream, bool ptr64) :
|
||||
stream(stream), ptr64(ptr64) {
|
||||
current.size = current.start = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
const FileBlockHead& GetCurrent() const {
|
||||
const FileBlockHead &GetCurrent() const {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Advance to the next section.
|
||||
* @throw DeadlyImportError if the last chunk was passed. */
|
||||
void Next();
|
||||
|
||||
public:
|
||||
|
||||
FileBlockHead current;
|
||||
StreamReaderAny& stream;
|
||||
StreamReaderAny &stream;
|
||||
bool ptr64;
|
||||
};
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Import statistics, i.e. number of file blocks read*/
|
||||
|
@ -628,17 +606,13 @@ public:
|
|||
class Statistics {
|
||||
|
||||
public:
|
||||
|
||||
Statistics ()
|
||||
: fields_read ()
|
||||
, pointers_resolved ()
|
||||
, cache_hits ()
|
||||
// , blocks_read ()
|
||||
, cached_objects ()
|
||||
{}
|
||||
Statistics() :
|
||||
fields_read(), pointers_resolved(), cache_hits()
|
||||
// , blocks_read ()
|
||||
,
|
||||
cached_objects() {}
|
||||
|
||||
public:
|
||||
|
||||
/** total number of fields we read */
|
||||
unsigned int fields_read;
|
||||
|
||||
|
@ -662,17 +636,13 @@ public:
|
|||
* avoids circular references and avoids object duplication. */
|
||||
// -------------------------------------------------------------------------------
|
||||
template <template <typename> class TOUT>
|
||||
class ObjectCache
|
||||
{
|
||||
class ObjectCache {
|
||||
public:
|
||||
|
||||
typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
|
||||
typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
|
||||
|
||||
public:
|
||||
|
||||
ObjectCache(const FileDatabase& db)
|
||||
: db(db)
|
||||
{
|
||||
ObjectCache(const FileDatabase &db) :
|
||||
db(db) {
|
||||
// currently there are only ~400 structure records per blend file.
|
||||
// we read only a small part of them and don't cache objects
|
||||
// which we don't need, so this should suffice.
|
||||
|
@ -680,17 +650,17 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Check whether a specific item is in the cache.
|
||||
* @param s Data type of the item
|
||||
* @param out Output pointer. Unchanged if the
|
||||
* cache doesn't know the item yet.
|
||||
* @param ptr Item address to look for. */
|
||||
template <typename T> void get (
|
||||
const Structure& s,
|
||||
TOUT<T>& out,
|
||||
const Pointer& ptr) const;
|
||||
template <typename T>
|
||||
void get(
|
||||
const Structure &s,
|
||||
TOUT<T> &out,
|
||||
const Pointer &ptr) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Add an item to the cache after the item has
|
||||
|
@ -700,47 +670,44 @@ public:
|
|||
* @param s Data type of the item
|
||||
* @param out Item to insert into the cache
|
||||
* @param ptr address (cache key) of the item. */
|
||||
template <typename T> void set
|
||||
(const Structure& s,
|
||||
const TOUT<T>& out,
|
||||
const Pointer& ptr);
|
||||
template <typename T>
|
||||
void set(const Structure &s,
|
||||
const TOUT<T> &out,
|
||||
const Pointer &ptr);
|
||||
|
||||
private:
|
||||
|
||||
mutable vector<StructureCache> caches;
|
||||
const FileDatabase& db;
|
||||
const FileDatabase &db;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
template <> class ObjectCache<Blender::vector>
|
||||
{
|
||||
template <>
|
||||
class ObjectCache<Blender::vector> {
|
||||
public:
|
||||
ObjectCache(const FileDatabase &) {}
|
||||
|
||||
ObjectCache(const FileDatabase&) {}
|
||||
|
||||
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
|
||||
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
|
||||
template <typename T>
|
||||
void get(const Structure &, vector<T> &, const Pointer &) {}
|
||||
template <typename T>
|
||||
void set(const Structure &, const vector<T> &, const Pointer &) {}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4355)
|
||||
#pragma warning(disable : 4355)
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Memory representation of a full BLEND file and all its dependencies. The
|
||||
* output aiScene is constructed from an instance of this data structure. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class FileDatabase
|
||||
{
|
||||
template <template <typename> class TOUT> friend class ObjectCache;
|
||||
class FileDatabase {
|
||||
template <template <typename> class TOUT>
|
||||
friend class ObjectCache;
|
||||
|
||||
public:
|
||||
FileDatabase()
|
||||
: _cacheArrays(*this)
|
||||
, _cache(*this)
|
||||
, next_cache_idx()
|
||||
{}
|
||||
FileDatabase() :
|
||||
_cacheArrays(*this), _cache(*this), next_cache_idx() {}
|
||||
|
||||
public:
|
||||
// publicly accessible fields
|
||||
|
@ -748,12 +715,11 @@ public:
|
|||
bool little;
|
||||
|
||||
DNA dna;
|
||||
std::shared_ptr< StreamReaderAny > reader;
|
||||
vector< FileBlockHead > entries;
|
||||
std::shared_ptr<StreamReaderAny> reader;
|
||||
vector<FileBlockHead> entries;
|
||||
|
||||
public:
|
||||
|
||||
Statistics& stats() const {
|
||||
Statistics &stats() const {
|
||||
return _stats;
|
||||
}
|
||||
|
||||
|
@ -762,18 +728,16 @@ public:
|
|||
// arrays of objects are never cached because we can't easily
|
||||
// ensure their proper destruction.
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ObjectCache<vector>& cache(vector<T>& /*in*/) const {
|
||||
ObjectCache<vector> &cache(vector<T> & /*in*/) const {
|
||||
return _cacheArrays;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
mutable Statistics _stats;
|
||||
#endif
|
||||
|
@ -785,24 +749,20 @@ private:
|
|||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(default:4355)
|
||||
#pragma warning(default : 4355)
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class DNAParser
|
||||
{
|
||||
class DNAParser {
|
||||
|
||||
public:
|
||||
|
||||
/** Bind the parser to a empty DNA and an input stream */
|
||||
DNAParser(FileDatabase& db)
|
||||
: db(db)
|
||||
{}
|
||||
DNAParser(FileDatabase &db) :
|
||||
db(db) {}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Locate the DNA in the file and parse it. The input
|
||||
* stream is expected to point to the beginning of the DN1
|
||||
|
@ -811,18 +771,16 @@ public:
|
|||
* @throw DeadlyImportError if the DNA cannot be read.
|
||||
* @note The position of the stream pointer is undefined
|
||||
* afterwards.*/
|
||||
void Parse ();
|
||||
void Parse();
|
||||
|
||||
public:
|
||||
|
||||
/** Obtain a reference to the extracted DNA information */
|
||||
const Blender::DNA& GetDNA() const {
|
||||
const Blender::DNA &GetDNA() const {
|
||||
return db.dna;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
} // end Blend
|
||||
} // end Assimp
|
||||
} // namespace Blender
|
||||
} // namespace Assimp
|
||||
|
||||
#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
|
||||
{
|
||||
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);
|
||||
|
||||
zstream.next_in = reinterpret_cast<Bytef*>( reader->GetPtr() );
|
||||
zstream.avail_in = reader->GetRemainingSize();
|
||||
zstream.avail_in = (uInt) reader->GetRemainingSize();
|
||||
|
||||
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()));
|
||||
|
||||
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,
|
||||
// so we can extract the file extension from it.
|
||||
|
@ -439,19 +439,19 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
|||
--s;
|
||||
}
|
||||
|
||||
tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
|
||||
tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
|
||||
tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
|
||||
tex->achFormatHint[3] = '\0';
|
||||
curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
|
||||
curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
|
||||
curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
|
||||
curTex->achFormatHint[3] = '\0';
|
||||
|
||||
// tex->mHeight = 0;
|
||||
tex->mWidth = img->packedfile->size;
|
||||
uint8_t* ch = new uint8_t[tex->mWidth];
|
||||
curTex->mWidth = img->packedfile->size;
|
||||
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->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));
|
||||
} else {
|
||||
|
@ -1078,9 +1078,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
const aiFace& f = out->mFaces[out->mNumFaces++];
|
||||
|
||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
||||
vo->x = v->uv[i][0];
|
||||
vo->y = v->uv[i][1];
|
||||
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||
vo->x = v->uv[j][0];
|
||||
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->y = uv.uv[1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// create textureCoords for every mapped tex
|
||||
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++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++];
|
||||
|
||||
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
|
||||
for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
|
||||
vo->x = v->uv[i][0];
|
||||
vo->y = v->uv[i][1];
|
||||
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
|
||||
vo->x = v->uv[j][0];
|
||||
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::Blender;
|
||||
|
||||
template <typename T> BlenderModifier* god() {
|
||||
template <typename T>
|
||||
BlenderModifier *god() {
|
||||
return new T();
|
||||
}
|
||||
|
||||
// add all available modifiers here
|
||||
typedef BlenderModifier* (*fpCreateModifier)();
|
||||
typedef BlenderModifier *(*fpCreateModifier)();
|
||||
static const fpCreateModifier creators[] = {
|
||||
&god<BlenderModifier_Mirror>,
|
||||
&god<BlenderModifier_Subdivision>,
|
||||
|
||||
NULL // sentinel
|
||||
nullptr // sentinel
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct SharedModifierData : ElemBase
|
||||
{
|
||||
struct SharedModifierData : ElemBase {
|
||||
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;
|
||||
|
||||
// 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
|
||||
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
||||
// structures is at offset sizeof(vftable) with no padding.
|
||||
const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
|
||||
for (; cur; cur = static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
|
||||
const SharedModifierData *cur = static_cast<const SharedModifierData *>(orig_object.modifiers.first.get());
|
||||
for (; cur; cur = static_cast<const SharedModifierData *>(cur->modifier.next.get()), ++ful) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
||||
continue;
|
||||
}
|
||||
|
||||
s = conv_data.db.dna.Get( f->type );
|
||||
s = conv_data.db.dna.Get(f->type);
|
||||
if (!s || s->name != "ModifierData") {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
||||
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
|
||||
// ModifierData (with the above note).
|
||||
const ModifierData& dat = cur->modifier;
|
||||
const ModifierData &dat = cur->modifier;
|
||||
|
||||
const fpCreateModifier* curgod = creators;
|
||||
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
||||
const fpCreateModifier *curgod = creators;
|
||||
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) {
|
||||
cached_modifiers->push_back((*curgod)());
|
||||
|
||||
endmod = cached_modifiers->end();
|
||||
curmod = endmod-1;
|
||||
curmod = endmod - 1;
|
||||
}
|
||||
|
||||
BlenderModifier* const modifier = *curmod;
|
||||
if(modifier->IsActive(dat)) {
|
||||
modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
|
||||
BlenderModifier *const modifier = *curmod;
|
||||
if (modifier->IsActive(dat)) {
|
||||
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
|
||||
cnt++;
|
||||
|
||||
curgod = NULL;
|
||||
curgod = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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
|
||||
// able to fully do their job.
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
|
||||
{
|
||||
bool BlenderModifier_Mirror ::IsActive(const ModifierData &modin) {
|
||||
return modin.type == ModifierData::eModifierType_Mirror;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
{
|
||||
void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||
const Scene & /*in*/,
|
||||
const Object &orig_object) {
|
||||
// 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);
|
||||
|
||||
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
|
||||
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
||||
aiMesh* mesh;
|
||||
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
|
||||
aiMesh *mesh;
|
||||
SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]);
|
||||
|
||||
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 zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
||||
|
||||
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] );
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]);
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mVertices[j];
|
||||
|
||||
v.x = center.x + xs*(center.x - v.x);
|
||||
v.y = center.y + ys*(center.y - v.y);
|
||||
v.z = center.z + zs*(center.z - v.z);
|
||||
v.x = center.x + xs * (center.x - v.x);
|
||||
v.y = center.y + ys * (center.y - v.y);
|
||||
v.z = center.z + zs * (center.z - v.z);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
} else {
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mVertices[j];
|
||||
v.x *= xs;
|
||||
v.y *= ys;
|
||||
v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mNormals) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mNormals[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mNormals[j];
|
||||
v.x *= xs;
|
||||
v.y *= ys;
|
||||
v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mTangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mTangents[j];
|
||||
v.x *= xs;
|
||||
v.y *= ys;
|
||||
v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mBitangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mBitangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mBitangents[j];
|
||||
v.x *= xs;
|
||||
v.y *= ys;
|
||||
v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,27 +220,28 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
|||
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 i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTextureCoords[n][i];
|
||||
v.x *= us;v.y *= vs;
|
||||
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
|
||||
aiVector3D &v = mesh->mTextureCoords[n][j];
|
||||
v.x *= us;
|
||||
v.y *= vs;
|
||||
}
|
||||
}
|
||||
|
||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||
if (xs * ys * zs < 0) {
|
||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace& face = mesh->mFaces[i];
|
||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||
for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
|
||||
aiFace &face = mesh->mFaces[j];
|
||||
for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||
std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||
}
|
||||
}
|
||||
|
||||
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::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
|
||||
std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind);
|
||||
std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes,
|
||||
[&out](unsigned int n) { return out.mNumMeshes + n; });
|
||||
|
||||
delete[] out.mMeshes;
|
||||
|
@ -246,27 +249,24 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
|||
out.mNumMeshes *= 2;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
{
|
||||
void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier,
|
||||
const Scene & /*in*/,
|
||||
const Object &orig_object) {
|
||||
// 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);
|
||||
|
||||
Subdivider::Algorithm algo;
|
||||
switch (mir.subdivType)
|
||||
{
|
||||
switch (mir.subdivType) {
|
||||
case SubsurfModifierData::TYPE_CatmullClarke:
|
||||
algo = Subdivider::CATMULL_CLARKE;
|
||||
break;
|
||||
|
@ -277,23 +277,23 @@ void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
|
|||
break;
|
||||
|
||||
default:
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
|
||||
return;
|
||||
};
|
||||
|
||||
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
|
||||
ai_assert(subd);
|
||||
if ( conv_data.meshes->empty() ) {
|
||||
if (conv_data.meshes->empty()) {
|
||||
return;
|
||||
}
|
||||
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
||||
std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
|
||||
aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - 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);
|
||||
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
|
||||
subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
|
||||
std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
|
||||
|
||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
||||
orig_object.id.name,"`");
|
||||
orig_object.id.name, "`");
|
||||
}
|
||||
|
||||
#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
|
|
@ -55,7 +55,6 @@ namespace Blender {
|
|||
// declared in the ./source/blender/makesdna directory.
|
||||
// Stuff that is not used by Assimp is commented.
|
||||
|
||||
|
||||
// NOTE
|
||||
// this file serves as input data to the `./scripts/genblenddna.py`
|
||||
// script. This script generates the actual binding code to read a
|
||||
|
@ -95,13 +94,13 @@ namespace Blender {
|
|||
|
||||
// warn if field is missing, substitute default value
|
||||
#ifdef WARN
|
||||
# undef WARN
|
||||
#undef WARN
|
||||
#endif
|
||||
#define WARN
|
||||
|
||||
// fail the import if the field does not exist
|
||||
#ifdef FAIL
|
||||
# undef FAIL
|
||||
#undef FAIL
|
||||
#endif
|
||||
#define FAIL
|
||||
|
||||
|
@ -117,7 +116,7 @@ static const size_t MaxNameLen = 1024;
|
|||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct ID : ElemBase {
|
||||
char name[ MaxNameLen ] WARN;
|
||||
char name[MaxNameLen] WARN;
|
||||
short flag;
|
||||
};
|
||||
|
||||
|
@ -127,17 +126,16 @@ struct ListBase : ElemBase {
|
|||
std::shared_ptr<ElemBase> last;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct PackedFile : ElemBase {
|
||||
int size WARN;
|
||||
int seek WARN;
|
||||
std::shared_ptr< FileOffset > data WARN;
|
||||
std::shared_ptr<FileOffset> data WARN;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct GroupObject : ElemBase {
|
||||
std::shared_ptr<GroupObject> prev,next FAIL;
|
||||
std::shared_ptr<GroupObject> prev, next FAIL;
|
||||
std::shared_ptr<Object> ob;
|
||||
};
|
||||
|
||||
|
@ -162,11 +160,8 @@ struct MVert : ElemBase {
|
|||
int mat_nr WARN;
|
||||
int bweight;
|
||||
|
||||
MVert() : ElemBase()
|
||||
, flag(0)
|
||||
, mat_nr(0)
|
||||
, bweight(0)
|
||||
{}
|
||||
MVert() :
|
||||
ElemBase(), flag(0), mat_nr(0), bweight(0) {}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -203,19 +198,19 @@ struct MPoly : ElemBase {
|
|||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MTexPoly : ElemBase {
|
||||
Image* tpage;
|
||||
Image *tpage;
|
||||
char flag, transp;
|
||||
short mode, tile, pad;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MCol : ElemBase {
|
||||
char r,g,b,a FAIL;
|
||||
char r, g, b, a FAIL;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MFace : ElemBase {
|
||||
int v1,v2,v3,v4 FAIL;
|
||||
int v1, v2, v3, v4 FAIL;
|
||||
int mat_nr FAIL;
|
||||
char flag;
|
||||
};
|
||||
|
@ -232,12 +227,8 @@ struct TFace : ElemBase {
|
|||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MTFace : ElemBase {
|
||||
MTFace()
|
||||
: flag(0)
|
||||
, mode(0)
|
||||
, tile(0)
|
||||
, unwrap(0)
|
||||
{
|
||||
MTFace() :
|
||||
flag(0), mode(0), tile(0), unwrap(0) {
|
||||
}
|
||||
|
||||
float uv[4][2] FAIL;
|
||||
|
@ -270,11 +261,11 @@ struct MDeformVert : ElemBase {
|
|||
struct Material : ElemBase {
|
||||
ID id FAIL;
|
||||
|
||||
float r,g,b WARN;
|
||||
float specr,specg,specb WARN;
|
||||
float r, g, b WARN;
|
||||
float specr, specg, specb WARN;
|
||||
short har;
|
||||
float ambr,ambg,ambb WARN;
|
||||
float mirr,mirg,mirb;
|
||||
float ambr, ambg, ambb WARN;
|
||||
float mirr, mirg, mirb;
|
||||
float emit WARN;
|
||||
float ray_mirror;
|
||||
float alpha WARN;
|
||||
|
@ -401,18 +392,17 @@ struct CustomDataLayer : ElemBase {
|
|||
char name[64];
|
||||
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
|
||||
|
||||
CustomDataLayer()
|
||||
: ElemBase()
|
||||
, type(0)
|
||||
, offset(0)
|
||||
, flag(0)
|
||||
, active(0)
|
||||
, active_rnd(0)
|
||||
, active_clone(0)
|
||||
, active_mask(0)
|
||||
, uid(0)
|
||||
, data(nullptr)
|
||||
{
|
||||
CustomDataLayer() :
|
||||
ElemBase(),
|
||||
type(0),
|
||||
offset(0),
|
||||
flag(0),
|
||||
active(0),
|
||||
active_rnd(0),
|
||||
active_clone(0),
|
||||
active_mask(0),
|
||||
uid(0),
|
||||
data(nullptr) {
|
||||
memset(name, 0, sizeof name);
|
||||
}
|
||||
};
|
||||
|
@ -430,7 +420,7 @@ CustomData 208
|
|||
CustomDataExternal *external 200 8
|
||||
*/
|
||||
struct CustomData : ElemBase {
|
||||
vector<std::shared_ptr<struct CustomDataLayer> > layers;
|
||||
vector<std::shared_ptr<struct CustomDataLayer>> layers;
|
||||
int typemap[42]; // CD_NUMTYPES
|
||||
int totlayer;
|
||||
int maxlayer;
|
||||
|
@ -469,7 +459,7 @@ struct Mesh : ElemBase {
|
|||
vector<MDeformVert> dvert;
|
||||
vector<MCol> mcol;
|
||||
|
||||
vector< std::shared_ptr<Material> > mat FAIL;
|
||||
vector<std::shared_ptr<Material>> mat FAIL;
|
||||
|
||||
struct CustomData vdata;
|
||||
struct CustomData edata;
|
||||
|
@ -490,36 +480,35 @@ struct Library : ElemBase {
|
|||
// -------------------------------------------------------------------------------
|
||||
struct Camera : ElemBase {
|
||||
enum Type {
|
||||
Type_PERSP = 0
|
||||
,Type_ORTHO = 1
|
||||
Type_PERSP = 0,
|
||||
Type_ORTHO = 1
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
|
||||
Type type,flag WARN;
|
||||
Type type, flag WARN;
|
||||
float lens WARN;
|
||||
float sensor_x WARN;
|
||||
float clipsta, clipend;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Lamp : ElemBase {
|
||||
|
||||
enum FalloffType {
|
||||
FalloffType_Constant = 0x0
|
||||
,FalloffType_InvLinear = 0x1
|
||||
,FalloffType_InvSquare = 0x2
|
||||
FalloffType_Constant = 0x0,
|
||||
FalloffType_InvLinear = 0x1,
|
||||
FalloffType_InvSquare = 0x2
|
||||
//,FalloffType_Curve = 0x3
|
||||
//,FalloffType_Sliders = 0x4
|
||||
};
|
||||
|
||||
enum Type {
|
||||
Type_Local = 0x0
|
||||
,Type_Sun = 0x1
|
||||
,Type_Spot = 0x2
|
||||
,Type_Hemi = 0x3
|
||||
,Type_Area = 0x4
|
||||
Type_Local = 0x0,
|
||||
Type_Sun = 0x1,
|
||||
Type_Spot = 0x2,
|
||||
Type_Hemi = 0x3,
|
||||
Type_Area = 0x4
|
||||
//,Type_YFPhoton = 0x5
|
||||
};
|
||||
|
||||
|
@ -532,7 +521,7 @@ struct Lamp : ElemBase {
|
|||
//int mode;
|
||||
|
||||
short colormodel, totex;
|
||||
float r,g,b,k WARN;
|
||||
float r, g, b, k WARN;
|
||||
//float shdwr, shdwg, shdwb;
|
||||
|
||||
float energy, dist, spotsize, spotblend;
|
||||
|
@ -646,13 +635,13 @@ struct SubsurfModifierData : ElemBase {
|
|||
|
||||
enum Flags {
|
||||
// some omitted
|
||||
FLAGS_SubsurfUV =1<<3
|
||||
FLAGS_SubsurfUV = 1 << 3
|
||||
};
|
||||
|
||||
ModifierData modifier FAIL;
|
||||
short subdivType WARN;
|
||||
short levels FAIL;
|
||||
short renderLevels ;
|
||||
short renderLevels;
|
||||
short flags;
|
||||
};
|
||||
|
||||
|
@ -660,13 +649,13 @@ struct SubsurfModifierData : ElemBase {
|
|||
struct MirrorModifierData : ElemBase {
|
||||
|
||||
enum Flags {
|
||||
Flags_CLIPPING =1<<0,
|
||||
Flags_MIRROR_U =1<<1,
|
||||
Flags_MIRROR_V =1<<2,
|
||||
Flags_AXIS_X =1<<3,
|
||||
Flags_AXIS_Y =1<<4,
|
||||
Flags_AXIS_Z =1<<5,
|
||||
Flags_VGROUP =1<<6
|
||||
Flags_CLIPPING = 1 << 0,
|
||||
Flags_MIRROR_U = 1 << 1,
|
||||
Flags_MIRROR_V = 1 << 2,
|
||||
Flags_AXIS_X = 1 << 3,
|
||||
Flags_AXIS_Y = 1 << 4,
|
||||
Flags_AXIS_Z = 1 << 5,
|
||||
Flags_VGROUP = 1 << 6
|
||||
};
|
||||
|
||||
ModifierData modifier FAIL;
|
||||
|
@ -681,18 +670,20 @@ struct Object : ElemBase {
|
|||
ID id FAIL;
|
||||
|
||||
enum Type {
|
||||
Type_EMPTY = 0
|
||||
,Type_MESH = 1
|
||||
,Type_CURVE = 2
|
||||
,Type_SURF = 3
|
||||
,Type_FONT = 4
|
||||
,Type_MBALL = 5
|
||||
Type_EMPTY = 0,
|
||||
Type_MESH = 1,
|
||||
Type_CURVE = 2,
|
||||
Type_SURF = 3,
|
||||
Type_FONT = 4,
|
||||
Type_MBALL = 5
|
||||
|
||||
,Type_LAMP = 10
|
||||
,Type_CAMERA = 11
|
||||
,
|
||||
Type_LAMP = 10,
|
||||
Type_CAMERA = 11
|
||||
|
||||
,Type_WAVE = 21
|
||||
,Type_LATTICE = 22
|
||||
,
|
||||
Type_WAVE = 21,
|
||||
Type_LATTICE = 22
|
||||
};
|
||||
|
||||
Type type FAIL;
|
||||
|
@ -700,39 +691,29 @@ struct Object : ElemBase {
|
|||
float parentinv[4][4] WARN;
|
||||
char parsubstr[32] WARN;
|
||||
|
||||
Object* parent WARN;
|
||||
Object *parent 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<ElemBase> data FAIL;
|
||||
|
||||
ListBase modifiers;
|
||||
|
||||
Object()
|
||||
: ElemBase()
|
||||
, type( Type_EMPTY )
|
||||
, parent( nullptr )
|
||||
, track()
|
||||
, proxy()
|
||||
, proxy_from()
|
||||
, data() {
|
||||
Object() :
|
||||
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Base : ElemBase {
|
||||
Base* prev WARN;
|
||||
Base *prev WARN;
|
||||
std::shared_ptr<Base> next WARN;
|
||||
std::shared_ptr<Object> object WARN;
|
||||
|
||||
Base()
|
||||
: ElemBase()
|
||||
, prev( nullptr )
|
||||
, next()
|
||||
, object() {
|
||||
Base() :
|
||||
ElemBase(), prev(nullptr), next(), object() {
|
||||
// empty
|
||||
// empty
|
||||
}
|
||||
|
@ -748,11 +729,8 @@ struct Scene : ElemBase {
|
|||
|
||||
ListBase base;
|
||||
|
||||
Scene()
|
||||
: ElemBase()
|
||||
, camera()
|
||||
, world()
|
||||
, basact() {
|
||||
Scene() :
|
||||
ElemBase(), camera(), world(), basact() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -784,8 +762,8 @@ struct Image : ElemBase {
|
|||
|
||||
short gen_x, gen_y, gen_type;
|
||||
|
||||
Image()
|
||||
: ElemBase() {
|
||||
Image() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -795,33 +773,33 @@ struct Tex : ElemBase {
|
|||
|
||||
// actually, the only texture type we support is Type_IMAGE
|
||||
enum Type {
|
||||
Type_CLOUDS = 1
|
||||
,Type_WOOD = 2
|
||||
,Type_MARBLE = 3
|
||||
,Type_MAGIC = 4
|
||||
,Type_BLEND = 5
|
||||
,Type_STUCCI = 6
|
||||
,Type_NOISE = 7
|
||||
,Type_IMAGE = 8
|
||||
,Type_PLUGIN = 9
|
||||
,Type_ENVMAP = 10
|
||||
,Type_MUSGRAVE = 11
|
||||
,Type_VORONOI = 12
|
||||
,Type_DISTNOISE = 13
|
||||
,Type_POINTDENSITY = 14
|
||||
,Type_VOXELDATA = 15
|
||||
Type_CLOUDS = 1,
|
||||
Type_WOOD = 2,
|
||||
Type_MARBLE = 3,
|
||||
Type_MAGIC = 4,
|
||||
Type_BLEND = 5,
|
||||
Type_STUCCI = 6,
|
||||
Type_NOISE = 7,
|
||||
Type_IMAGE = 8,
|
||||
Type_PLUGIN = 9,
|
||||
Type_ENVMAP = 10,
|
||||
Type_MUSGRAVE = 11,
|
||||
Type_VORONOI = 12,
|
||||
Type_DISTNOISE = 13,
|
||||
Type_POINTDENSITY = 14,
|
||||
Type_VOXELDATA = 15
|
||||
};
|
||||
|
||||
enum ImageFlags {
|
||||
ImageFlags_INTERPOL = 1
|
||||
,ImageFlags_USEALPHA = 2
|
||||
,ImageFlags_MIPMAP = 4
|
||||
,ImageFlags_IMAROT = 16
|
||||
,ImageFlags_CALCALPHA = 32
|
||||
,ImageFlags_NORMALMAP = 2048
|
||||
,ImageFlags_GAUSS_MIP = 4096
|
||||
,ImageFlags_FILTER_MIN = 8192
|
||||
,ImageFlags_DERIVATIVEMAP = 16384
|
||||
ImageFlags_INTERPOL = 1,
|
||||
ImageFlags_USEALPHA = 2,
|
||||
ImageFlags_MIPMAP = 4,
|
||||
ImageFlags_IMAROT = 16,
|
||||
ImageFlags_CALCALPHA = 32,
|
||||
ImageFlags_NORMALMAP = 2048,
|
||||
ImageFlags_GAUSS_MIP = 4096,
|
||||
ImageFlags_FILTER_MIN = 8192,
|
||||
ImageFlags_DERIVATIVEMAP = 16384
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
|
@ -876,11 +854,8 @@ struct Tex : ElemBase {
|
|||
|
||||
//char use_nodes;
|
||||
|
||||
Tex()
|
||||
: ElemBase()
|
||||
, imaflag( ImageFlags_INTERPOL )
|
||||
, type( Type_CLOUDS )
|
||||
, ima() {
|
||||
Tex() :
|
||||
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -889,52 +864,52 @@ struct Tex : ElemBase {
|
|||
struct MTex : ElemBase {
|
||||
|
||||
enum Projection {
|
||||
Proj_N = 0
|
||||
,Proj_X = 1
|
||||
,Proj_Y = 2
|
||||
,Proj_Z = 3
|
||||
Proj_N = 0,
|
||||
Proj_X = 1,
|
||||
Proj_Y = 2,
|
||||
Proj_Z = 3
|
||||
};
|
||||
|
||||
enum Flag {
|
||||
Flag_RGBTOINT = 0x1
|
||||
,Flag_STENCIL = 0x2
|
||||
,Flag_NEGATIVE = 0x4
|
||||
,Flag_ALPHAMIX = 0x8
|
||||
,Flag_VIEWSPACE = 0x10
|
||||
Flag_RGBTOINT = 0x1,
|
||||
Flag_STENCIL = 0x2,
|
||||
Flag_NEGATIVE = 0x4,
|
||||
Flag_ALPHAMIX = 0x8,
|
||||
Flag_VIEWSPACE = 0x10
|
||||
};
|
||||
|
||||
enum BlendType {
|
||||
BlendType_BLEND = 0
|
||||
,BlendType_MUL = 1
|
||||
,BlendType_ADD = 2
|
||||
,BlendType_SUB = 3
|
||||
,BlendType_DIV = 4
|
||||
,BlendType_DARK = 5
|
||||
,BlendType_DIFF = 6
|
||||
,BlendType_LIGHT = 7
|
||||
,BlendType_SCREEN = 8
|
||||
,BlendType_OVERLAY = 9
|
||||
,BlendType_BLEND_HUE = 10
|
||||
,BlendType_BLEND_SAT = 11
|
||||
,BlendType_BLEND_VAL = 12
|
||||
,BlendType_BLEND_COLOR = 13
|
||||
BlendType_BLEND = 0,
|
||||
BlendType_MUL = 1,
|
||||
BlendType_ADD = 2,
|
||||
BlendType_SUB = 3,
|
||||
BlendType_DIV = 4,
|
||||
BlendType_DARK = 5,
|
||||
BlendType_DIFF = 6,
|
||||
BlendType_LIGHT = 7,
|
||||
BlendType_SCREEN = 8,
|
||||
BlendType_OVERLAY = 9,
|
||||
BlendType_BLEND_HUE = 10,
|
||||
BlendType_BLEND_SAT = 11,
|
||||
BlendType_BLEND_VAL = 12,
|
||||
BlendType_BLEND_COLOR = 13
|
||||
};
|
||||
|
||||
enum MapType {
|
||||
MapType_COL = 1
|
||||
,MapType_NORM = 2
|
||||
,MapType_COLSPEC = 4
|
||||
,MapType_COLMIR = 8
|
||||
,MapType_REF = 16
|
||||
,MapType_SPEC = 32
|
||||
,MapType_EMIT = 64
|
||||
,MapType_ALPHA = 128
|
||||
,MapType_HAR = 256
|
||||
,MapType_RAYMIRR = 512
|
||||
,MapType_TRANSLU = 1024
|
||||
,MapType_AMB = 2048
|
||||
,MapType_DISPLACE = 4096
|
||||
,MapType_WARP = 8192
|
||||
MapType_COL = 1,
|
||||
MapType_NORM = 2,
|
||||
MapType_COLSPEC = 4,
|
||||
MapType_COLMIR = 8,
|
||||
MapType_REF = 16,
|
||||
MapType_SPEC = 32,
|
||||
MapType_EMIT = 64,
|
||||
MapType_ALPHA = 128,
|
||||
MapType_HAR = 256,
|
||||
MapType_RAYMIRR = 512,
|
||||
MapType_TRANSLU = 1024,
|
||||
MapType_AMB = 2048,
|
||||
MapType_DISPLACE = 4096,
|
||||
MapType_WARP = 8192
|
||||
};
|
||||
|
||||
// short texco, maptoneg;
|
||||
|
@ -945,7 +920,7 @@ struct MTex : ElemBase {
|
|||
std::shared_ptr<Tex> tex;
|
||||
char uvname[32];
|
||||
|
||||
Projection projx,projy,projz;
|
||||
Projection projx, projy, projz;
|
||||
char mapping;
|
||||
float ofs[3], size[3], rot;
|
||||
|
||||
|
@ -953,7 +928,7 @@ struct MTex : ElemBase {
|
|||
short colormodel, pmapto, pmaptoneg;
|
||||
//short normapspace, which_output;
|
||||
//char brush_map_mode;
|
||||
float r,g,b,k WARN;
|
||||
float r, g, b, k WARN;
|
||||
//float def_var, rt;
|
||||
|
||||
//float colfac, varfac;
|
||||
|
@ -972,12 +947,12 @@ struct MTex : ElemBase {
|
|||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
|
||||
MTex()
|
||||
: ElemBase() {
|
||||
MTex() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Blender
|
||||
} // namespace Assimp
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -75,10 +75,10 @@ struct Face
|
|||
|
||||
// ------------------
|
||||
/** COB chunk header information */
|
||||
const unsigned int NO_SIZE = UINT_MAX;
|
||||
|
||||
struct ChunkInfo
|
||||
{
|
||||
enum {NO_SIZE=UINT_MAX};
|
||||
|
||||
ChunkInfo ()
|
||||
: id (0)
|
||||
, parent_id (0)
|
|
@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
|||
*ot++ = *buffer++;
|
||||
|
||||
*ot = '\0';
|
||||
nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
|
||||
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
|
||||
}
|
||||
|
||||
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <assimp/commonMetaData.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/commonMetaData.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Collada {
|
||||
|
@ -63,39 +63,32 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
|
|||
|
||||
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
|
||||
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
|
||||
for (auto &val : result)
|
||||
{
|
||||
for (auto &val : result) {
|
||||
ToCamelCase(val.first);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
|
||||
{
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
|
||||
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
|
||||
void ToCamelCase(std::string &text)
|
||||
{
|
||||
void ToCamelCase(std::string &text) {
|
||||
if (text.empty())
|
||||
return;
|
||||
// Capitalise first character
|
||||
auto it = text.begin();
|
||||
(*it) = ToUpper(*it);
|
||||
++it;
|
||||
for (/*started above*/ ; it != text.end(); /*iterated below*/)
|
||||
{
|
||||
if ((*it) == '_')
|
||||
{
|
||||
for (/*started above*/; it != text.end(); /*iterated below*/) {
|
||||
if ((*it) == '_') {
|
||||
it = text.erase(it);
|
||||
if (it != text.end())
|
||||
(*it) = ToUpper(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make lower case
|
||||
(*it) = ToLower(*it);
|
||||
++it;
|
|
@ -45,13 +45,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AI_COLLADAHELPER_H_INC
|
||||
#define AI_COLLADAHELPER_H_INC
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <assimp/light.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
struct aiMaterial;
|
||||
|
||||
|
@ -59,17 +59,14 @@ namespace Assimp {
|
|||
namespace Collada {
|
||||
|
||||
/** Collada file versions which evolved during the years ... */
|
||||
enum FormatVersion
|
||||
{
|
||||
enum FormatVersion {
|
||||
FV_1_5_n,
|
||||
FV_1_4_n,
|
||||
FV_1_3_n
|
||||
};
|
||||
|
||||
|
||||
/** Transformation types that can be applied to a node */
|
||||
enum TransformType
|
||||
{
|
||||
enum TransformType {
|
||||
TF_LOOKAT,
|
||||
TF_ROTATE,
|
||||
TF_TRANSLATE,
|
||||
|
@ -79,8 +76,7 @@ enum TransformType
|
|||
};
|
||||
|
||||
/** Different types of input data to a vertex or face */
|
||||
enum InputType
|
||||
{
|
||||
enum InputType {
|
||||
IT_Invalid,
|
||||
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
||||
IT_Position,
|
||||
|
@ -92,15 +88,13 @@ enum InputType
|
|||
};
|
||||
|
||||
/** Supported controller types */
|
||||
enum ControllerType
|
||||
{
|
||||
enum ControllerType {
|
||||
Skin,
|
||||
Morph
|
||||
};
|
||||
|
||||
/** Supported morph methods */
|
||||
enum MorphMethod
|
||||
{
|
||||
enum MorphMethod {
|
||||
Normalized,
|
||||
Relative
|
||||
};
|
||||
|
@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
|
|||
void ToCamelCase(std::string &text);
|
||||
|
||||
/** 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
|
||||
TransformType mType;
|
||||
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
|
||||
};
|
||||
|
||||
/** A collada camera. */
|
||||
struct Camera
|
||||
{
|
||||
Camera()
|
||||
: mOrtho (false)
|
||||
, mHorFov (10e10f)
|
||||
, mVerFov (10e10f)
|
||||
, mAspect (10e10f)
|
||||
, mZNear (0.1f)
|
||||
, mZFar (1000.f)
|
||||
{}
|
||||
struct Camera {
|
||||
Camera() :
|
||||
mOrtho(false),
|
||||
mHorFov(10e10f),
|
||||
mVerFov(10e10f),
|
||||
mAspect(10e10f),
|
||||
mZNear(0.1f),
|
||||
mZFar(1000.f) {}
|
||||
|
||||
// Name of camera
|
||||
std::string mName;
|
||||
|
@ -159,19 +150,17 @@ struct Camera
|
|||
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
|
||||
|
||||
/** A collada light source. */
|
||||
struct Light
|
||||
{
|
||||
Light()
|
||||
: mType (aiLightSource_UNDEFINED)
|
||||
, mAttConstant (1.f)
|
||||
, mAttLinear (0.f)
|
||||
, mAttQuadratic (0.f)
|
||||
, mFalloffAngle (180.f)
|
||||
, mFalloffExponent (0.f)
|
||||
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mIntensity (1.f)
|
||||
{}
|
||||
struct Light {
|
||||
Light() :
|
||||
mType(aiLightSource_UNDEFINED),
|
||||
mAttConstant(1.f),
|
||||
mAttLinear(0.f),
|
||||
mAttQuadratic(0.f),
|
||||
mFalloffAngle(180.f),
|
||||
mFalloffExponent(0.f),
|
||||
mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
|
||||
mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
|
||||
mIntensity(1.f) {}
|
||||
|
||||
//! Type of the light source aiLightSourceType + ambient
|
||||
unsigned int mType;
|
||||
|
@ -180,7 +169,7 @@ struct Light
|
|||
aiColor3D mColor;
|
||||
|
||||
//! Light attenuation
|
||||
ai_real mAttConstant,mAttLinear,mAttQuadratic;
|
||||
ai_real mAttConstant, mAttLinear, mAttQuadratic;
|
||||
|
||||
//! Spot light falloff
|
||||
ai_real mFalloffAngle;
|
||||
|
@ -198,12 +187,10 @@ struct Light
|
|||
};
|
||||
|
||||
/** Short vertex index description */
|
||||
struct InputSemanticMapEntry
|
||||
{
|
||||
InputSemanticMapEntry()
|
||||
: mSet(0)
|
||||
, mType(IT_Invalid)
|
||||
{}
|
||||
struct InputSemanticMapEntry {
|
||||
InputSemanticMapEntry() :
|
||||
mSet(0),
|
||||
mType(IT_Invalid) {}
|
||||
|
||||
//! Index of set, optional
|
||||
unsigned int mSet;
|
||||
|
@ -213,8 +200,7 @@ struct InputSemanticMapEntry
|
|||
};
|
||||
|
||||
/** Table to map from effect to vertex input semantics */
|
||||
struct SemanticMappingTable
|
||||
{
|
||||
struct SemanticMappingTable {
|
||||
//! Name of material
|
||||
std::string mMatName;
|
||||
|
||||
|
@ -222,7 +208,7 @@ struct SemanticMappingTable
|
|||
std::map<std::string, InputSemanticMapEntry> mMap;
|
||||
|
||||
//! For std::find
|
||||
bool operator == (const std::string& s) const {
|
||||
bool operator==(const std::string &s) const {
|
||||
return s == mMatName;
|
||||
}
|
||||
};
|
||||
|
@ -230,8 +216,7 @@ struct SemanticMappingTable
|
|||
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
|
||||
* The ID refers to either a mesh or a controller which specifies the mesh
|
||||
*/
|
||||
struct MeshInstance
|
||||
{
|
||||
struct MeshInstance {
|
||||
///< ID of the mesh or controller to be instanced
|
||||
std::string mMeshOrController;
|
||||
|
||||
|
@ -240,34 +225,30 @@ struct MeshInstance
|
|||
};
|
||||
|
||||
/** A reference to a camera inside a node*/
|
||||
struct CameraInstance
|
||||
{
|
||||
struct CameraInstance {
|
||||
///< ID of the camera
|
||||
std::string mCamera;
|
||||
};
|
||||
|
||||
/** A reference to a light inside a node*/
|
||||
struct LightInstance
|
||||
{
|
||||
struct LightInstance {
|
||||
///< ID of the camera
|
||||
std::string mLight;
|
||||
};
|
||||
|
||||
/** A reference to a node inside a node*/
|
||||
struct NodeInstance
|
||||
{
|
||||
struct NodeInstance {
|
||||
///< ID of the node
|
||||
std::string mNode;
|
||||
};
|
||||
|
||||
/** A node in a scene hierarchy */
|
||||
struct Node
|
||||
{
|
||||
struct Node {
|
||||
std::string mName;
|
||||
std::string mID;
|
||||
std::string mSID;
|
||||
Node* mParent;
|
||||
std::vector<Node*> mChildren;
|
||||
Node *mParent;
|
||||
std::vector<Node *> mChildren;
|
||||
|
||||
/** Operations in order to calculate the resulting transformation to parent. */
|
||||
std::vector<Transform> mTransforms;
|
||||
|
@ -288,29 +269,27 @@ struct Node
|
|||
std::string mPrimaryCamera;
|
||||
|
||||
//! Constructor. Begin with a zero parent
|
||||
Node()
|
||||
: mParent( nullptr ){
|
||||
Node() :
|
||||
mParent(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Destructor: delete all children subsequently
|
||||
~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;
|
||||
}
|
||||
};
|
||||
|
||||
/** Data source array: either floats or strings */
|
||||
struct Data
|
||||
{
|
||||
struct Data {
|
||||
bool mIsStringArray;
|
||||
std::vector<ai_real> mValues;
|
||||
std::vector<std::string> mStrings;
|
||||
};
|
||||
|
||||
/** Accessor to a data array */
|
||||
struct Accessor
|
||||
{
|
||||
struct Accessor {
|
||||
size_t mCount; // in number of objects
|
||||
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
|
||||
size_t mOffset; // in number of values
|
||||
|
@ -319,49 +298,54 @@ struct Accessor
|
|||
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.
|
||||
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()
|
||||
{
|
||||
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
|
||||
Accessor() {
|
||||
mCount = 0;
|
||||
mSize = 0;
|
||||
mOffset = 0;
|
||||
mStride = 0;
|
||||
mData = NULL;
|
||||
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** A single face in a mesh */
|
||||
struct Face
|
||||
{
|
||||
struct Face {
|
||||
std::vector<size_t> mIndices;
|
||||
};
|
||||
|
||||
/** An input channel for mesh data, referring to a single accessor */
|
||||
struct InputChannel
|
||||
{
|
||||
struct InputChannel {
|
||||
InputType mType; // Type of the data
|
||||
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
||||
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
|
||||
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
||||
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. 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 */
|
||||
struct SubMesh
|
||||
{
|
||||
struct SubMesh {
|
||||
std::string mMaterial; ///< subgroup identifier
|
||||
size_t mNumFaces; ///< number of faces in this submesh
|
||||
};
|
||||
|
||||
/** Contains data for a single mesh */
|
||||
struct Mesh
|
||||
{
|
||||
Mesh()
|
||||
{
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
struct Mesh {
|
||||
Mesh(const std::string &id) :
|
||||
mId(id) {
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
|
||||
mNumUVComponents[i] = 2;
|
||||
}
|
||||
|
||||
const std::string mId;
|
||||
std::string mName;
|
||||
|
||||
// just to check if there's some sophisticated addressing involved...
|
||||
|
@ -394,8 +378,7 @@ struct Mesh
|
|||
};
|
||||
|
||||
/** Which type of primitives the ReadPrimitives() function is going to read */
|
||||
enum PrimitiveType
|
||||
{
|
||||
enum PrimitiveType {
|
||||
Prim_Invalid,
|
||||
Prim_Lines,
|
||||
Prim_LineStrip,
|
||||
|
@ -407,8 +390,7 @@ enum PrimitiveType
|
|||
};
|
||||
|
||||
/** A skeleton controller to deform a mesh with the use of joints */
|
||||
struct Controller
|
||||
{
|
||||
struct Controller {
|
||||
// controller type
|
||||
ControllerType mType;
|
||||
|
||||
|
@ -436,36 +418,32 @@ struct Controller
|
|||
std::vector<size_t> mWeightCounts;
|
||||
|
||||
// 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 mMorphWeight;
|
||||
};
|
||||
|
||||
/** A collada material. Pretty much the only member is a reference to an effect. */
|
||||
struct Material
|
||||
{
|
||||
struct Material {
|
||||
std::string mName;
|
||||
std::string mEffect;
|
||||
};
|
||||
|
||||
/** Type of the effect param */
|
||||
enum ParamType
|
||||
{
|
||||
enum ParamType {
|
||||
Param_Sampler,
|
||||
Param_Surface
|
||||
};
|
||||
|
||||
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
|
||||
struct EffectParam
|
||||
{
|
||||
struct EffectParam {
|
||||
ParamType mType;
|
||||
std::string mReference; // to which other thing the param is referring to.
|
||||
};
|
||||
|
||||
/** Shading type supported by the standard effect spec of Collada */
|
||||
enum ShadeType
|
||||
{
|
||||
enum ShadeType {
|
||||
Shade_Invalid,
|
||||
Shade_Constant,
|
||||
Shade_Lambert,
|
||||
|
@ -474,18 +452,16 @@ enum ShadeType
|
|||
};
|
||||
|
||||
/** Represents a texture sampler in collada */
|
||||
struct Sampler
|
||||
{
|
||||
Sampler()
|
||||
: mWrapU (true)
|
||||
, mWrapV (true)
|
||||
, mMirrorU ()
|
||||
, mMirrorV ()
|
||||
, mOp (aiTextureOp_Multiply)
|
||||
, mUVId (UINT_MAX)
|
||||
, mWeighting (1.f)
|
||||
, mMixWithPrevious (1.f)
|
||||
{}
|
||||
struct Sampler {
|
||||
Sampler() :
|
||||
mWrapU(true),
|
||||
mWrapV(true),
|
||||
mMirrorU(),
|
||||
mMirrorV(),
|
||||
mOp(aiTextureOp_Multiply),
|
||||
mUVId(UINT_MAX),
|
||||
mWeighting(1.f),
|
||||
mMixWithPrevious(1.f) {}
|
||||
|
||||
/** Name of image reference
|
||||
*/
|
||||
|
@ -537,8 +513,7 @@ struct Sampler
|
|||
|
||||
/** A collada effect. Can contain about anything according to the Collada spec,
|
||||
but we limit our version to a reasonable subset. */
|
||||
struct Effect
|
||||
{
|
||||
struct Effect {
|
||||
// Shading mode
|
||||
ShadeType mShadeType;
|
||||
|
||||
|
@ -566,30 +541,28 @@ struct Effect
|
|||
// Double-sided?
|
||||
bool mDoubleSided, mWireframe, mFaceted;
|
||||
|
||||
Effect()
|
||||
: mShadeType (Shade_Phong)
|
||||
, mEmissive ( 0, 0, 0, 1)
|
||||
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
|
||||
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
|
||||
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
|
||||
, mTransparent ( 0, 0, 0, 1)
|
||||
, mShininess (10.0f)
|
||||
, mRefractIndex (1.f)
|
||||
, mReflectivity (0.f)
|
||||
, mTransparency (1.f)
|
||||
, mHasTransparency (false)
|
||||
, mRGBTransparency(false)
|
||||
, mInvertTransparency(false)
|
||||
, mDoubleSided (false)
|
||||
, mWireframe (false)
|
||||
, mFaceted (false)
|
||||
{
|
||||
Effect() :
|
||||
mShadeType(Shade_Phong),
|
||||
mEmissive(0, 0, 0, 1),
|
||||
mAmbient(0.1f, 0.1f, 0.1f, 1),
|
||||
mDiffuse(0.6f, 0.6f, 0.6f, 1),
|
||||
mSpecular(0.4f, 0.4f, 0.4f, 1),
|
||||
mTransparent(0, 0, 0, 1),
|
||||
mShininess(10.0f),
|
||||
mRefractIndex(1.f),
|
||||
mReflectivity(0.f),
|
||||
mTransparency(1.f),
|
||||
mHasTransparency(false),
|
||||
mRGBTransparency(false),
|
||||
mInvertTransparency(false),
|
||||
mDoubleSided(false),
|
||||
mWireframe(false),
|
||||
mFaceted(false) {
|
||||
}
|
||||
};
|
||||
|
||||
/** An image, meaning texture */
|
||||
struct Image
|
||||
{
|
||||
struct Image {
|
||||
std::string mFileName;
|
||||
|
||||
/** Embedded image data */
|
||||
|
@ -600,8 +573,7 @@ struct Image
|
|||
};
|
||||
|
||||
/** An animation channel. */
|
||||
struct AnimationChannel
|
||||
{
|
||||
struct AnimationChannel {
|
||||
/** URL of the data to animate. Could be about anything, but we support only the
|
||||
* "NodeID/TransformID.SubElement" notation
|
||||
*/
|
||||
|
@ -620,8 +592,7 @@ struct AnimationChannel
|
|||
};
|
||||
|
||||
/** An animation. Container for 0-x animation channels or 0-x animations */
|
||||
struct Animation
|
||||
{
|
||||
struct Animation {
|
||||
/** Anim name */
|
||||
std::string mName;
|
||||
|
||||
|
@ -629,22 +600,19 @@ struct Animation
|
|||
std::vector<AnimationChannel> mChannels;
|
||||
|
||||
/** the sub-animations, if any */
|
||||
std::vector<Animation*> mSubAnims;
|
||||
std::vector<Animation *> mSubAnims;
|
||||
|
||||
/** Destructor */
|
||||
~Animation()
|
||||
{
|
||||
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||
~Animation() {
|
||||
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
/** Collect all channels in the animation hierarchy into a single channel list. */
|
||||
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
|
||||
{
|
||||
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
|
||||
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
|
||||
|
||||
for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||
{
|
||||
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
|
||||
Animation *pAnim = (*it);
|
||||
|
||||
pAnim->CollectChannelsRecursively(channels);
|
||||
|
@ -652,18 +620,15 @@ struct Animation
|
|||
}
|
||||
|
||||
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
|
||||
void CombineSingleChannelAnimations()
|
||||
{
|
||||
void CombineSingleChannelAnimations() {
|
||||
CombineSingleChannelAnimationsRecursively(this);
|
||||
}
|
||||
|
||||
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
|
||||
{
|
||||
void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
|
||||
std::set<std::string> childrenTargets;
|
||||
bool childrenAnimationsHaveDifferentChannels = true;
|
||||
|
||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
||||
{
|
||||
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
|
||||
Animation *anim = *it;
|
||||
CombineSingleChannelAnimationsRecursively(anim);
|
||||
|
||||
|
@ -678,10 +643,8 @@ struct Animation
|
|||
}
|
||||
|
||||
// We only want to combine animations if they have different channels
|
||||
if (childrenAnimationsHaveDifferentChannels)
|
||||
{
|
||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
||||
{
|
||||
if (childrenAnimationsHaveDifferentChannels) {
|
||||
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
|
||||
Animation *anim = *it;
|
||||
|
||||
pParent->mChannels.push_back(anim->mChannels[0]);
|
||||
|
@ -696,29 +659,27 @@ struct Animation
|
|||
};
|
||||
|
||||
/** Description of a collada animation channel which has been determined to affect the current node */
|
||||
struct ChannelEntry
|
||||
{
|
||||
const Collada::AnimationChannel* mChannel; ///> the source channel
|
||||
struct ChannelEntry {
|
||||
const Collada::AnimationChannel *mChannel; ///> the source channel
|
||||
std::string mTargetId;
|
||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
||||
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
|
||||
size_t mSubElement; // starting index inside the transform data
|
||||
|
||||
// resolved data references
|
||||
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
|
||||
const Collada::Data* mTimeData; ///> Source data array for the time values
|
||||
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
|
||||
const Collada::Data* mValueData; ///> Source datat array for the key value values
|
||||
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
|
||||
const Collada::Data *mTimeData; ///> Source data array for the time values
|
||||
const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
|
||||
const Collada::Data *mValueData; ///> Source datat array for the key value values
|
||||
|
||||
ChannelEntry()
|
||||
: mChannel()
|
||||
, mTransformIndex()
|
||||
, mSubElement()
|
||||
, mTimeAccessor()
|
||||
, mTimeData()
|
||||
, mValueAccessor()
|
||||
, mValueData()
|
||||
{}
|
||||
ChannelEntry() :
|
||||
mChannel(),
|
||||
mTransformIndex(),
|
||||
mSubElement(),
|
||||
mTimeAccessor(),
|
||||
mTimeData(),
|
||||
mValueAccessor(),
|
||||
mValueData() {}
|
||||
};
|
||||
|
||||
} // 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++);
|
||||
|
||||
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&) {
|
||||
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
|
||||
|
||||
#include "DXF/DXFLoader.h"
|
||||
#include "DXF/DXFHelper.h"
|
||||
#include "AssetLib/DXF/DXFLoader.h"
|
||||
#include "AssetLib/DXF/DXFHelper.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.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() ) {
|
||||
|
@ -473,7 +473,7 @@ void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
|
|||
++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;
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <stdint.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/ByteSwapper.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
@ -427,6 +428,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||
{
|
||||
ai_assert(input);
|
||||
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
|
||||
|
||||
if(length < 0x1b) {
|
||||
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);
|
||||
const uint32_t version = ReadWord(input, cursor, input + length);
|
||||
ASSIMP_LOG_DEBUG_F("FBX version: ", version);
|
||||
const bool is64bits = version >= 7500;
|
||||
const char *end = input + length;
|
||||
while (cursor < end ) {
|
|
@ -48,18 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
namespace Assimp {
|
||||
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
|
||||
namespace FBX {
|
||||
|
||||
// rotation order. We'll probably use EulerXYZ for everything
|
||||
enum RotOrder {
|
||||
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
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0,
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
|
@ -70,18 +70,18 @@ namespace FBX
|
|||
RotOrder_SphericXYZ,
|
||||
|
||||
RotOrder_MAX // end-of-enum sentinel
|
||||
};
|
||||
};
|
||||
|
||||
// transformation inheritance method. Most of the time RSrs
|
||||
enum TransformInheritance {
|
||||
// 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 // AI_FBXCOMMON_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -189,8 +189,7 @@ private:
|
|||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model,
|
||||
aiNode *parent, aiNode *root_node);
|
||||
std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
|
||||
|
@ -220,17 +219,15 @@ private:
|
|||
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
||||
* each output vertex the DOM index it maps to.
|
||||
*/
|
||||
void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent = NULL, aiNode *root_node = NULL,
|
||||
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent = NULL, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||
std::vector<unsigned int> *outputVertStartIndices = NULL);
|
||||
// lookup
|
||||
static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node);
|
||||
aiNode *parent );
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
|
@ -352,12 +349,10 @@ private:
|
|||
aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name,
|
||||
const Model& target,
|
||||
NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
|
||||
NodeMap::const_iterator iter_end,
|
||||
const LayerMap& layer_map,
|
||||
NodeMap::const_iterator iterEnd,
|
||||
int64_t start, int64_t stop,
|
||||
double& max_time,
|
||||
double& min_time,
|
||||
bool reverse_order = false);
|
||||
double& maxTime,
|
||||
double& minTime);
|
||||
|
||||
// key (time), value, mapto (component index)
|
||||
typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList;
|
||||
|
@ -382,20 +377,6 @@ private:
|
|||
double& minTime,
|
||||
Model::RotOrder order);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale,
|
||||
aiVectorKey* out_translation,
|
||||
const KeyFrameListList& scaling,
|
||||
const KeyFrameListList& translation,
|
||||
const KeyFrameListList& rotation,
|
||||
const KeyTimeList& times,
|
||||
double& maxTime,
|
||||
double& minTime,
|
||||
Model::RotOrder order,
|
||||
const aiVector3D& def_scale,
|
||||
const aiVector3D& def_translate,
|
||||
const aiVector3D& def_rotation);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// euler xyz -> quat
|
||||
aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order);
|
||||
|
@ -431,13 +412,13 @@ private:
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// FBX file could have embedded textures not connected to anything
|
||||
void ConvertOrphantEmbeddedTextures();
|
||||
void ConvertOrphanedEmbeddedTextures();
|
||||
|
||||
private:
|
||||
// 0: not assigned yet, others: index is value - 1
|
||||
unsigned int defaultMaterialIndex;
|
||||
|
||||
std::vector<aiMesh*> meshes;
|
||||
std::vector<aiMesh*> mMeshes;
|
||||
std::vector<aiMaterial*> materials;
|
||||
std::vector<aiAnimation*> animations;
|
||||
std::vector<aiLight*> lights;
|
||||
|
@ -467,9 +448,9 @@ private:
|
|||
|
||||
double anim_fps;
|
||||
|
||||
aiScene* const out;
|
||||
aiScene* const mSceneOut;
|
||||
const FBX::Document& doc;
|
||||
|
||||
bool mRemoveEmptyBones;
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
std::vector<aiBone*>& bones);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue