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
|
||||
|
|
221
CMakeLists.txt
221
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)
|
||||
|
||||
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 "")
|
||||
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 "")
|
||||
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,44 +577,49 @@ 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 )
|
||||
IF ( ASSIMP_INSTALL )
|
||||
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||
ENDIF()
|
||||
|
||||
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}")
|
||||
|
@ -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)
|
||||
|
@ -652,6 +668,7 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
|||
INCLUDE(CPack)
|
||||
INCLUDE(DebSourcePPA)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
if(WIN32)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
@ -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,8 +58,7 @@ static const unsigned int NotSet = 0xcdcdcdcd;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup final material indices, generae a default material if necessary
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial()
|
||||
{
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial() {
|
||||
// Try to find an existing material that matches the
|
||||
// typical default material setting:
|
||||
// - no textures
|
||||
|
@ -70,8 +66,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
// NOTE: This is here to workaround the fact that some
|
||||
// exporters are writing a default material, too.
|
||||
unsigned int idx(NotSet);
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
|
||||
std::string s = mScene->mMaterials[i].mName;
|
||||
for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
*it = static_cast<char>(::tolower(*it));
|
||||
|
@ -89,8 +84,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
|
||||
{
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
|
||||
continue;
|
||||
}
|
||||
idx = i;
|
||||
|
@ -104,29 +98,23 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
unsigned int cnt = 0;
|
||||
for (std::vector<D3DS::Mesh>::iterator
|
||||
i = mScene->mMeshes.begin();
|
||||
i != mScene->mMeshes.end();++i)
|
||||
{
|
||||
i != mScene->mMeshes.end(); ++i) {
|
||||
for (std::vector<unsigned int>::iterator
|
||||
a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a) {
|
||||
// NOTE: The additional check seems to be necessary,
|
||||
// some exporters seem to generate invalid data here
|
||||
if (0xcdcdcdcd == (*a))
|
||||
{
|
||||
if (0xcdcdcdcd == (*a)) {
|
||||
(*a) = idx;
|
||||
++cnt;
|
||||
}
|
||||
else if ( (*a) >= mScene->mMaterials.size())
|
||||
{
|
||||
} else if ((*a) >= mScene->mMaterials.size()) {
|
||||
(*a) = idx;
|
||||
ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnt && idx == mScene->mMaterials.size())
|
||||
{
|
||||
if (cnt && idx == mScene->mMaterials.size()) {
|
||||
// We need to create our own default material
|
||||
D3DS::Material sMat("%%%DEFAULT");
|
||||
sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f);
|
||||
|
@ -138,20 +126,15 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
||||
{
|
||||
for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh &sMesh) {
|
||||
for (std::vector<D3DS::Face>::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) {
|
||||
// check whether all indices are in range
|
||||
for (unsigned int a = 0; a < 3;++a)
|
||||
{
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a) {
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size() - 1;
|
||||
}
|
||||
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
|
||||
{
|
||||
if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size() - 1;
|
||||
}
|
||||
|
@ -161,8 +144,7 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate out unique verbose format representation
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
||||
{
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh &sMesh) {
|
||||
// TODO: really necessary? I don't think. Just a waste of memory and time
|
||||
// to do it now in a separate buffer.
|
||||
|
||||
|
@ -172,13 +154,11 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
|||
if (sMesh.mTexCoords.size())
|
||||
vNew2.resize(sMesh.mFaces.size() * 3);
|
||||
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) {
|
||||
D3DS::Face &face = sMesh.mFaces[i];
|
||||
|
||||
// Positions
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
vNew[base] = sMesh.mPositions[face.mIndices[a]];
|
||||
if (sMesh.mTexCoords.size())
|
||||
vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
|
||||
|
@ -192,8 +172,7 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS texture to texture keys in an aiMaterial
|
||||
void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
||||
{
|
||||
void CopyTexture(aiMaterial &mat, D3DS::Texture &texture, aiTextureType type) {
|
||||
// Setup the texture name
|
||||
aiString tex;
|
||||
tex.Set(texture.mMapName);
|
||||
|
@ -210,8 +189,7 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
|||
|
||||
// Mirroring - double the scaling values
|
||||
// FIXME: this is not really correct ...
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror)
|
||||
{
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror) {
|
||||
texture.mScaleU *= 2.0;
|
||||
texture.mScaleV *= 2.0;
|
||||
texture.mOffsetU /= 2.0;
|
||||
|
@ -225,12 +203,10 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS material to an aiMaterial
|
||||
void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
|
||||
aiMaterial& mat)
|
||||
{
|
||||
aiMaterial &mat) {
|
||||
// NOTE: Pass the background image to the viewer by bypassing the
|
||||
// material system. This is an evil hack, never do it again!
|
||||
if (0 != mBackgroundImage.length() && bHasBG)
|
||||
{
|
||||
if (0 != mBackgroundImage.length() && bHasBG) {
|
||||
aiString tex;
|
||||
tex.Set(mBackgroundImage);
|
||||
mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||
|
@ -256,14 +232,10 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
|
||||
// Phong shininess and shininess strength
|
||||
if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading)
|
||||
{
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
|
||||
{
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading) {
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) {
|
||||
oldMat.mShading = D3DS::Discreet3DS::Gouraud;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
}
|
||||
|
@ -276,43 +248,45 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
mat.AddProperty<ai_real>(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING);
|
||||
|
||||
// Two sided rendering?
|
||||
if (oldMat.mTwoSided)
|
||||
{
|
||||
if (oldMat.mTwoSided) {
|
||||
int i = 1;
|
||||
mat.AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
// Shading mode
|
||||
aiShadingMode eShading = aiShadingMode_NoShading;
|
||||
switch (oldMat.mShading)
|
||||
{
|
||||
switch (oldMat.mShading) {
|
||||
case D3DS::Discreet3DS::Flat:
|
||||
eShading = aiShadingMode_Flat; break;
|
||||
eShading = aiShadingMode_Flat;
|
||||
break;
|
||||
|
||||
// I don't know what "Wire" shading should be,
|
||||
// assume it is simple lambertian diffuse shading
|
||||
case D3DS::Discreet3DS::Wire:
|
||||
{
|
||||
case D3DS::Discreet3DS::Wire: {
|
||||
// Set the wireframe flag
|
||||
unsigned int iWire = 1;
|
||||
mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
|
||||
case D3DS::Discreet3DS::Gouraud:
|
||||
eShading = aiShadingMode_Gouraud; break;
|
||||
eShading = aiShadingMode_Gouraud;
|
||||
break;
|
||||
|
||||
// assume cook-torrance shading for metals.
|
||||
case D3DS::Discreet3DS::Phong:
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
eShading = aiShadingMode_Phong;
|
||||
break;
|
||||
|
||||
case D3DS::Discreet3DS::Metal:
|
||||
eShading = aiShadingMode_CookTorrance; break;
|
||||
eShading = aiShadingMode_CookTorrance;
|
||||
break;
|
||||
|
||||
// FIX to workaround a warning with GCC 4 who complained
|
||||
// about a missing case Blinn: here - Blinn isn't a valid
|
||||
// value in the 3DS Loader, it is just needed for ASE
|
||||
case D3DS::Discreet3DS::Blinn:
|
||||
eShading = aiShadingMode_Blinn; break;
|
||||
eShading = aiShadingMode_Blinn;
|
||||
break;
|
||||
}
|
||||
int eShading_ = static_cast<int>(eShading);
|
||||
mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
@ -355,8 +329,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Split meshes by their materials and generate output aiMesh'es
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
|
||||
std::vector<aiMesh *> avOutMeshes;
|
||||
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
|
||||
|
||||
|
@ -371,13 +344,11 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
unsigned int iNum = 0;
|
||||
for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a,++iNum)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a, ++iNum) {
|
||||
aiSplit[*a].push_back(iNum);
|
||||
}
|
||||
// now generate submeshes
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
|
||||
{
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) {
|
||||
if (aiSplit[p].empty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -402,20 +373,17 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
|
||||
meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
|
||||
if ((*i).mTexCoords.size())
|
||||
{
|
||||
if ((*i).mTexCoords.size()) {
|
||||
meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
|
||||
}
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
|
||||
{
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) {
|
||||
unsigned int index = aiSplit[p][q];
|
||||
aiFace &face = meshOut->mFaces[q];
|
||||
|
||||
face.mIndices = new unsigned int[3];
|
||||
face.mNumIndices = 3;
|
||||
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
unsigned int idx = (*i).mFaces[index].mIndices[a];
|
||||
meshOut->mVertices[base] = (*i).mPositions[idx];
|
||||
meshOut->mNormals[base] = (*i).mNormals[idx];
|
||||
|
@ -445,24 +413,21 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Add a node to the scenegraph and setup its final transformation
|
||||
void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
|
||||
D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
|
||||
{
|
||||
D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) {
|
||||
std::vector<unsigned int> iArray;
|
||||
iArray.reserve(3);
|
||||
|
||||
aiMatrix4x4 abs;
|
||||
|
||||
// Find all meshes with the same name as the node
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
|
||||
{
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) {
|
||||
const D3DS::Mesh *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0];
|
||||
ai_assert(NULL != pcMesh);
|
||||
ai_assert(nullptr != pcMesh);
|
||||
|
||||
if (pcIn->mName == pcMesh->mName)
|
||||
iArray.push_back(a);
|
||||
}
|
||||
if (!iArray.empty())
|
||||
{
|
||||
if (!iArray.empty()) {
|
||||
// The matrix should be identical for all meshes with the
|
||||
// same name. It HAS to be identical for all meshes .....
|
||||
D3DS::Mesh *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]);
|
||||
|
@ -470,7 +435,8 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Compute the inverse of the transformation matrix to move the
|
||||
// vertices back to their relative and local space
|
||||
aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
|
||||
mInv.Inverse();mInvTransposed.Transpose();
|
||||
mInv.Inverse();
|
||||
mInvTransposed.Transpose();
|
||||
aiVector3D pivot = pcIn->vPivot;
|
||||
|
||||
pcOut->mNumMeshes = (unsigned int)iArray.size();
|
||||
|
@ -479,8 +445,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
const unsigned int iIndex = iArray[i];
|
||||
aiMesh *const mesh = pcSOut->mMeshes[iIndex];
|
||||
|
||||
if (mesh->mColors[1] == NULL)
|
||||
{
|
||||
if (mesh->mColors[1] == nullptr) {
|
||||
// Transform the vertices back into their local space
|
||||
// fixme: consider computing normals after this, so we don't need to transform them
|
||||
const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices;
|
||||
|
@ -492,8 +457,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle negative transformation matrix determinant -> invert vertex x
|
||||
if (imesh->mMat.Determinant() < 0.0f)
|
||||
{
|
||||
if (imesh->mMat.Determinant() < 0.0f) {
|
||||
/* we *must* have normals */
|
||||
for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
|
||||
pvCurrent->x *= -1.f;
|
||||
|
@ -503,16 +467,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle pivot point
|
||||
if (pivot.x || pivot.y || pivot.z)
|
||||
{
|
||||
if (pivot.x || pivot.y || pivot.z) {
|
||||
for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
|
||||
*pvCurrent -= pivot;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
}
|
||||
else
|
||||
} else
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
|
||||
// Setup the mesh index
|
||||
|
@ -522,15 +484,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// Setup the name of the node
|
||||
// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
|
||||
if (pcIn->mInstanceNumber > 1)
|
||||
{
|
||||
if (pcIn->mInstanceNumber > 1) {
|
||||
char tmp[12];
|
||||
ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
|
||||
std::string tempStr = pcIn->mName + "_inst_";
|
||||
tempStr += tmp;
|
||||
pcOut->mName.Set(tempStr);
|
||||
}
|
||||
else
|
||||
} else
|
||||
pcOut->mName.Set(pcIn->mName);
|
||||
|
||||
// Now build the transformation matrix of the node
|
||||
|
@ -543,26 +503,28 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix());
|
||||
}
|
||||
else if (pcIn->aCameraRollKeys.size())
|
||||
{
|
||||
} else if (pcIn->aCameraRollKeys.size()) {
|
||||
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue),
|
||||
pcOut->mTransformation);
|
||||
}
|
||||
|
||||
// SCALING
|
||||
aiMatrix4x4 &m = pcOut->mTransformation;
|
||||
if (pcIn->aScalingKeys.size())
|
||||
{
|
||||
if (pcIn->aScalingKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aScalingKeys[0].mValue;
|
||||
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
|
||||
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
|
||||
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
|
||||
m.a1 *= v.x;
|
||||
m.b1 *= v.x;
|
||||
m.c1 *= v.x;
|
||||
m.a2 *= v.y;
|
||||
m.b2 *= v.y;
|
||||
m.c2 *= v.y;
|
||||
m.a3 *= v.z;
|
||||
m.b3 *= v.z;
|
||||
m.c3 *= v.z;
|
||||
}
|
||||
|
||||
// TRANSLATION
|
||||
if (pcIn->aPositionKeys.size())
|
||||
{
|
||||
if (pcIn->aPositionKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aPositionKeys[0].mValue;
|
||||
m.a4 += v.x;
|
||||
m.b4 += v.y;
|
||||
|
@ -572,21 +534,18 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Generate animation channels for the node
|
||||
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
|
||||
pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
|
||||
pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
pcIn->aTargetPositionKeys.size() > 1) {
|
||||
aiAnimation *anim = pcSOut->mAnimations[0];
|
||||
ai_assert(nullptr != anim);
|
||||
|
||||
if (pcIn->aCameraRollKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
|
||||
if (pcIn->aCameraRollKeys.size() > 1) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ...");
|
||||
|
||||
// Camera roll keys - in fact they're just rotations
|
||||
// around the camera's z axis. The angles are given
|
||||
// in degrees (and they're clockwise).
|
||||
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) {
|
||||
aiQuatKey &q = pcIn->aRotationKeys[i];
|
||||
aiFloatKey &f = pcIn->aCameraRollKeys[i];
|
||||
|
||||
|
@ -599,7 +558,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
#if 0
|
||||
if (pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ...");
|
||||
|
||||
// Camera or spot light - need to convert the separate
|
||||
// target position channel to our representation
|
||||
|
@ -655,8 +614,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
nda->mNodeName.Set(pcIn->mName);
|
||||
|
||||
// POSITION keys
|
||||
if (pcIn->aPositionKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aPositionKeys.size() > 0) {
|
||||
nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
|
||||
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
|
||||
::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0],
|
||||
|
@ -664,15 +622,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// ROTATION keys
|
||||
if (pcIn->aRotationKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aRotationKeys.size() > 0) {
|
||||
nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
|
||||
nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
|
||||
|
||||
// Rotations are quaternion offsets
|
||||
aiQuaternion abs1;
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
|
||||
{
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) {
|
||||
const aiQuatKey &q = pcIn->aRotationKeys[n];
|
||||
|
||||
abs1 = (n ? abs1 * q.mValue : q.mValue);
|
||||
|
@ -682,8 +638,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// SCALING keys
|
||||
if (pcIn->aScalingKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aScalingKeys.size() > 0) {
|
||||
nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
|
||||
nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
|
||||
::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0],
|
||||
|
@ -697,8 +652,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// Recursively process all children
|
||||
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
|
||||
for (unsigned int i = 0; i < size;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
pcOut->mChildren[i] = new aiNode();
|
||||
pcOut->mChildren[i]->mParent = pcOut;
|
||||
AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs);
|
||||
|
@ -707,16 +661,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find out how many node animation channels we'll have finally
|
||||
void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
||||
{
|
||||
void CountTracks(D3DS::Node *node, unsigned int &cnt) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// We will never generate more than one channel for a node, so
|
||||
// this is rather easy here.
|
||||
|
||||
if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
|
||||
node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
|
||||
node->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
node->aTargetPositionKeys.size() > 1) {
|
||||
++cnt;
|
||||
|
||||
// account for the additional channel for the camera/spotlight target position
|
||||
|
@ -730,11 +682,9 @@ void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate the output node graph
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
|
||||
pcOut->mRootNode = new aiNode();
|
||||
if (0 == mRootNode->mChildren.size())
|
||||
{
|
||||
if (0 == mRootNode->mChildren.size()) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// It seems the file is so messed up that it has not even a hierarchy.
|
||||
// generate a flat hiearachy which looks like this:
|
||||
|
@ -755,8 +705,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
|
||||
// Build dummy nodes for all meshes
|
||||
unsigned int a = 0;
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
pcNode->mMeshes = new unsigned int[1];
|
||||
|
@ -768,8 +717,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// Build dummy nodes for all cameras
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
|
@ -778,24 +726,20 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// Build dummy nodes for all lights
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
// Build a name for the node
|
||||
pcNode->mName = mScene->mLights[i]->mName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// First of all: find out how many scaling, rotation and translation
|
||||
// animation tracks we'll have afterwards
|
||||
unsigned int numChannel = 0;
|
||||
CountTracks(mRootNode, numChannel);
|
||||
|
||||
if (numChannel)
|
||||
{
|
||||
if (numChannel) {
|
||||
// Allocate a primary animation channel
|
||||
pcOut->mNumAnimations = 1;
|
||||
pcOut->mAnimations = new aiAnimation *[1];
|
||||
|
@ -814,37 +758,34 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// We used the first and second vertex color set to store some temporary values so we need to cleanup here
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
|
||||
{
|
||||
pcOut->mMeshes[a]->mColors[0] = NULL;
|
||||
pcOut->mMeshes[a]->mColors[1] = NULL;
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
|
||||
pcOut->mMeshes[a]->mColors[0] = nullptr;
|
||||
pcOut->mMeshes[a]->mColors[1] = nullptr;
|
||||
}
|
||||
|
||||
pcOut->mRootNode->mTransformation = aiMatrix4x4(
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, -1.f, 0.f, 0.f,
|
||||
0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
|
||||
0.f, 0.f, 0.f, 1.f) *
|
||||
pcOut->mRootNode->mTransformation;
|
||||
|
||||
// If the root node is unnamed name it "<3DSRoot>"
|
||||
if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") ||
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
|
||||
{
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) {
|
||||
pcOut->mRootNode->mName.Set("<3DSRoot>");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert all meshes in the scene and generate the final output scene.
|
||||
void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
|
||||
// Allocate enough storage for all output materials
|
||||
pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
|
||||
pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials];
|
||||
|
||||
// ... and convert the 3DS materials to aiMaterial's
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) {
|
||||
aiMaterial *pcNew = new aiMaterial();
|
||||
ConvertMaterial(mScene->mMaterials[i], *pcNew);
|
||||
pcOut->mMaterials[i] = pcNew;
|
||||
|
@ -855,16 +796,14 @@ void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
|||
|
||||
// Now copy all light sources to the output scene
|
||||
pcOut->mNumLights = (unsigned int)mScene->mLights.size();
|
||||
if (pcOut->mNumLights)
|
||||
{
|
||||
if (pcOut->mNumLights) {
|
||||
pcOut->mLights = new aiLight *[pcOut->mNumLights];
|
||||
::memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights);
|
||||
}
|
||||
|
||||
// Now copy all cameras to the output scene
|
||||
pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
|
||||
if (pcOut->mNumCameras)
|
||||
{
|
||||
if (pcOut->mNumCameras) {
|
||||
pcOut->mCameras = new aiCamera *[pcOut->mNumCameras];
|
||||
::memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras);
|
||||
}
|
|
@ -43,16 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
|
||||
#include "3DS/3DSExporter.h"
|
||||
#include "3DS/3DSLoader.h"
|
||||
#include "3DS/3DSHelper.h"
|
||||
#include "AssetLib/3DS/3DSExporter.h"
|
||||
#include "AssetLib/3DS/3DSHelper.h"
|
||||
#include "AssetLib/3DS/3DSLoader.h"
|
||||
#include "PostProcessing/SplitLargeMeshes.h"
|
||||
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -70,17 +70,16 @@ namespace {
|
|||
// size based on the then-position of the output stream cursor is filled in.
|
||||
class ChunkWriter {
|
||||
enum {
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef
|
||||
, SIZE_OFFSET = 2
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
|
||||
SIZE_OFFSET = 2
|
||||
};
|
||||
public:
|
||||
|
||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
||||
: writer(writer)
|
||||
{
|
||||
public:
|
||||
ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
|
||||
writer(writer) {
|
||||
chunk_start_pos = writer.GetCurrentPos();
|
||||
writer.PutU2(chunk_type);
|
||||
writer.PutU4(CHUNK_SIZE_NOT_SET);
|
||||
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
|
||||
}
|
||||
|
||||
~ChunkWriter() {
|
||||
|
@ -99,7 +98,6 @@ namespace {
|
|||
std::size_t chunk_start_pos;
|
||||
};
|
||||
|
||||
|
||||
// Return an unique name for a given |mesh| attached to |node| that
|
||||
// preserves the mesh's given name if it has one. |index| is the index
|
||||
// of the mesh in |aiScene::mMeshes|.
|
||||
|
@ -149,12 +147,11 @@ namespace {
|
|||
CollectMeshes(node->mChildren[i], meshes);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
|
||||
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
|
||||
{
|
||||
void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
|
||||
std::shared_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
|
||||
if (!outfile) {
|
||||
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
||||
|
@ -186,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
|
||||
|
@ -262,7 +255,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
|
|||
const unsigned int mesh_idx = node.mMeshes[i];
|
||||
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,10 +269,9 @@ 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);
|
||||
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||
const aiMaterial &mat = *scene->mMaterials[i];
|
||||
|
||||
{
|
||||
|
@ -290,22 +282,22 @@ void Discreet3DSExporter::WriteMaterials()
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -441,13 +429,12 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
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);
|
||||
|
@ -461,7 +448,7 @@ 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);
|
||||
|
||||
|
@ -474,7 +461,7 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
|
||||
// Faces (indices)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
|
||||
|
@ -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,9 +511,8 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||
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);
|
||||
|
||||
|
@ -559,7 +545,7 @@ void Discreet3DSExporter::WriteString(const aiString& s) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteColor(const aiColor3D &color) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
writer.PutF4(color.r);
|
||||
writer.PutF4(color.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,8 +107,7 @@ public:
|
|||
} shadetype3ds;
|
||||
|
||||
// Flags for animated keys
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
KEY_USE_TENS = 0x1,
|
||||
KEY_USE_CONT = 0x2,
|
||||
KEY_USE_BIAS = 0x4,
|
||||
|
@ -118,8 +115,7 @@ public:
|
|||
KEY_USE_EASE_FROM = 0x10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
|
||||
// ********************************************************************
|
||||
// Basic chunks which can be found everywhere in the file
|
||||
|
@ -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,53 +589,39 @@ 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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
~Node() {
|
||||
for (unsigned int i = 0; i < mChildren.size(); ++i)
|
||||
delete mChildren[i];
|
||||
}
|
||||
|
@ -600,7 +656,6 @@ 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;
|
||||
|
@ -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;
|
||||
|
@ -645,7 +698,6 @@ struct Scene
|
|||
// Node* pcRootNode;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace D3DS
|
||||
} // end of namespace Assimp
|
||||
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -47,15 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* http://www.the-labs.com/Blender/3DS-details.html
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
#include "3DSLoader.h"
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -72,7 +69,6 @@ static const aiImporterDesc desc = {
|
|||
"3ds prj"
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Begins a new parsing block
|
||||
// - Reads the current chunk and validates it
|
||||
|
@ -88,8 +84,7 @@ static const aiImporterDesc desc = {
|
|||
if (chunkSize <= 0) \
|
||||
continue; \
|
||||
const unsigned int oldReadLimit = stream->SetReadLimit( \
|
||||
stream->GetCurrentPos() + chunkSize); \
|
||||
|
||||
stream->GetCurrentPos() + chunkSize);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// End a parsing block
|
||||
|
@ -103,15 +98,8 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
Discreet3DSImporter::Discreet3DSImporter()
|
||||
: stream()
|
||||
, mLastNodeIndex()
|
||||
, mCurrentNode()
|
||||
, mRootNode()
|
||||
, mScene()
|
||||
, mMasterScale()
|
||||
, bHasBG()
|
||||
, bIsPrj() {
|
||||
Discreet3DSImporter::Discreet3DSImporter() :
|
||||
stream(), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -141,30 +129,27 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader registry entry
|
||||
const aiImporterDesc* Discreet3DSImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *Discreet3DSImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties
|
||||
void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||
// nothing to be done for the moment
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void Discreet3DSImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
|
||||
|
||||
// We should have at least one chunk
|
||||
if (stream.GetRemainingSize() < 16) {
|
||||
if (theStream.GetRemainingSize() < 16) {
|
||||
throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
|
||||
}
|
||||
this->stream = &stream;
|
||||
this->stream = &theStream;
|
||||
|
||||
// Allocate our temporary 3DS representation
|
||||
D3DS::Scene _scene;
|
||||
|
@ -177,7 +162,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
mRootNode = mCurrentNode;
|
||||
mRootNode->mHierarchyPos = -1;
|
||||
mRootNode->mHierarchyIndex = -1;
|
||||
mRootNode->mParent = NULL;
|
||||
mRootNode->mParent = nullptr;
|
||||
mMasterScale = 1.0f;
|
||||
mBackgroundImage = "";
|
||||
bHasBG = false;
|
||||
|
@ -200,7 +185,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
ComputeNormalsWithSmoothingsGroups<D3DS::Face>(mesh);
|
||||
}
|
||||
|
||||
// Replace all occurences of the default material with a
|
||||
// Replace all occurrences of the default material with a
|
||||
// valid material. Generate it if no material containing
|
||||
// DEFAULT in its name has been found in the file
|
||||
ReplaceDefaultMaterial();
|
||||
|
@ -227,11 +212,12 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Applies a master-scaling factor to the imported scene
|
||||
void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
|
||||
{
|
||||
void Discreet3DSImporter::ApplyMasterScale(aiScene *pScene) {
|
||||
// There are some 3DS files with a zero scaling factor
|
||||
if (!mMasterScale)mMasterScale = 1.0f;
|
||||
else mMasterScale = 1.0f / mMasterScale;
|
||||
if (!mMasterScale)
|
||||
mMasterScale = 1.0f;
|
||||
else
|
||||
mMasterScale = 1.0f / mMasterScale;
|
||||
|
||||
// Construct an uniform scaling matrix and multiply with it
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
|
@ -245,8 +231,7 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a new chunk from the file
|
||||
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk *pcOut) {
|
||||
ai_assert(pcOut != nullptr);
|
||||
|
||||
pcOut->Flag = stream->GetI2();
|
||||
|
@ -263,8 +248,7 @@ void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Skip a chunk
|
||||
void Discreet3DSImporter::SkipChunk()
|
||||
{
|
||||
void Discreet3DSImporter::SkipChunk() {
|
||||
Discreet3DS::Chunk psChunk;
|
||||
ReadChunk(&psChunk);
|
||||
|
||||
|
@ -274,13 +258,11 @@ void Discreet3DSImporter::SkipChunk()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Process the primary chunk of the file
|
||||
void Discreet3DSImporter::ParseMainChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMainChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
|
||||
case Discreet3DS::CHUNK_PRJ:
|
||||
bIsPrj = true;
|
||||
|
@ -295,13 +277,11 @@ void Discreet3DSImporter::ParseMainChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseEditorChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseEditorChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_OBJMESH:
|
||||
|
||||
ParseObjectChunk();
|
||||
|
@ -314,36 +294,31 @@ void Discreet3DSImporter::ParseEditorChunk()
|
|||
ParseKeyframeChunk();
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_VERSION:
|
||||
{
|
||||
case Discreet3DS::CHUNK_VERSION: {
|
||||
// print the version number
|
||||
char buff[10];
|
||||
ASSIMP_itoa10(buff, stream->GetI2());
|
||||
ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseObjectChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseObjectChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_OBJBLOCK:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_OBJBLOCK: {
|
||||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
|
||||
// Get the name of the geometry object
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
ParseChunk(sz, cnt);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_MATERIAL:
|
||||
|
||||
|
@ -357,24 +332,22 @@ void Discreet3DSImporter::ParseObjectChunk()
|
|||
// This is the ambient base color of the scene.
|
||||
// We add it to the ambient color of all materials
|
||||
ParseColorChunk(&mClrAmbient, true);
|
||||
if (is_qnan(mClrAmbient.r))
|
||||
{
|
||||
if (is_qnan(mClrAmbient.r)) {
|
||||
// We failed to read the ambient base color.
|
||||
ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
|
||||
mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_BIT_MAP:
|
||||
{
|
||||
case Discreet3DS::CHUNK_BIT_MAP: {
|
||||
// Specifies the background image. The string should already be
|
||||
// properly 0 terminated but we need to be sure
|
||||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
mBackgroundImage = std::string(sz, cnt);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
|
||||
bHasBG = true;
|
||||
|
@ -389,8 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
||||
{
|
||||
void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// IMPLEMENTATION NOTE;
|
||||
|
@ -399,20 +371,16 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
// to to be able to return valid cameras/lights even if no scenegraph is given.
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRIMESH:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRIMESH: {
|
||||
// this starts a new triangle mesh
|
||||
mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num)));
|
||||
|
||||
// Read mesh chunks
|
||||
ParseMeshChunk();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_LIGHT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_LIGHT: {
|
||||
// This starts a new light
|
||||
aiLight *light = new aiLight();
|
||||
mScene->mLights.push_back(light);
|
||||
|
@ -435,15 +403,13 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
light->mColorSpecular = light->mColorDiffuse;
|
||||
light->mColorAmbient = mClrAmbient;
|
||||
|
||||
if (light->mType == aiLightSource_UNDEFINED)
|
||||
{
|
||||
if (light->mType == aiLightSource_UNDEFINED) {
|
||||
// It must be a point light
|
||||
light->mType = aiLightSource_POINT;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_CAMERA:
|
||||
{
|
||||
case Discreet3DS::CHUNK_CAMERA: {
|
||||
// This starts a new camera
|
||||
aiCamera *camera = new aiCamera();
|
||||
mScene->mCameras.push_back(camera);
|
||||
|
@ -465,8 +431,8 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
|
||||
camera->mLookAt = aiVector3D(0.0, 1.0, 0.0);
|
||||
|
||||
}
|
||||
else camera->mLookAt /= len;
|
||||
} else
|
||||
camera->mLookAt /= len;
|
||||
|
||||
// And finally - the camera rotation angle, in counter clockwise direction
|
||||
const ai_real angle = AI_DEG_TO_RAD(stream->GetF4());
|
||||
|
@ -482,21 +448,19 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
// Now check for further subchunks
|
||||
if (!bIsPrj) /* fixme */ {
|
||||
ParseCameraChunk();
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseLightChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseLightChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
aiLight *light = mScene->mLights.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_DL_SPOTLIGHT:
|
||||
// Now we can be sure that the light is a spot light
|
||||
light->mType = aiLightSource_SPOT;
|
||||
|
@ -537,14 +501,12 @@ void Discreet3DSImporter::ParseLightChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseCameraChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseCameraChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
aiCamera *camera = mScene->mCameras.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
// near and far clip plane
|
||||
case Discreet3DS::CHUNK_CAM_RANGES:
|
||||
camera->mClipPlaneNear = stream->GetF4();
|
||||
|
@ -556,13 +518,11 @@ void Discreet3DSImporter::ParseCameraChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseKeyframeChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseKeyframeChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRACKCAMTGT:
|
||||
case Discreet3DS::CHUNK_TRACKSPOTL:
|
||||
case Discreet3DS::CHUNK_TRACKCAMERA:
|
||||
|
@ -580,8 +540,7 @@ void Discreet3DSImporter::ParseKeyframeChunk()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Little helper function for ParseHierarchyChunk
|
||||
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
|
||||
{
|
||||
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node *pcNode, D3DS::Node *pcCurrent) {
|
||||
if (!pcCurrent) {
|
||||
mRootNode->push_back(pcNode);
|
||||
return;
|
||||
|
@ -590,8 +549,8 @@ void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCur
|
|||
if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) {
|
||||
if (pcCurrent->mParent) {
|
||||
pcCurrent->mParent->push_back(pcNode);
|
||||
}
|
||||
else pcCurrent->push_back(pcNode);
|
||||
} else
|
||||
pcCurrent->push_back(pcNode);
|
||||
return;
|
||||
}
|
||||
return InverseNodeSearch(pcNode, pcCurrent->mParent);
|
||||
|
@ -599,30 +558,31 @@ void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCur
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find a node with a specific name in the import hierarchy
|
||||
D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
|
||||
{
|
||||
if (root->mName == name)
|
||||
D3DS::Node *FindNode(D3DS::Node *root, const std::string &name) {
|
||||
if (root->mName == name) {
|
||||
return root;
|
||||
}
|
||||
|
||||
for (std::vector<D3DS::Node *>::iterator it = root->mChildren.begin(); it != root->mChildren.end(); ++it) {
|
||||
D3DS::Node* nd;
|
||||
if (( nd = FindNode(*it,name)))
|
||||
D3DS::Node *nd = FindNode(*it, name);
|
||||
if (nullptr != nd) {
|
||||
return nd;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Binary predicate for std::unique()
|
||||
template <class T>
|
||||
bool KeyUniqueCompare(const T& first, const T& second)
|
||||
{
|
||||
bool KeyUniqueCompare(const T &first, const T &second) {
|
||||
return first.mTime == second.mTime;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Skip some additional import data.
|
||||
void Discreet3DSImporter::SkipTCBInfo()
|
||||
{
|
||||
void Discreet3DSImporter::SkipTCBInfo() {
|
||||
unsigned int flags = stream->GetI2();
|
||||
|
||||
if (!flags) {
|
||||
|
@ -652,13 +612,11 @@ void Discreet3DSImporter::SkipTCBInfo()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read hierarchy and keyframe info
|
||||
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
||||
{
|
||||
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRACKOBJNAME:
|
||||
|
||||
// This is the name of the object to which the track applies. The chunk also
|
||||
|
@ -669,7 +627,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
std::string name = std::string(sz, cnt);
|
||||
|
||||
// Now find out whether we have this node already (target animation channels
|
||||
|
@ -677,11 +636,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
D3DS::Node *pcNode = FindNode(mRootNode, name);
|
||||
int instanceNumber = 1;
|
||||
|
||||
if ( pcNode)
|
||||
{
|
||||
if (pcNode) {
|
||||
// if the source is not a CHUNK_TRACKINFO block it won't be an object instance
|
||||
if (parent != Discreet3DS::CHUNK_TRACKINFO)
|
||||
{
|
||||
if (parent != Discreet3DS::CHUNK_TRACKINFO) {
|
||||
mCurrentNode = pcNode;
|
||||
break;
|
||||
}
|
||||
|
@ -705,14 +662,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
// add to the parent of the last touched node
|
||||
mCurrentNode->mParent->push_back(pcNode);
|
||||
mLastNodeIndex++;
|
||||
}
|
||||
else if(hierarchy >= mLastNodeIndex) {
|
||||
} else if (hierarchy >= mLastNodeIndex) {
|
||||
|
||||
// place it at the current position in the hierarchy
|
||||
mCurrentNode->push_back(pcNode);
|
||||
mLastNodeIndex = hierarchy;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// need to go back to the specified position in the hierarchy.
|
||||
InverseNodeSearch(pcNode, mCurrentNode);
|
||||
mLastNodeIndex++;
|
||||
|
@ -727,7 +682,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
// This is the "real" name of a $$$DUMMY object
|
||||
{
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1());
|
||||
while (stream->GetI1())
|
||||
;
|
||||
|
||||
// If object name is DUMMY, take this one instead
|
||||
if (mCurrentNode->mName == "$$$DUMMY") {
|
||||
|
@ -739,8 +695,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
|
||||
case Discreet3DS::CHUNK_TRACKPIVOT:
|
||||
|
||||
if ( Discreet3DS::CHUNK_TRACKINFO != parent)
|
||||
{
|
||||
if (Discreet3DS::CHUNK_TRACKINFO != parent) {
|
||||
ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
|
||||
break;
|
||||
}
|
||||
|
@ -751,11 +706,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
mCurrentNode->vPivot.z = stream->GetF4();
|
||||
break;
|
||||
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// POSITION KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKPOS:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKPOS: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI4();
|
||||
bool sortKeys = false;
|
||||
|
@ -765,8 +718,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
std::vector<aiVectorKey> *l;
|
||||
if (Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) {
|
||||
l = &mCurrentNode->aTargetPositionKeys;
|
||||
}
|
||||
else l = & mCurrentNode->aPositionKeys;
|
||||
} else
|
||||
l = &mCurrentNode->aPositionKeys;
|
||||
|
||||
l->reserve(numFrames);
|
||||
for (unsigned int i = 0; i < numFrames; ++i) {
|
||||
|
@ -793,14 +746,14 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// CAMERA ROLL KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKROLL:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKROLL: {
|
||||
// roll keys are accepted for cameras only
|
||||
if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
|
||||
ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
|
||||
|
@ -835,24 +788,19 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiFloatKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// CAMERA FOV KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKFOV:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKFOV: {
|
||||
ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
|
||||
"This is not supported");
|
||||
}
|
||||
break;
|
||||
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// ROTATION KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKROTATE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKROTATE: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI4();
|
||||
|
||||
|
@ -891,13 +839,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiQuatKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// SCALING KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKSCALE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKSCALE: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI2();
|
||||
stream->IncPtr(2);
|
||||
|
@ -934,8 +881,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
|
@ -943,18 +890,15 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a face chunk - it contains smoothing groups and material assignments
|
||||
void Discreet3DSImporter::ParseFaceChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseFaceChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// Get the mesh we're currently working on
|
||||
D3DS::Mesh &mMesh = mScene->mMeshes.back();
|
||||
|
||||
// Get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_SMOOLIST:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_SMOOLIST: {
|
||||
// This is the list of smoothing groups - a bitfield for every face.
|
||||
// Up to 32 smoothing groups assigned to a single face.
|
||||
unsigned int num = chunkSize / 4, m = 0;
|
||||
|
@ -964,14 +908,14 @@ void Discreet3DSImporter::ParseFaceChunk()
|
|||
for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num; ++i, ++m) {
|
||||
// nth bit is set for nth smoothing group
|
||||
(*i).iSmoothGroup = stream->GetI4();
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_FACEMAT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_FACEMAT: {
|
||||
// at fist an asciiz with the material name
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1());
|
||||
while (stream->GetI1())
|
||||
;
|
||||
|
||||
// find the index of the material
|
||||
unsigned int idx = 0xcdcdcdcd, cnt = 0;
|
||||
|
@ -994,28 +938,25 @@ void Discreet3DSImporter::ParseFaceChunk()
|
|||
// check range
|
||||
if (fidx >= mMesh.mFaceMaterials.size()) {
|
||||
ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
|
||||
} else
|
||||
mMesh.mFaceMaterials[fidx] = idx;
|
||||
}
|
||||
else mMesh.mFaceMaterials[fidx] = idx;
|
||||
}}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a mesh chunk. Here's the actual mesh data
|
||||
void Discreet3DSImporter::ParseMeshChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMeshChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// Get the mesh we're currently working on
|
||||
D3DS::Mesh &mMesh = mScene->mMeshes.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_VERTLIST:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_VERTLIST: {
|
||||
// This is the list of all vertices in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mPositions.reserve(num);
|
||||
|
@ -1025,10 +966,9 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
v.y = stream->GetF4();
|
||||
v.z = stream->GetF4();
|
||||
mMesh.mPositions.push_back(v);
|
||||
}}
|
||||
break;
|
||||
case Discreet3DS::CHUNK_TRMATRIX:
|
||||
{
|
||||
}
|
||||
} break;
|
||||
case Discreet3DS::CHUNK_TRMATRIX: {
|
||||
// This is the RLEATIVE transformation matrix of the current mesh. Vertices are
|
||||
// pretransformed by this matrix wonder.
|
||||
mMesh.mMat.a1 = stream->GetF4();
|
||||
|
@ -1043,11 +983,9 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
mMesh.mMat.a4 = stream->GetF4();
|
||||
mMesh.mMat.b4 = stream->GetF4();
|
||||
mMesh.mMat.c4 = stream->GetF4();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAPLIST:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAPLIST: {
|
||||
// This is the list of all UV coords in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mTexCoords.reserve(num);
|
||||
|
@ -1056,11 +994,10 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
v.x = stream->GetF4();
|
||||
v.y = stream->GetF4();
|
||||
mMesh.mTexCoords.push_back(v);
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_FACELIST:
|
||||
{
|
||||
case Discreet3DS::CHUNK_FACELIST: {
|
||||
// This is the list of all faces in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mFaces.reserve(num);
|
||||
|
@ -1081,22 +1018,19 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
mMesh.mFaceMaterials.resize(mMesh.mFaces.size(), 0xcdcdcdcd);
|
||||
|
||||
// Larger 3DS files could have multiple FACE chunks here
|
||||
chunkSize = stream->GetRemainingSizeToLimit();
|
||||
chunkSize = (int)stream->GetRemainingSizeToLimit();
|
||||
if (chunkSize > (int)sizeof(Discreet3DS::Chunk))
|
||||
ParseFaceChunk();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a 3DS material chunk
|
||||
void Discreet3DSImporter::ParseMaterialChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMaterialChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_MAT_MATNAME:
|
||||
|
||||
{
|
||||
|
@ -1109,13 +1043,11 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
if (!cnt) {
|
||||
// This may not be, we use the default name instead
|
||||
ASSIMP_LOG_ERROR("3DS: Empty material name");
|
||||
}
|
||||
else mScene->mMaterials.back().mName = std::string(sz,cnt);
|
||||
}
|
||||
break;
|
||||
} else
|
||||
mScene->mMaterials.back().mName = std::string(sz, cnt);
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_DIFFUSE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_DIFFUSE: {
|
||||
// This is the diffuse material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mDiffuse;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1123,11 +1055,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
|
||||
pc->r = pc->g = pc->b = 1.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SPECULAR:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_SPECULAR: {
|
||||
// This is the specular material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mSpecular;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1135,11 +1066,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
|
||||
pc->r = pc->g = pc->b = 1.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_AMBIENT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_AMBIENT: {
|
||||
// This is the ambient material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mAmbient;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1147,11 +1077,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
|
||||
pc->r = pc->g = pc->b = 0.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILLUM: {
|
||||
// This is the emissive material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mEmissive;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1159,11 +1088,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
|
||||
pc->r = pc->g = pc->b = 0.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_TRANSPARENCY: {
|
||||
// This is the material's transparency
|
||||
ai_real *pcf = &mScene->mMaterials.back().mTransparency;
|
||||
*pcf = ParsePercentageChunk();
|
||||
|
@ -1173,8 +1101,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
*pcf = ai_real(1.0);
|
||||
else
|
||||
*pcf = ai_real(1.0) - *pcf * (ai_real)0xFFFF / ai_real(100.0);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHADING:
|
||||
// This is the material shading mode
|
||||
|
@ -1186,37 +1113,32 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
mScene->mMaterials.back().mTwoSided = true;
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS:
|
||||
{ // This is the shininess of the material
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS: { // This is the shininess of the material
|
||||
ai_real *pcf = &mScene->mMaterials.back().mSpecularExponent;
|
||||
*pcf = ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 0.0;
|
||||
else *pcf *= (ai_real)0xFFFF;
|
||||
}
|
||||
break;
|
||||
else
|
||||
*pcf *= (ai_real)0xFFFF;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
|
||||
{ // This is the shininess strength of the material
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: { // This is the shininess strength of the material
|
||||
ai_real *pcf = &mScene->mMaterials.back().mShininessStrength;
|
||||
*pcf = ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = ai_real(0.0);
|
||||
else
|
||||
*pcf *= (ai_real)0xffff / ai_real(100.0);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
|
||||
{ // This is the self illumination strength of the material
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILPCT: { // This is the self illumination strength of the material
|
||||
ai_real f = ParsePercentageChunk();
|
||||
if (is_qnan(f))
|
||||
f = ai_real(0.0);
|
||||
else
|
||||
f *= (ai_real)0xFFFF / ai_real(100.0);
|
||||
mScene->mMaterials.back().mEmissive = aiColor3D(f, f, f);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
// Parse texture chunks
|
||||
case Discreet3DS::CHUNK_MAT_TEXTURE:
|
||||
|
@ -1252,24 +1174,19 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture *pcOut) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAPFILE:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_MAPFILE: {
|
||||
// The material name string is already zero-terminated, but we need to be sure ...
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
unsigned int cnt = 0;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
pcOut->mMapName = std::string(sz, cnt);
|
||||
}
|
||||
break;
|
||||
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_PERCENTD:
|
||||
// Manually parse the blend factor
|
||||
|
@ -1289,8 +1206,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
case Discreet3DS::CHUNK_MAT_MAP_USCALE:
|
||||
// Texture coordinate scaling in the U direction
|
||||
pcOut->mScaleU = stream->GetF4();
|
||||
if (0.0f == pcOut->mScaleU)
|
||||
{
|
||||
if (0.0f == pcOut->mScaleU) {
|
||||
ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1.");
|
||||
pcOut->mScaleU = 1.0f;
|
||||
}
|
||||
|
@ -1298,8 +1214,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
|
||||
// Texture coordinate scaling in the V direction
|
||||
pcOut->mScaleV = stream->GetF4();
|
||||
if (0.0f == pcOut->mScaleV)
|
||||
{
|
||||
if (0.0f == pcOut->mScaleV) {
|
||||
ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1.");
|
||||
pcOut->mScaleV = 1.0f;
|
||||
}
|
||||
|
@ -1320,8 +1235,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
pcOut->mRotation = -AI_DEG_TO_RAD(stream->GetF4());
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_MAP_TILING:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_MAP_TILING: {
|
||||
const uint16_t iFlags = stream->GetI2();
|
||||
|
||||
// Get the mapping mode (for both axes)
|
||||
|
@ -1332,9 +1246,9 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
pcOut->mMapMode = aiTextureMapMode_Decal;
|
||||
|
||||
// wrapping in all remaining cases
|
||||
else pcOut->mMapMode = aiTextureMapMode_Wrap;
|
||||
}
|
||||
break;
|
||||
else
|
||||
pcOut->mMapMode = aiTextureMapMode_Wrap;
|
||||
} break;
|
||||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
|
@ -1357,9 +1271,8 @@ ai_real Discreet3DSImporter::ParsePercentageChunk() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
|
||||
void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
||||
{
|
||||
ai_assert(out != NULL);
|
||||
void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
|
||||
ai_assert(out != nullptr);
|
||||
|
||||
// error return value
|
||||
const ai_real qnan = get_qnan();
|
||||
|
@ -1372,8 +1285,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
bool bGamma = false;
|
||||
|
||||
// Get the type of the chunk
|
||||
switch(chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_LINRGBF:
|
||||
bGamma = true;
|
||||
|
||||
|
@ -1389,8 +1301,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
|
||||
case Discreet3DS::CHUNK_LINRGBB:
|
||||
bGamma = true;
|
||||
case Discreet3DS::CHUNK_RGBB:
|
||||
{
|
||||
case Discreet3DS::CHUNK_RGBB: {
|
||||
if (sizeof(char) * 3 > diff) {
|
||||
*out = clrError;
|
||||
return;
|
||||
|
@ -1399,8 +1310,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
out->r = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
out->g = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
out->b = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
// Percentage chunks are accepted, too.
|
||||
case Discreet3DS::CHUNK_PERCENTF:
|
|
@ -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,13 +44,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "D3MFExporter.h"
|
||||
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include "3MFXmlTags.h"
|
||||
#include "D3MFOpcPackage.h"
|
||||
|
@ -83,15 +83,8 @@ void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pSce
|
|||
|
||||
namespace D3MF {
|
||||
|
||||
D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
|
||||
: mArchiveName( pFile )
|
||||
, m_zipArchive( nullptr )
|
||||
, mScene( pScene )
|
||||
, mModelOutput()
|
||||
, mRelOutput()
|
||||
, mContentOutput()
|
||||
, mBuildItems()
|
||||
, mRelations() {
|
||||
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
|
||||
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
|
|||
|
||||
writeObjects();
|
||||
|
||||
|
||||
mModelOutput << "</" << XmlTag::resources << ">";
|
||||
mModelOutput << std::endl;
|
||||
writeBuild();
|
||||
|
@ -254,16 +246,27 @@ void D3MFExporter::writeBaseMaterials() {
|
|||
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
|
||||
hexDiffuseColor.clear();
|
||||
tmp.clear();
|
||||
hexDiffuseColor = "#";
|
||||
// rgbs %
|
||||
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
|
||||
|
||||
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";
|
||||
}
|
||||
|
@ -284,7 +287,7 @@ void D3MFExporter::writeObjects() {
|
|||
if (nullptr == currentNode) {
|
||||
continue;
|
||||
}
|
||||
mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
|
||||
mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
|
||||
mModelOutput << std::endl;
|
||||
for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
|
||||
aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
|
||||
|
@ -348,7 +351,7 @@ void D3MFExporter::writeBuild() {
|
|||
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
|
||||
|
||||
for (size_t i = 0; i < mBuildItems.size(); ++i) {
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
mModelOutput << "</" << XmlTag::build << ">";
|
||||
|
@ -394,7 +397,6 @@ void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::str
|
|||
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>
|
||||
|
||||
|
@ -73,12 +73,12 @@ public:
|
|||
using MatArray = std::vector<aiMaterial *>;
|
||||
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
|
||||
|
||||
XmlSerializer(XmlReader* xmlReader)
|
||||
: mMeshes()
|
||||
, mMatArray()
|
||||
, mActiveMatGroup( 99999999 )
|
||||
, mMatId2MatArray()
|
||||
, xmlReader(xmlReader){
|
||||
XmlSerializer(XmlReader *xmlReader) :
|
||||
mMeshes(),
|
||||
mMatArray(),
|
||||
mActiveMatGroup(99999999),
|
||||
mMatId2MatArray(),
|
||||
xmlReader(xmlReader) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,6 @@ private:
|
|||
++buf;
|
||||
diffuse.r = static_cast<ai_real>(strtol(comp, NULL, 16)) / ai_real(255.0);
|
||||
|
||||
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
|
@ -346,7 +345,6 @@ private:
|
|||
if (parseColor(color, diffuse)) {
|
||||
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
}
|
||||
aiMaterial *readMaterialDef() {
|
||||
aiMaterial *mat(nullptr);
|
||||
|
@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
|
|||
"3mf"
|
||||
};
|
||||
|
||||
D3MFImporter::D3MFImporter()
|
||||
: BaseImporter() {
|
||||
D3MFImporter::D3MFImporter() :
|
||||
BaseImporter() {
|
||||
// empty
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG(rootFile);
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
|
||||
|
||||
mZipArchive->Close(fileStream);
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
|
@ -6,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -44,25 +41,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file Implementation of the AC3D importer class */
|
||||
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_AC_IMPORTER
|
||||
|
||||
// internal headers
|
||||
#include "ACLoader.h"
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/Subdivision.h>
|
||||
#include "Common/Importer.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/Subdivision.h>
|
||||
#include <assimp/config.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/light.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/config.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -82,83 +77,82 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// skip to the next token
|
||||
#define AI_AC_SKIP_TO_NEXT_TOKEN() \
|
||||
if (!SkipSpaces(&buffer)) \
|
||||
{ \
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \
|
||||
continue; \
|
||||
inline const char *AcSkipToNextToken(const char *buffer) {
|
||||
if (!SkipSpaces(&buffer)) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a string (may be enclosed in double quotation marks). buffer must point to "
|
||||
#define AI_AC_GET_STRING(out) \
|
||||
if (*buffer == '\0') { \
|
||||
throw DeadlyImportError("AC3D: Unexpected EOF in string"); \
|
||||
} \
|
||||
++buffer; \
|
||||
const char* sz = buffer; \
|
||||
while ('\"' != *buffer) \
|
||||
{ \
|
||||
if (IsLineEnd( *buffer )) \
|
||||
{ \
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \
|
||||
out = "ERROR"; \
|
||||
break; \
|
||||
} \
|
||||
++buffer; \
|
||||
} \
|
||||
if (IsLineEnd( *buffer ))continue; \
|
||||
out = std::string(sz,(unsigned int)(buffer-sz)); \
|
||||
inline const char *AcGetString(const char *buffer, std::string &out) {
|
||||
if (*buffer == '\0') {
|
||||
throw DeadlyImportError("AC3D: Unexpected EOF in string");
|
||||
}
|
||||
++buffer;
|
||||
const char *sz = buffer;
|
||||
while ('\"' != *buffer) {
|
||||
if (IsLineEnd(*buffer)) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
|
||||
out = "ERROR";
|
||||
break;
|
||||
}
|
||||
++buffer;
|
||||
}
|
||||
if (IsLineEnd(*buffer)) {
|
||||
return buffer;
|
||||
}
|
||||
out = std::string(sz, (unsigned int)(buffer - sz));
|
||||
++buffer;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read 1 to n floats prefixed with an optional predefined identifier
|
||||
#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
|
||||
AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
||||
if (name_length) \
|
||||
{ \
|
||||
if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
|
||||
{ \
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \
|
||||
continue; \
|
||||
} \
|
||||
buffer += name_length+1; \
|
||||
} \
|
||||
for (unsigned int i = 0; i < num;++i) \
|
||||
{ \
|
||||
AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
||||
buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
|
||||
template <class T>
|
||||
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
|
||||
buffer = AcSkipToNextToken(buffer);
|
||||
if (0 != name_length) {
|
||||
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string(name) + " was expected.");
|
||||
return buffer;
|
||||
}
|
||||
buffer += name_length + 1;
|
||||
}
|
||||
for (unsigned int _i = 0; _i < num; ++_i) {
|
||||
buffer = AcSkipToNextToken(buffer);
|
||||
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
AC3DImporter::AC3DImporter()
|
||||
: buffer(),
|
||||
AC3DImporter::AC3DImporter() :
|
||||
buffer(),
|
||||
configSplitBFCull(),
|
||||
configEvalSubdivision(),
|
||||
mNumMeshes(),
|
||||
mLights(),
|
||||
lights(),
|
||||
groups(),
|
||||
polys(),
|
||||
worlds()
|
||||
{
|
||||
mLightsCounter(0),
|
||||
mGroupsCounter(0),
|
||||
mPolysCounter(0),
|
||||
mWorldsCounter(0) {
|
||||
// nothing to be done here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
AC3DImporter::~AC3DImporter()
|
||||
{
|
||||
AC3DImporter::~AC3DImporter() {
|
||||
// nothing to be done here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
std::string extension = GetExtension(pFile);
|
||||
|
||||
// fixme: are acc and ac3d *really* used? Some sources say they are
|
||||
|
@ -174,23 +168,20 @@ bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* AC3DImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *AC3DImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a pointer to the next line from the file
|
||||
bool AC3DImporter::GetNextLine( )
|
||||
{
|
||||
bool AC3DImporter::GetNextLine() {
|
||||
SkipLine(&buffer);
|
||||
return SkipSpaces(&buffer);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Parse an object section in an AC file
|
||||
void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
||||
{
|
||||
void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
||||
if (!TokenMatch(buffer, "OBJECT", 6))
|
||||
return;
|
||||
|
||||
|
@ -201,9 +192,8 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
objects.push_back(Object());
|
||||
Object &obj = objects.back();
|
||||
|
||||
aiLight* light = NULL;
|
||||
if (!ASSIMP_strincmp(buffer,"light",5))
|
||||
{
|
||||
aiLight *light = nullptr;
|
||||
if (!ASSIMP_strincmp(buffer, "light", 5)) {
|
||||
// This is a light source. Add it to the list
|
||||
mLights->push_back(light = new aiLight());
|
||||
|
||||
|
@ -217,85 +207,59 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
|
||||
obj.name = std::string(light->mName.data);
|
||||
|
||||
ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
|
||||
obj.type = Object::Light;
|
||||
}
|
||||
else if (!ASSIMP_strincmp(buffer,"group",5))
|
||||
{
|
||||
} else if (!ASSIMP_strincmp(buffer, "group", 5)) {
|
||||
obj.type = Object::Group;
|
||||
}
|
||||
else if (!ASSIMP_strincmp(buffer,"world",5))
|
||||
{
|
||||
} else if (!ASSIMP_strincmp(buffer, "world", 5)) {
|
||||
obj.type = Object::World;
|
||||
}
|
||||
else obj.type = Object::Poly;
|
||||
while (GetNextLine())
|
||||
{
|
||||
if (TokenMatch(buffer,"kids",4))
|
||||
{
|
||||
} else
|
||||
obj.type = Object::Poly;
|
||||
while (GetNextLine()) {
|
||||
if (TokenMatch(buffer, "kids", 4)) {
|
||||
SkipSpaces(&buffer);
|
||||
unsigned int num = strtoul10(buffer, &buffer);
|
||||
GetNextLine();
|
||||
if (num)
|
||||
{
|
||||
if (num) {
|
||||
// load the children of this object recursively
|
||||
obj.children.reserve(num);
|
||||
for (unsigned int i = 0; i < num; ++i)
|
||||
LoadObjectSection(obj.children);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (TokenMatch(buffer,"name",4))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "name", 4)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_GET_STRING(obj.name);
|
||||
buffer = AcGetString(buffer, obj.name);
|
||||
|
||||
// If this is a light source, we'll also need to store
|
||||
// the name of the node in it.
|
||||
if (light)
|
||||
{
|
||||
if (light) {
|
||||
light->mName.Set(obj.name);
|
||||
}
|
||||
}
|
||||
else if (TokenMatch(buffer,"texture",7))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "texture", 7)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_GET_STRING(obj.texture);
|
||||
}
|
||||
else if (TokenMatch(buffer,"texrep",6))
|
||||
{
|
||||
buffer = AcGetString(buffer, obj.texture);
|
||||
} else if (TokenMatch(buffer, "texrep", 6)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
|
||||
if (!obj.texRepeat.x || !obj.texRepeat.y)
|
||||
obj.texRepeat = aiVector2D(1.f, 1.f);
|
||||
}
|
||||
else if (TokenMatch(buffer,"texoff",6))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "texoff", 6)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
|
||||
}
|
||||
else if (TokenMatch(buffer,"rot",3))
|
||||
{
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset);
|
||||
} else if (TokenMatch(buffer, "rot", 3)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
|
||||
}
|
||||
else if (TokenMatch(buffer,"loc",3))
|
||||
{
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation);
|
||||
} else if (TokenMatch(buffer, "loc", 3)) {
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
|
||||
}
|
||||
else if (TokenMatch(buffer,"subdiv",6))
|
||||
{
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation);
|
||||
} else if (TokenMatch(buffer, "subdiv", 6)) {
|
||||
SkipSpaces(&buffer);
|
||||
obj.subDiv = strtoul10(buffer, &buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"crease",6))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "crease", 6)) {
|
||||
SkipSpaces(&buffer);
|
||||
obj.crease = fast_atof(buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"numvert",7))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "numvert", 7)) {
|
||||
SkipSpaces(&buffer);
|
||||
|
||||
unsigned int t = strtoul10(buffer, &buffer);
|
||||
|
@ -303,43 +267,34 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
|
||||
}
|
||||
obj.vertices.reserve(t);
|
||||
for (unsigned int i = 0; i < t;++i)
|
||||
{
|
||||
if (!GetNextLine())
|
||||
{
|
||||
for (unsigned int i = 0; i < t; ++i) {
|
||||
if (!GetNextLine()) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
|
||||
break;
|
||||
}
|
||||
else if (!IsNumeric(*buffer))
|
||||
{
|
||||
} else if (!IsNumeric(*buffer)) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
|
||||
--buffer; // make sure the line is processed a second time
|
||||
break;
|
||||
}
|
||||
obj.vertices.push_back(aiVector3D());
|
||||
aiVector3D &v = obj.vertices.back();
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x);
|
||||
}
|
||||
}
|
||||
else if (TokenMatch(buffer,"numsurf",7))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "numsurf", 7)) {
|
||||
SkipSpaces(&buffer);
|
||||
|
||||
bool Q3DWorkAround = false;
|
||||
|
||||
const unsigned int t = strtoul10(buffer, &buffer);
|
||||
obj.surfaces.reserve(t);
|
||||
for (unsigned int i = 0; i < t;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < t; ++i) {
|
||||
GetNextLine();
|
||||
if (!TokenMatch(buffer,"SURF",4))
|
||||
{
|
||||
if (!TokenMatch(buffer, "SURF", 4)) {
|
||||
// FIX: this can occur for some files - Quick 3D for
|
||||
// example writes no surf chunks
|
||||
if (!Q3DWorkAround)
|
||||
{
|
||||
if (!Q3DWorkAround) {
|
||||
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
|
||||
ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
|
||||
}
|
||||
--buffer; // make sure the line is processed a second time
|
||||
// break; --- see fix notes above
|
||||
|
@ -351,24 +306,17 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
Surface &surf = obj.surfaces.back();
|
||||
surf.flags = strtoul_cppstyle(buffer);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if(!GetNextLine())
|
||||
{
|
||||
while (1) {
|
||||
if (!GetNextLine()) {
|
||||
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
|
||||
}
|
||||
if (TokenMatch(buffer,"mat",3))
|
||||
{
|
||||
if (TokenMatch(buffer, "mat", 3)) {
|
||||
SkipSpaces(&buffer);
|
||||
surf.mat = strtoul10(buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"refs",4))
|
||||
{
|
||||
} else if (TokenMatch(buffer, "refs", 4)) {
|
||||
// --- see fix notes above
|
||||
if (Q3DWorkAround)
|
||||
{
|
||||
if (!surf.entries.empty())
|
||||
{
|
||||
if (Q3DWorkAround) {
|
||||
if (!surf.entries.empty()) {
|
||||
buffer -= 6;
|
||||
break;
|
||||
}
|
||||
|
@ -380,10 +328,8 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
|
||||
obj.numRefs += m;
|
||||
|
||||
for (unsigned int k = 0; k < m; ++k)
|
||||
{
|
||||
if(!GetNextLine())
|
||||
{
|
||||
for (unsigned int k = 0; k < m; ++k) {
|
||||
if (!GetNextLine()) {
|
||||
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete");
|
||||
break;
|
||||
}
|
||||
|
@ -392,12 +338,9 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
|
||||
entry.first = strtoul10(buffer, &buffer);
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
} else {
|
||||
--buffer; // make sure the line is processed a second time
|
||||
break;
|
||||
}
|
||||
|
@ -412,24 +355,20 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
// Convert a material from AC3DImporter::Material to aiMaterial
|
||||
void AC3DImporter::ConvertMaterial(const Object &object,
|
||||
const Material &matSrc,
|
||||
aiMaterial& matDest)
|
||||
{
|
||||
aiMaterial &matDest) {
|
||||
aiString s;
|
||||
|
||||
if (matSrc.name.length())
|
||||
{
|
||||
if (matSrc.name.length()) {
|
||||
s.Set(matSrc.name);
|
||||
matDest.AddProperty(&s, AI_MATKEY_NAME);
|
||||
}
|
||||
if (object.texture.length())
|
||||
{
|
||||
if (object.texture.length()) {
|
||||
s.Set(object.texture);
|
||||
matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
||||
// UV transformation
|
||||
if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
|
||||
object.texOffset.x || object.texOffset.y)
|
||||
{
|
||||
object.texOffset.x || object.texOffset.y) {
|
||||
aiUVTransform transform;
|
||||
transform.mScaling = object.texRepeat;
|
||||
transform.mTranslation = object.texOffset;
|
||||
|
@ -442,13 +381,13 @@ void AC3DImporter::ConvertMaterial(const Object& object,
|
|||
matDest.AddProperty<aiColor3D>(&matSrc.emis, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
matDest.AddProperty<aiColor3D>(&matSrc.spec, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
int n;
|
||||
if (matSrc.shin)
|
||||
{
|
||||
int n = -1;
|
||||
if (matSrc.shin) {
|
||||
n = aiShadingMode_Phong;
|
||||
matDest.AddProperty<float>(&matSrc.shin, 1, AI_MATKEY_SHININESS);
|
||||
} else {
|
||||
n = aiShadingMode_Gouraud;
|
||||
}
|
||||
else n = aiShadingMode_Gouraud;
|
||||
matDest.AddProperty<int>(&n, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
float f = 1.f - matSrc.trans;
|
||||
|
@ -461,14 +400,11 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiMaterial *> &outMaterials,
|
||||
const std::vector<Material> &materials,
|
||||
aiNode* parent)
|
||||
{
|
||||
aiNode *parent) {
|
||||
aiNode *node = new aiNode();
|
||||
node->mParent = parent;
|
||||
if (object.vertices.size())
|
||||
{
|
||||
if (!object.surfaces.size() || !object.numRefs)
|
||||
{
|
||||
if (object.vertices.size()) {
|
||||
if (!object.surfaces.size() || !object.numRefs) {
|
||||
/* " An object with 7 vertices (no surfaces, no materials defined).
|
||||
This is a good way of getting point data into AC3D.
|
||||
The Vertex->create convex-surface/object can be used on these
|
||||
|
@ -488,8 +424,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
aiVector3D *verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
|
||||
{
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i, ++faces, ++verts) {
|
||||
*verts = object.vertices[i];
|
||||
faces->mNumIndices = 1;
|
||||
faces->mIndices = new unsigned int[1];
|
||||
|
@ -502,9 +437,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
mesh->mMaterialIndex = 0;
|
||||
outMaterials.push_back(new aiMaterial());
|
||||
ConvertMaterial(object, materials[0], *outMaterials.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// need to generate one or more meshes for this object.
|
||||
// find out how many different materials we have
|
||||
typedef std::pair<unsigned int, unsigned int> IntPair;
|
||||
|
@ -514,53 +447,46 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
std::vector<Surface>::iterator it, end = object.surfaces.end();
|
||||
std::vector<Surface::SurfaceEntry>::iterator it2, end2;
|
||||
|
||||
for (it = object.surfaces.begin(); it != end; ++it)
|
||||
{
|
||||
for (it = object.surfaces.begin(); it != end; ++it) {
|
||||
unsigned int idx = (*it).mat;
|
||||
if (idx >= needMat.size())
|
||||
{
|
||||
if (idx >= needMat.size()) {
|
||||
ASSIMP_LOG_ERROR("AC3D: material index is out of range");
|
||||
idx = 0;
|
||||
}
|
||||
if ((*it).entries.empty())
|
||||
{
|
||||
if ((*it).entries.empty()) {
|
||||
ASSIMP_LOG_WARN("AC3D: surface her zero vertex references");
|
||||
}
|
||||
|
||||
// validate all vertex indices to make sure we won't crash here
|
||||
for (it2 = (*it).entries.begin(),
|
||||
end2 = (*it).entries.end(); it2 != end2; ++it2)
|
||||
{
|
||||
if ((*it2).first >= object.vertices.size())
|
||||
{
|
||||
end2 = (*it).entries.end();
|
||||
it2 != end2; ++it2) {
|
||||
if ((*it2).first >= object.vertices.size()) {
|
||||
ASSIMP_LOG_WARN("AC3D: Invalid vertex reference");
|
||||
(*it2).first = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needMat[idx].first)++node->mNumMeshes;
|
||||
if (!needMat[idx].first) {
|
||||
++node->mNumMeshes;
|
||||
}
|
||||
|
||||
switch ((*it).flags & 0xf)
|
||||
{
|
||||
switch ((*it).flags & 0xf) {
|
||||
// closed line
|
||||
case 0x1:
|
||||
|
||||
needMat[idx].first += (unsigned int)(*it).entries.size();
|
||||
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
|
||||
break;
|
||||
|
||||
// unclosed line
|
||||
case 0x2:
|
||||
|
||||
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
|
||||
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
|
||||
break;
|
||||
|
||||
// 0 == polygon, else unknown
|
||||
default:
|
||||
|
||||
if ((*it).flags & 0xf)
|
||||
{
|
||||
if ((*it).flags & 0xf) {
|
||||
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
|
||||
(*it).flags &= ~(0xf);
|
||||
}
|
||||
|
@ -575,16 +501,17 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
unsigned int mat = 0;
|
||||
const size_t oldm = meshes.size();
|
||||
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
|
||||
cit != cend; ++cit, ++mat)
|
||||
{
|
||||
if (!(*cit).first)continue;
|
||||
cit != cend; ++cit, ++mat) {
|
||||
if (!(*cit).first) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// allocate a new aiMesh object
|
||||
*pip++ = (unsigned int)meshes.size();
|
||||
aiMesh *mesh = new aiMesh();
|
||||
meshes.push_back(mesh);
|
||||
|
||||
mesh->mMaterialIndex = (unsigned int)outMaterials.size();
|
||||
mesh->mMaterialIndex = static_cast<unsigned int>(outMaterials.size());
|
||||
outMaterials.push_back(new aiMaterial());
|
||||
ConvertMaterial(object, materials[mat], *outMaterials.back());
|
||||
|
||||
|
@ -608,29 +535,24 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
|
||||
// allocate UV coordinates, but only if the texture name for the
|
||||
// surface is not empty
|
||||
aiVector3D* uv = NULL;
|
||||
if(object.texture.length())
|
||||
{
|
||||
aiVector3D *uv = nullptr;
|
||||
if (object.texture.length()) {
|
||||
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mNumUVComponents[0] = 2;
|
||||
}
|
||||
|
||||
for (it = object.surfaces.begin(); it != end; ++it)
|
||||
{
|
||||
if (mat == (*it).mat)
|
||||
{
|
||||
for (it = object.surfaces.begin(); it != end; ++it) {
|
||||
if (mat == (*it).mat) {
|
||||
const Surface &src = *it;
|
||||
|
||||
// closed polygon
|
||||
unsigned int type = (*it).flags & 0xf;
|
||||
if (!type)
|
||||
{
|
||||
if (!type) {
|
||||
aiFace &face = *faces++;
|
||||
if((face.mNumIndices = (unsigned int)src.entries.size()))
|
||||
{
|
||||
face.mNumIndices = (unsigned int)src.entries.size();
|
||||
if (0 != face.mNumIndices) {
|
||||
face.mIndices = new unsigned int[face.mNumIndices];
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
|
||||
{
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) {
|
||||
const Surface::SurfaceEntry &entry = src.entries[i];
|
||||
face.mIndices[i] = cur++;
|
||||
|
||||
|
@ -640,27 +562,22 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
}
|
||||
*vertices = object.vertices[entry.first] + object.translation;
|
||||
|
||||
|
||||
// copy texture coordinates
|
||||
if (uv)
|
||||
{
|
||||
if (uv) {
|
||||
uv->x = entry.second.x;
|
||||
uv->y = entry.second.y;
|
||||
++uv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
|
||||
it2 = (*it).entries.begin();
|
||||
|
||||
// either a closed or an unclosed line
|
||||
unsigned int tmp = (unsigned int)(*it).entries.size();
|
||||
if (0x2 == type) --tmp;
|
||||
for (unsigned int m = 0; m < tmp;++m)
|
||||
{
|
||||
for (unsigned int m = 0; m < tmp; ++m) {
|
||||
aiFace &face = *faces++;
|
||||
|
||||
face.mNumIndices = 2;
|
||||
|
@ -676,26 +593,22 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
*vertices++ = object.vertices[(*it2).first];
|
||||
|
||||
// copy texture coordinates
|
||||
if (uv)
|
||||
{
|
||||
if (uv) {
|
||||
uv->x = (*it2).second.x;
|
||||
uv->y = (*it2).second.y;
|
||||
++uv;
|
||||
}
|
||||
|
||||
|
||||
if (0x1 == type && tmp-1 == m)
|
||||
{
|
||||
if (0x1 == type && tmp - 1 == m) {
|
||||
// if this is a closed line repeat its beginning now
|
||||
it2 = (*it).entries.begin();
|
||||
}
|
||||
else ++it2;
|
||||
} else
|
||||
++it2;
|
||||
|
||||
// second point
|
||||
*vertices++ = object.vertices[(*it2).first];
|
||||
|
||||
if (uv)
|
||||
{
|
||||
if (uv) {
|
||||
uv->x = (*it2).second.x;
|
||||
uv->y = (*it2).second.y;
|
||||
++uv;
|
||||
|
@ -719,10 +632,8 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
|
||||
|
||||
// previous meshes are deleted vy Subdivide().
|
||||
}
|
||||
else {
|
||||
ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: "
|
||||
+object.name);
|
||||
} else {
|
||||
ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " + object.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -730,47 +641,41 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
|
||||
if (object.name.length())
|
||||
node->mName.Set(object.name);
|
||||
else
|
||||
{
|
||||
else {
|
||||
// generate a name depending on the type of the node
|
||||
switch (object.type)
|
||||
{
|
||||
switch (object.type) {
|
||||
case Object::Group:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
|
||||
break;
|
||||
case Object::Poly:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i",polys++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
|
||||
break;
|
||||
case Object::Light:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i",lights++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
|
||||
break;
|
||||
|
||||
// there shouldn't be more than one world, but we don't care
|
||||
case Object::World:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i",worlds++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// setup the local transformation matrix of the object
|
||||
// compute the transformation offset to the parent node
|
||||
node->mTransformation = aiMatrix4x4(object.rotation);
|
||||
|
||||
if (object.type == Object::Group || !object.numRefs)
|
||||
{
|
||||
if (object.type == Object::Group || !object.numRefs) {
|
||||
node->mTransformation.a4 = object.translation.x;
|
||||
node->mTransformation.b4 = object.translation.y;
|
||||
node->mTransformation.c4 = object.translation.z;
|
||||
}
|
||||
|
||||
// add children to the object
|
||||
if (object.children.size())
|
||||
{
|
||||
if (object.children.size()) {
|
||||
node->mNumChildren = (unsigned int)object.children.size();
|
||||
node->mChildren = new aiNode *[node->mNumChildren];
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
node->mChildren[i] = ConvertObjectSection(object.children[i], meshes, outMaterials, materials, node);
|
||||
}
|
||||
}
|
||||
|
@ -779,8 +684,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AC3DImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
void AC3DImporter::SetupProperties(const Importer *pImp) {
|
||||
configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL, 1) ? true : false;
|
||||
configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION, 1) ? true : false;
|
||||
}
|
||||
|
@ -788,13 +692,13 @@ void AC3DImporter::SetupProperties(const Importer* pImp)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void AC3DImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
if (file.get() == nullptr) {
|
||||
throw DeadlyImportError("Failed to open AC3D file " + pFile + ".");
|
||||
}
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
std::vector<char> mBuffer2;
|
||||
|
@ -803,7 +707,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
buffer = &mBuffer2[0];
|
||||
mNumMeshes = 0;
|
||||
|
||||
lights = polys = worlds = groups = 0;
|
||||
mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
|
||||
|
||||
if (::strncmp(buffer, "AC3D", 4)) {
|
||||
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
|
||||
|
@ -824,39 +728,34 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
std::vector<aiLight *> lights;
|
||||
mLights = &lights;
|
||||
|
||||
while (GetNextLine())
|
||||
{
|
||||
if (TokenMatch(buffer,"MATERIAL",8))
|
||||
{
|
||||
while (GetNextLine()) {
|
||||
if (TokenMatch(buffer, "MATERIAL", 8)) {
|
||||
materials.push_back(Material());
|
||||
Material &mat = materials.back();
|
||||
|
||||
// manually parse the material ... sscanf would use the buldin atof ...
|
||||
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
|
||||
|
||||
AI_AC_SKIP_TO_NEXT_TOKEN();
|
||||
if ('\"' == *buffer)
|
||||
{
|
||||
AI_AC_GET_STRING(mat.name);
|
||||
AI_AC_SKIP_TO_NEXT_TOKEN();
|
||||
buffer = AcSkipToNextToken(buffer);
|
||||
if ('\"' == *buffer) {
|
||||
buffer = AcGetString(buffer, mat.name);
|
||||
buffer = AcSkipToNextToken(buffer);
|
||||
}
|
||||
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
|
||||
}
|
||||
LoadObjectSection(rootObjects);
|
||||
}
|
||||
|
||||
if (rootObjects.empty() || !mNumMeshes)
|
||||
{
|
||||
if (rootObjects.empty() || !mNumMeshes) {
|
||||
throw DeadlyImportError("AC3D: No meshes have been loaded");
|
||||
}
|
||||
if (materials.empty())
|
||||
{
|
||||
if (materials.empty()) {
|
||||
ASSIMP_LOG_WARN("AC3D: No material has been found");
|
||||
materials.push_back(Material());
|
||||
}
|
||||
|
@ -872,21 +771,22 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
Object *root;
|
||||
if (1 == rootObjects.size())
|
||||
root = &rootObjects[0];
|
||||
else
|
||||
{
|
||||
else {
|
||||
root = new Object();
|
||||
}
|
||||
|
||||
// now convert the imported stuff to our output data structure
|
||||
pScene->mRootNode = ConvertObjectSection(*root, meshes, omaterials, materials);
|
||||
if (1 != rootObjects.size())delete root;
|
||||
if (1 != rootObjects.size()) {
|
||||
delete root;
|
||||
}
|
||||
|
||||
if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
|
||||
if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) {
|
||||
pScene->mRootNode->mName.Set("<AC3DWorld>");
|
||||
}
|
||||
|
||||
// copy meshes
|
||||
if (meshes.empty())
|
||||
{
|
||||
if (meshes.empty()) {
|
||||
throw DeadlyImportError("An unknown error occurred during converting");
|
||||
}
|
||||
pScene->mNumMeshes = (unsigned int)meshes.size();
|
||||
|
@ -900,8 +800,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// copy lights
|
||||
pScene->mNumLights = (unsigned int)lights.size();
|
||||
if (lights.size())
|
||||
{
|
||||
if (lights.size()) {
|
||||
pScene->mLights = new aiLight *[lights.size()];
|
||||
::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
|
||||
}
|
|
@ -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,12 +94,9 @@ public:
|
|||
};
|
||||
|
||||
// Represents an AC3D surface
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: mat (0)
|
||||
, flags (0)
|
||||
{}
|
||||
struct Surface {
|
||||
Surface() :
|
||||
mat(0), flags(0) {}
|
||||
|
||||
unsigned int mat, flags;
|
||||
|
||||
|
@ -117,27 +105,12 @@ public:
|
|||
};
|
||||
|
||||
// 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,9 +152,7 @@ public:
|
|||
float crease;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
|
@ -190,7 +161,6 @@ public:
|
|||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details */
|
||||
|
@ -209,7 +179,6 @@ protected:
|
|||
void SetupProperties(const Importer *pImp);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached*/
|
||||
|
@ -233,7 +202,7 @@ private:
|
|||
std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiMaterial *> &outMaterials,
|
||||
const std::vector<Material> &materials,
|
||||
aiNode* parent = NULL);
|
||||
aiNode *parent = nullptr);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
||||
|
@ -245,8 +214,6 @@ private:
|
|||
aiMaterial &matDest);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// points to the next data line
|
||||
const char *buffer;
|
||||
|
||||
|
@ -268,7 +235,7 @@ private:
|
|||
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
|
|
@ -51,15 +51,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// internal headers
|
||||
#include "ASELoader.h"
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include "Common/TargetAnimation.h"
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -84,12 +84,8 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ASEImporter::ASEImporter()
|
||||
: mParser()
|
||||
, mBuffer()
|
||||
, pcScene()
|
||||
, configRecomputeNormals()
|
||||
, noSkeletonMesh() {
|
||||
ASEImporter::ASEImporter() :
|
||||
mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -126,7 +122,9 @@ const aiImporterDesc* ASEImporter::GetInfo () const {
|
|||
// Setup configuration options
|
||||
void ASEImporter::SetupProperties(const Importer *pImp) {
|
||||
configRecomputeNormals = (pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
|
||||
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS, 1) ?
|
||||
true :
|
||||
false);
|
||||
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||
}
|
||||
|
@ -226,17 +224,20 @@ void ASEImporter::InternReadFile( const std::string& pFile,
|
|||
// into one huge list.
|
||||
//------------------------------------------------------------------
|
||||
std::vector<BaseNode *> nodes;
|
||||
nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
|
||||
+ mParser->m_vCameras.size() + mParser->m_vDummies.size());
|
||||
nodes.reserve(mParser->m_vMeshes.size() + mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size());
|
||||
|
||||
// Lights
|
||||
for (auto &light : mParser->m_vLights)nodes.push_back(&light);
|
||||
for (auto &light : mParser->m_vLights)
|
||||
nodes.push_back(&light);
|
||||
// Cameras
|
||||
for (auto &camera : mParser->m_vCameras)nodes.push_back(&camera);
|
||||
for (auto &camera : mParser->m_vCameras)
|
||||
nodes.push_back(&camera);
|
||||
// Meshes
|
||||
for (auto &mesh : mParser->m_vMeshes)nodes.push_back(&mesh);
|
||||
for (auto &mesh : mParser->m_vMeshes)
|
||||
nodes.push_back(&mesh);
|
||||
// Dummies
|
||||
for (auto &dummy : mParser->m_vDummies)nodes.push_back(&dummy);
|
||||
for (auto &dummy : mParser->m_vDummies)
|
||||
nodes.push_back(&dummy);
|
||||
|
||||
// build the final node graph
|
||||
BuildNodes(nodes);
|
||||
|
@ -263,9 +264,8 @@ void ASEImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::GenerateDefaultMaterial()
|
||||
{
|
||||
ai_assert(NULL != mParser);
|
||||
void ASEImporter::GenerateDefaultMaterial() {
|
||||
ai_assert(nullptr != mParser);
|
||||
|
||||
bool bHas = false;
|
||||
for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
|
||||
|
@ -288,8 +288,7 @@ void ASEImporter::GenerateDefaultMaterial()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
||||
{
|
||||
void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
|
||||
// check whether we have at least one mesh which has animations
|
||||
std::vector<ASE::BaseNode *>::const_iterator i = nodes.begin();
|
||||
unsigned int iNum = 0;
|
||||
|
@ -370,8 +369,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
|||
nd->mNodeName.Set(me->mName);
|
||||
|
||||
// copy position keys
|
||||
if (me->mAnim.akeyPositions.size() > 1 )
|
||||
{
|
||||
if (me->mAnim.akeyPositions.size() > 1) {
|
||||
// Allocate the key array and fill it
|
||||
nd->mNumPositionKeys = (unsigned int)me->mAnim.akeyPositions.size();
|
||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||
|
@ -424,8 +422,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output cameras
|
||||
void ASEImporter::BuildCameras()
|
||||
{
|
||||
void ASEImporter::BuildCameras() {
|
||||
if (!mParser->m_vCameras.empty()) {
|
||||
pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
|
||||
pcScene->mCameras = new aiCamera *[pcScene->mNumCameras];
|
||||
|
@ -446,8 +443,7 @@ void ASEImporter::BuildCameras()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output lights
|
||||
void ASEImporter::BuildLights()
|
||||
{
|
||||
void ASEImporter::BuildLights() {
|
||||
if (!mParser->m_vLights.empty()) {
|
||||
pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
|
||||
pcScene->mLights = new aiLight *[pcScene->mNumLights];
|
||||
|
@ -462,8 +458,7 @@ void ASEImporter::BuildLights()
|
|||
out->mDirection = aiVector3D(0.f, 0.f, -1.f);
|
||||
|
||||
out->mName.Set(in.mName);
|
||||
switch (in.mLightType)
|
||||
{
|
||||
switch (in.mLightType) {
|
||||
case ASE::Light::TARGET:
|
||||
out->mType = aiLightSource_SPOT;
|
||||
out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
|
||||
|
@ -486,16 +481,14 @@ void ASEImporter::BuildLights()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode* pcParent,const char* szName)
|
||||
{
|
||||
aiNode *pcParent, const char *szName) {
|
||||
aiMatrix4x4 m;
|
||||
AddNodes(nodes, pcParent, szName, m);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Add meshes to a given node
|
||||
void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
|
||||
{
|
||||
void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
|
||||
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
|
||||
// Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
|
||||
const aiMesh *pcMesh = pcScene->mMeshes[i];
|
||||
|
@ -549,8 +542,7 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
|
|||
// Add child nodes to a given parent node
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode *pcParent, const char *szName,
|
||||
const aiMatrix4x4& mat)
|
||||
{
|
||||
const aiMatrix4x4 &mat) {
|
||||
const size_t len = szName ? ::strlen(szName) : 0;
|
||||
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
|
||||
|
||||
|
@ -564,8 +556,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
if (szName) {
|
||||
if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str()))
|
||||
continue;
|
||||
}
|
||||
else if (snode->mParent.length())
|
||||
} else if (snode->mParent.length())
|
||||
continue;
|
||||
|
||||
(*it)->mProcessed = true;
|
||||
|
@ -595,8 +586,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
// slightly inconvinient here and a better solution should
|
||||
// be used when this code is refactored next.
|
||||
AddMeshes(snode, node);
|
||||
}
|
||||
else if (is_not_qnan( snode->mTargetPosition.x )) {
|
||||
} else if (is_not_qnan(snode->mTargetPosition.x)) {
|
||||
// If this is a target camera or light we generate a small
|
||||
// child node which marks the position of the camera
|
||||
// target (the direction information is contained in *this*
|
||||
|
@ -624,7 +614,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
node->mNumChildren++;
|
||||
|
||||
// What we did is so great, it is at least worth a debug message
|
||||
ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (" + snode->mName + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,7 +634,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Build the output node graph
|
||||
void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
|
||||
ai_assert(NULL != pcScene);
|
||||
ai_assert(nullptr != pcScene);
|
||||
|
||||
// allocate the one and only root node
|
||||
aiNode *root = pcScene->mRootNode = new aiNode();
|
||||
|
@ -663,7 +653,7 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
|
|||
}
|
||||
|
||||
// add all nodes
|
||||
AddNodes(nodes,ch,NULL);
|
||||
AddNodes(nodes, ch, nullptr);
|
||||
|
||||
// now iterate through al nodes and find those that have not yet
|
||||
// been added to the nodegraph (= their parent could not be recognized)
|
||||
|
@ -723,9 +713,9 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
|
|||
pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
|
||||
}
|
||||
|
||||
// Reset the third color set to NULL - we used this field to store a temporary pointer
|
||||
// Reset the third color set to nullptr - we used this field to store a temporary pointer
|
||||
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i)
|
||||
pcScene->mMeshes[i]->mColors[2] = NULL;
|
||||
pcScene->mMeshes[i]->mColors[2] = nullptr;
|
||||
|
||||
// The root node should not have at least one child or the file is valid
|
||||
if (!pcScene->mRootNode->mNumChildren) {
|
||||
|
@ -773,8 +763,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
|
|||
// iterate through all faces in the mesh
|
||||
unsigned int iCurrent = 0, fi = 0;
|
||||
for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin(); i != mesh.mFaces.end(); ++i, ++fi) {
|
||||
for (unsigned int n = 0; n < 3;++n,++iCurrent)
|
||||
{
|
||||
for (unsigned int n = 0; n < 3; ++n, ++iCurrent) {
|
||||
mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
|
||||
|
||||
// add texture coordinates
|
||||
|
@ -814,8 +803,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Copy a texture from the ASE structs to the output material
|
||||
void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
|
||||
{
|
||||
void CopyASETexture(aiMaterial &mat, ASE::Texture &texture, aiTextureType type) {
|
||||
// Setup the texture name
|
||||
aiString tex;
|
||||
tex.Set(texture.mMapName);
|
||||
|
@ -831,8 +819,7 @@ void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert from ASE material to output material
|
||||
void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
||||
{
|
||||
void ASEImporter::ConvertMaterial(ASE::Material &mat) {
|
||||
// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
|
||||
|
||||
// Allocate the output material
|
||||
|
@ -855,16 +842,14 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
mat.pcInstance->AddProperty(&mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
|
||||
// shininess
|
||||
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
|
||||
{
|
||||
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) {
|
||||
mat.pcInstance->AddProperty(&mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.pcInstance->AddProperty(&mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
}
|
||||
// If there is no shininess, we can disable phong lighting
|
||||
else if (D3DS::Discreet3DS::Metal == mat.mShading ||
|
||||
D3DS::Discreet3DS::Phong == mat.mShading ||
|
||||
D3DS::Discreet3DS::Blinn == mat.mShading)
|
||||
{
|
||||
D3DS::Discreet3DS::Blinn == mat.mShading) {
|
||||
mat.mShading = D3DS::Discreet3DS::Gouraud;
|
||||
}
|
||||
|
||||
|
@ -872,35 +857,37 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
mat.pcInstance->AddProperty<ai_real>(&mat.mTransparency, 1, AI_MATKEY_OPACITY);
|
||||
|
||||
// Two sided rendering?
|
||||
if (mat.mTwoSided)
|
||||
{
|
||||
if (mat.mTwoSided) {
|
||||
int i = 1;
|
||||
mat.pcInstance->AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
// shading mode
|
||||
aiShadingMode eShading = aiShadingMode_NoShading;
|
||||
switch (mat.mShading)
|
||||
{
|
||||
switch (mat.mShading) {
|
||||
case D3DS::Discreet3DS::Flat:
|
||||
eShading = aiShadingMode_Flat; break;
|
||||
eShading = aiShadingMode_Flat;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Phong:
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
eShading = aiShadingMode_Phong;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Blinn:
|
||||
eShading = aiShadingMode_Blinn; break;
|
||||
eShading = aiShadingMode_Blinn;
|
||||
break;
|
||||
|
||||
// I don't know what "Wire" shading should be,
|
||||
// assume it is simple lambertian diffuse (L dot N) shading
|
||||
case D3DS::Discreet3DS::Wire:
|
||||
{
|
||||
case D3DS::Discreet3DS::Wire: {
|
||||
// set the wireframe flag
|
||||
unsigned int iWire = 1;
|
||||
mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
case D3DS::Discreet3DS::Gouraud:
|
||||
eShading = aiShadingMode_Gouraud; break;
|
||||
eShading = aiShadingMode_Gouraud;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Metal:
|
||||
eShading = aiShadingMode_CookTorrance; break;
|
||||
eShading = aiShadingMode_CookTorrance;
|
||||
break;
|
||||
}
|
||||
mat.pcInstance->AddProperty<int>((int *)&eShading, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
|
@ -934,7 +921,8 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
|
||||
// store the name of the material itself, too
|
||||
if (mat.mName.length() > 0) {
|
||||
aiString tex;tex.Set( mat.mName);
|
||||
aiString tex;
|
||||
tex.Set(mat.mName);
|
||||
mat.pcInstance->AddProperty(&tex, AI_MATKEY_NAME);
|
||||
}
|
||||
return;
|
||||
|
@ -942,8 +930,7 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output meshes
|
||||
void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
|
||||
{
|
||||
void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMeshes) {
|
||||
// validate the material index of the mesh
|
||||
if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
|
||||
mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1;
|
||||
|
@ -952,8 +939,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// If the material the mesh is assigned to is consisting of submeshes, split it
|
||||
if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
|
||||
std::vector<ASE::Material> vSubMaterials = mParser->
|
||||
m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
|
||||
std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
|
||||
|
||||
std::vector<unsigned int> *aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
|
||||
|
||||
|
@ -965,8 +951,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// use the last material instead
|
||||
aiSplit[vSubMaterials.size() - 1].push_back(i);
|
||||
}
|
||||
else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
|
||||
} else
|
||||
aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
|
||||
}
|
||||
|
||||
// now generate submeshes
|
||||
|
@ -994,7 +980,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
|
||||
|
||||
// receive output vertex weights
|
||||
std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
|
||||
std::vector<std::pair<unsigned int, float>> *avOutputBones = nullptr;
|
||||
if (!mesh.mBones.empty()) {
|
||||
avOutputBones = new std::vector<std::pair<unsigned int, float>>[mesh.mBones.size()];
|
||||
}
|
||||
|
@ -1041,8 +1027,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
}
|
||||
// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
|
||||
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
|
||||
if (!mesh.amTexCoords[c].empty())
|
||||
{
|
||||
if (!mesh.amTexCoords[c].empty()) {
|
||||
p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
|
||||
iBase = 0;
|
||||
for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
|
||||
|
@ -1075,8 +1060,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones];
|
||||
aiBone **pcBone = p_pcOut->mBones;
|
||||
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
|
||||
{
|
||||
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) {
|
||||
if (!avOutputBones[mrspock].empty()) {
|
||||
// we will need this bone. add it to the output mesh and
|
||||
// add all per-vertex weights
|
||||
|
@ -1086,8 +1070,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
|
||||
pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
||||
|
||||
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
|
||||
{
|
||||
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights; ++captainkirk) {
|
||||
const std::pair<unsigned int, float> &ref = avOutputBones[mrspock][captainkirk];
|
||||
pc->mWeights[captainkirk].mVertexId = ref.first;
|
||||
pc->mWeights[captainkirk].mWeight = ref.second;
|
||||
|
@ -1102,9 +1085,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
}
|
||||
// delete storage
|
||||
delete[] aiSplit;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Otherwise we can simply copy the data to one output mesh
|
||||
// This codepath needs less memory and uses fast memcpy()s
|
||||
// to do the actual copying. So I think it is worth the
|
||||
|
@ -1189,8 +1170,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
for (std::vector<std::pair<int, float>>::const_iterator
|
||||
ronaldweasley = (*harrypotter).mBoneWeights.begin();
|
||||
ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
|
||||
{
|
||||
ronaldweasley != (*harrypotter).mBoneWeights.end(); ++ronaldweasley) {
|
||||
aiVertexWeight weight;
|
||||
weight.mVertexId = quak;
|
||||
weight.mWeight = (*ronaldweasley).second;
|
||||
|
@ -1222,21 +1202,18 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup proper material indices and build output materials
|
||||
void ASEImporter::BuildMaterialIndices()
|
||||
{
|
||||
ai_assert(NULL != pcScene);
|
||||
void ASEImporter::BuildMaterialIndices() {
|
||||
ai_assert(nullptr != pcScene);
|
||||
|
||||
// iterate through all materials and check whether we need them
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
|
||||
{
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
|
||||
ASE::Material &mat = mParser->m_vMaterials[iMat];
|
||||
if (mat.bNeed) {
|
||||
// Convert it to the aiMaterial layout
|
||||
ConvertMaterial(mat);
|
||||
++pcScene->mNumMaterials;
|
||||
}
|
||||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
|
||||
{
|
||||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
|
||||
ASE::Material &submat = mat.avSubMaterials[iSubMat];
|
||||
if (submat.bNeed) {
|
||||
// Convert it to the aiMaterial layout
|
||||
|
@ -1253,9 +1230,8 @@ void ASEImporter::BuildMaterialIndices()
|
|||
unsigned int iNum = 0;
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
|
||||
ASE::Material &mat = mParser->m_vMaterials[iMat];
|
||||
if (mat.bNeed)
|
||||
{
|
||||
ai_assert(NULL != mat.pcInstance);
|
||||
if (mat.bNeed) {
|
||||
ai_assert(nullptr != mat.pcInstance);
|
||||
pcScene->mMaterials[iNum] = mat.pcInstance;
|
||||
|
||||
// Store the internal material, too
|
||||
|
@ -1263,14 +1239,12 @@ void ASEImporter::BuildMaterialIndices()
|
|||
|
||||
// Iterate through all meshes and search for one which is using
|
||||
// this top-level material index
|
||||
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
|
||||
{
|
||||
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) {
|
||||
aiMesh *mesh = pcScene->mMeshes[iMesh];
|
||||
if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
|
||||
iMat == (uintptr_t)mesh->mColors[3])
|
||||
{
|
||||
iMat == (uintptr_t)mesh->mColors[3]) {
|
||||
mesh->mMaterialIndex = iNum;
|
||||
mesh->mColors[3] = NULL;
|
||||
mesh->mColors[3] = nullptr;
|
||||
}
|
||||
}
|
||||
iNum++;
|
||||
|
@ -1278,7 +1252,7 @@ void ASEImporter::BuildMaterialIndices()
|
|||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
|
||||
ASE::Material &submat = mat.avSubMaterials[iSubMat];
|
||||
if (submat.bNeed) {
|
||||
ai_assert(NULL != submat.pcInstance);
|
||||
ai_assert(nullptr != submat.pcInstance);
|
||||
pcScene->mMaterials[iNum] = submat.pcInstance;
|
||||
|
||||
// Store the internal material, too
|
||||
|
@ -1291,7 +1265,7 @@ void ASEImporter::BuildMaterialIndices()
|
|||
|
||||
if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
|
||||
mesh->mMaterialIndex = iNum;
|
||||
mesh->mColors[3] = NULL;
|
||||
mesh->mColors[3] = nullptr;
|
||||
}
|
||||
}
|
||||
iNum++;
|
||||
|
@ -1307,13 +1281,11 @@ void ASEImporter::BuildMaterialIndices()
|
|||
// Generate normal vectors basing on smoothing groups
|
||||
bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) {
|
||||
|
||||
if (!mesh.mNormals.empty() && !configRecomputeNormals)
|
||||
{
|
||||
if (!mesh.mNormals.empty() && !configRecomputeNormals) {
|
||||
// Check whether there are only uninitialized normals. If there are
|
||||
// some, skip all normals from the file and compute them on our own
|
||||
for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin(); qq != mesh.mNormals.end(); ++qq) {
|
||||
if ((*qq).x || (*qq).y || (*qq).z)
|
||||
{
|
||||
if ((*qq).x || (*qq).y || (*qq).z) {
|
||||
return true;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
@ -99,7 +110,7 @@ struct Material : public D3DS::Material
|
|||
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,13 +48,13 @@ 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
|
||||
|
@ -105,8 +103,9 @@ template <typename T>
|
|||
T Read(IOStream *stream) {
|
||||
T t;
|
||||
size_t res = stream->Read(&t, sizeof(T), 1);
|
||||
if(res != 1)
|
||||
if (res != 1) {
|
||||
throw DeadlyImportError("Unexpected EOF");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -114,9 +113,9 @@ T Read(IOStream * stream) {
|
|||
template <>
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -124,10 +123,10 @@ aiVector3D Read<aiVector3D>(IOStream * stream) {
|
|||
template <>
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -135,10 +134,10 @@ aiColor4D Read<aiColor4D>(IOStream * stream) {
|
|||
template <>
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -147,9 +146,11 @@ template <>
|
|||
aiString Read<aiString>(IOStream *stream) {
|
||||
aiString s;
|
||||
stream->Read(&s.length, 4, 1);
|
||||
if(s.length)
|
||||
if (s.length) {
|
||||
stream->Read(s.data, s.length, 1);
|
||||
}
|
||||
s.data[s.length] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ template <>
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -168,7 +169,7 @@ 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);
|
||||
m[i][i2] = Read<ai_real>(stream);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
|
@ -228,8 +229,7 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode*
|
|||
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);
|
||||
|
@ -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));
|
||||
|
@ -312,6 +312,7 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) {
|
|||
static bool fitsIntoUI16(unsigned int mNumVertices) {
|
||||
return (mNumVertices < (1u << 16));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
|
||||
if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
|
||||
|
@ -448,10 +449,8 @@ void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) {
|
|||
/*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];
|
||||
|
@ -666,7 +665,6 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
|
|||
ReadBinaryCamera(stream, scene->mCameras[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
@ -709,8 +707,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
|||
unsigned char *uncompressedData = new unsigned char[uncompressedSize];
|
||||
|
||||
int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len);
|
||||
if(res != Z_OK)
|
||||
{
|
||||
if (res != Z_OK) {
|
||||
delete[] uncompressedData;
|
||||
delete[] compressedData;
|
||||
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
|
||||
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -91,20 +90,20 @@ public:
|
|||
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,8 +155,7 @@ public:
|
|||
void Delimit() {
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buff << ' ';
|
||||
first = false;
|
||||
}
|
||||
|
@ -464,12 +462,11 @@ 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 {
|
||||
} else {
|
||||
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
@ -477,8 +474,8 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
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 {
|
||||
|
@ -486,19 +483,15 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
}
|
||||
break;
|
||||
|
||||
case aiPTI_String:
|
||||
{
|
||||
case aiPTI_String: {
|
||||
aiString s;
|
||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||
out.SimpleValue(s);
|
||||
}
|
||||
break;
|
||||
case aiPTI_Buffer:
|
||||
{
|
||||
} break;
|
||||
case aiPTI_Buffer: {
|
||||
// binary data is written as series of hex-encoded octets
|
||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
@ -525,8 +518,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
|||
out.Key("data");
|
||||
if (!ai.mHeight) {
|
||||
out.SimpleValue(ai.pcData, ai.mWidth);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out.StartArray();
|
||||
for (unsigned int y = 0; y < ai.mHeight; ++y) {
|
||||
out.StartArray(true);
|
||||
|
@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
|||
if (ai.mType != aiLightSource_POINT) {
|
||||
out.Key("direction");
|
||||
Write(out, ai.mDirection, false);
|
||||
|
||||
}
|
||||
|
||||
if (ai.mType != aiLightSource_DIRECTIONAL) {
|
||||
|
@ -774,11 +765,10 @@ void Write(JSONWriter& out, const aiScene& ai) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
|
||||
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
|
||||
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
|
||||
if (!str) {
|
||||
//throw Assimp::DeadlyExportError("could not open output file");
|
||||
throw DeadlyExportError("could not open output file");
|
||||
}
|
||||
|
||||
// get a copy of the scene so we can modify it
|
||||
|
@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
|
|||
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
|
||||
Write(s, *scenecopy_tmp);
|
||||
|
||||
}
|
||||
catch (...) {
|
||||
} catch (...) {
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
throw;
|
||||
}
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -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,22 +73,19 @@ 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);
|
||||
|
||||
|
@ -104,32 +100,31 @@ bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
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)
|
||||
if (file.get() == nullptr) {
|
||||
throw DeadlyImportError("Failed to open file " + pFile + ".");
|
||||
}
|
||||
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize == 0)
|
||||
if (fileSize == 0) {
|
||||
throw DeadlyImportError("File is too small.");
|
||||
}
|
||||
|
||||
mBuffer.resize(fileSize);
|
||||
file->Read(&mBuffer.front(), 1, fileSize);
|
||||
|
@ -150,8 +145,7 @@ void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSys
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the file
|
||||
void BVHLoader::ReadStructure( aiScene* pScene)
|
||||
{
|
||||
void BVHLoader::ReadStructure(aiScene *pScene) {
|
||||
// first comes hierarchy
|
||||
std::string header = GetNextToken();
|
||||
if (header != "HIERARCHY")
|
||||
|
@ -167,8 +161,7 @@ void BVHLoader::ReadStructure( aiScene* 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\".");
|
||||
|
@ -179,8 +172,7 @@ 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 == "{")
|
||||
|
@ -201,8 +193,7 @@ aiNode* BVHLoader::ReadNode()
|
|||
|
||||
// now read the node's contents
|
||||
std::string siteToken;
|
||||
while( 1)
|
||||
{
|
||||
while (1) {
|
||||
std::string token = GetNextToken();
|
||||
|
||||
// node offset to parent node
|
||||
|
@ -210,15 +201,12 @@ aiNode* BVHLoader::ReadNode()
|
|||
ReadNodeOffset(node);
|
||||
else if (token == "CHANNELS")
|
||||
ReadNodeChannels(internNode);
|
||||
else if( token == "JOINT")
|
||||
{
|
||||
else if (token == "JOINT") {
|
||||
// child node follows
|
||||
aiNode *child = ReadNode();
|
||||
child->mParent = node;
|
||||
childNodes.push_back(child);
|
||||
}
|
||||
else if( token == "End")
|
||||
{
|
||||
} else if (token == "End") {
|
||||
// The real symbol is "End Site". Second part comes in a separate token
|
||||
siteToken.clear();
|
||||
siteToken = GetNextToken();
|
||||
|
@ -228,21 +216,17 @@ aiNode* BVHLoader::ReadNode()
|
|||
aiNode *child = ReadEndSite(nodeName);
|
||||
child->mParent = node;
|
||||
childNodes.push_back(child);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
} 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 << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -254,8 +238,7 @@ 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 != "{")
|
||||
|
@ -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();
|
||||
|
@ -304,14 +286,12 @@ 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;
|
||||
|
||||
for( unsigned int a = 0; a < numChannels; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numChannels; a++) {
|
||||
std::string channelToken = GetNextToken();
|
||||
|
||||
if (channelToken == "Xposition")
|
||||
|
@ -333,8 +313,7 @@ void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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:")
|
||||
|
@ -356,11 +335,9 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
|||
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());
|
||||
|
@ -372,11 +349,9 @@ 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())
|
||||
{
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (!isspace(*mReader))
|
||||
break;
|
||||
|
||||
|
@ -389,8 +364,7 @@ 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())
|
||||
{
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (isspace(*mReader))
|
||||
break;
|
||||
|
||||
|
@ -408,8 +382,7 @@ 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");
|
||||
|
@ -427,15 +400,13 @@ float BVHLoader::GetNextTokenAsFloat()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aborts the file reading with an exception
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
|
||||
{
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
|
||||
throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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];
|
||||
|
@ -455,8 +426,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
for (unsigned int i = 0; i < anim->mNumChannels; ++i)
|
||||
anim->mChannels[i] = NULL;
|
||||
|
||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < anim->mNumChannels; a++) {
|
||||
const Node &node = mNodes[a];
|
||||
const std::string nodeName = std::string(node.mNode->mName.data);
|
||||
aiNodeAnim *nodeAnim = new aiNodeAnim;
|
||||
|
@ -465,24 +435,20 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
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)
|
||||
{
|
||||
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,13 +470,11 @@ 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);
|
||||
nodeAnim->mNumPositionKeys = 1;
|
||||
|
@ -526,39 +490,33 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
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:
|
||||
{
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||
}
|
||||
break;
|
||||
case Channel_RotationY:
|
||||
{
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||
}
|
||||
break;
|
||||
case Channel_RotationZ: 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;
|
|
@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
/** Loader class to read Motion Capturing data from a .bvh file.
|
||||
|
@ -63,12 +62,10 @@ namespace Assimp
|
|||
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
|
||||
* inside the loader just to be able to see something.
|
||||
*/
|
||||
class BVHLoader : public BaseImporter
|
||||
{
|
||||
class BVHLoader : public BaseImporter {
|
||||
|
||||
/** Possible animation channels for which the motion data holds the values */
|
||||
enum ChannelType
|
||||
{
|
||||
enum ChannelType {
|
||||
Channel_PositionX,
|
||||
Channel_PositionY,
|
||||
Channel_PositionZ,
|
||||
|
@ -78,21 +75,19 @@ class BVHLoader : public BaseImporter
|
|||
};
|
||||
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
struct Node {
|
||||
const aiNode *mNode;
|
||||
std::vector<ChannelType> mChannels;
|
||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||
|
||||
Node()
|
||||
: mNode(nullptr)
|
||||
{ }
|
||||
Node() :
|
||||
mNode(nullptr) {}
|
||||
|
||||
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
||||
explicit Node(const aiNode *pNode) :
|
||||
mNode(pNode) {}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
BVHLoader();
|
||||
~BVHLoader();
|
||||
|
||||
|
@ -105,8 +100,6 @@ public:
|
|||
const aiImporterDesc *GetInfo() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
|
@ -42,22 +42,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Conversion of Blender's new BMesh stuff
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
|
||||
#include "BlenderBMesh.h"
|
||||
#include "BlenderDNA.h"
|
||||
#include "BlenderScene.h"
|
||||
#include "BlenderBMesh.h"
|
||||
#include "BlenderTessellator.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
|
||||
{
|
||||
namespace Assimp {
|
||||
template <>
|
||||
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
|
||||
static auto prefix = "BLEND_BMESH: ";
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
|
@ -66,32 +64,28 @@ using namespace Assimp::Formatter;
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
|
||||
BMesh(mesh),
|
||||
triMesh( NULL )
|
||||
{
|
||||
triMesh(nullptr) {
|
||||
ai_assert(nullptr != mesh);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter( )
|
||||
{
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter() {
|
||||
DestroyTriMesh();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderBMeshConverter::ContainsBMesh( ) const
|
||||
{
|
||||
bool BlenderBMeshConverter::ContainsBMesh() const {
|
||||
// TODO - Should probably do some additional verification here
|
||||
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
||||
{
|
||||
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
|
||||
AssertValidMesh();
|
||||
AssertValidSizes();
|
||||
PrepareTriMesh();
|
||||
|
||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
||||
{
|
||||
for (int i = 0; i < BMesh->totpoly; ++i) {
|
||||
const MPoly &poly = BMesh->mpoly[i];
|
||||
ConvertPolyToFaces(poly);
|
||||
}
|
||||
|
@ -100,32 +94,25 @@ const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidMesh( )
|
||||
{
|
||||
if ( !ContainsBMesh( ) )
|
||||
{
|
||||
void BlenderBMeshConverter::AssertValidMesh() {
|
||||
if (!ContainsBMesh()) {
|
||||
ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidSizes( )
|
||||
{
|
||||
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
|
||||
{
|
||||
void BlenderBMeshConverter::AssertValidSizes() {
|
||||
if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
|
||||
ThrowException("BMesh poly array has incorrect size");
|
||||
}
|
||||
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
|
||||
{
|
||||
if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
|
||||
ThrowException("BMesh loop array has incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::PrepareTriMesh( )
|
||||
{
|
||||
if ( triMesh )
|
||||
{
|
||||
void BlenderBMeshConverter::PrepareTriMesh() {
|
||||
if (triMesh) {
|
||||
DestroyTriMesh();
|
||||
}
|
||||
|
||||
|
@ -135,34 +122,27 @@ void BlenderBMeshConverter::PrepareTriMesh( )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::DestroyTriMesh( )
|
||||
{
|
||||
void BlenderBMeshConverter::DestroyTriMesh() {
|
||||
delete triMesh;
|
||||
triMesh = NULL;
|
||||
triMesh = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
||||
{
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
|
||||
const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
|
||||
|
||||
if ( poly.totloop == 3 || poly.totloop == 4 )
|
||||
{
|
||||
if (poly.totloop == 3 || poly.totloop == 4) {
|
||||
AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0);
|
||||
|
||||
// UVs are optional, so only convert when present.
|
||||
if ( BMesh->mloopuv.size() )
|
||||
{
|
||||
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
|
||||
{
|
||||
if (BMesh->mloopuv.size()) {
|
||||
if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
|
||||
ThrowException("BMesh uv loop array has incorrect size");
|
||||
}
|
||||
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
|
||||
AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0);
|
||||
}
|
||||
}
|
||||
else if ( poly.totloop > 4 )
|
||||
{
|
||||
} else if (poly.totloop > 4) {
|
||||
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
BlenderTessellatorGL tessGL(*this);
|
||||
tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
|
||||
|
@ -174,13 +154,13 @@ void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
||||
{
|
||||
void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
|
||||
MFace face;
|
||||
face.v1 = v1;
|
||||
face.v2 = v2;
|
||||
face.v3 = v3;
|
||||
face.v4 = v4;
|
||||
face.flag = 0;
|
||||
// TODO - Work out how materials work
|
||||
face.mat_nr = 0;
|
||||
triMesh->mface.push_back(face);
|
||||
|
@ -188,15 +168,13 @@ void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
|
||||
{
|
||||
void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) {
|
||||
MTFace mtface;
|
||||
memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
|
||||
memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
|
||||
memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
|
||||
|
||||
if ( uv4 )
|
||||
{
|
||||
if (uv4) {
|
||||
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
|
||||
}
|
||||
|
|
@ -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,12 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* serialized set of data structures.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
#include "BlenderDNA.h"
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
|
@ -72,8 +71,7 @@ struct Type {
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNAParser::Parse ()
|
||||
{
|
||||
void DNAParser::Parse() {
|
||||
StreamReaderAny &stream = *db.reader.get();
|
||||
DNA &dna = db.dna;
|
||||
|
||||
|
@ -94,7 +92,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// type dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TYPE")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||
}
|
||||
|
@ -107,7 +106,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// type length dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TLEN")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||
}
|
||||
|
@ -117,7 +117,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// structures dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "STRC")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||
}
|
||||
|
@ -131,8 +132,7 @@ void DNAParser::Parse ()
|
|||
if (n >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure name", n,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
" (there are only ", types.size(), " entries)"));
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
|
@ -153,8 +153,7 @@ 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();
|
||||
|
@ -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,8 +190,7 @@ void DNAParser::Parse ()
|
|||
if (rb == std::string::npos) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Encountered invalid array declaration ",
|
||||
f.name
|
||||
));
|
||||
f.name));
|
||||
}
|
||||
|
||||
f.flags |= FieldFlag_Array;
|
||||
|
@ -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,8 +230,10 @@ void DNA :: DumpToFile()
|
|||
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
|
||||
return;
|
||||
}
|
||||
f << "Field format: type name offset size" << "\n";
|
||||
f << "Structure format: name size" << "\n";
|
||||
f << "Field format: type name offset size"
|
||||
<< "\n";
|
||||
f << "Structure format: name size"
|
||||
<< "\n";
|
||||
|
||||
for (const Structure &s : structures) {
|
||||
f << s.name << " " << s.size << "\n\n";
|
||||
|
@ -254,9 +251,7 @@ void DNA :: DumpToFile()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void DNA ::ExtractArraySize(
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]
|
||||
)
|
||||
{
|
||||
size_t array_sizes[2]) {
|
||||
array_sizes[0] = array_sizes[1] = 1;
|
||||
std::string::size_type pos = out.find('[');
|
||||
if (pos++ == std::string::npos) {
|
||||
|
@ -274,9 +269,7 @@ void DNA :: DumpToFile()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const
|
||||
{
|
||||
const FileDatabase &db) const {
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
if (it == converters.end()) {
|
||||
return std::shared_ptr<ElemBase>();
|
||||
|
@ -292,16 +285,14 @@ std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
|
|||
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
|
||||
const Structure &structure,
|
||||
const FileDatabase & /*db*/
|
||||
) const
|
||||
{
|
||||
) const {
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
return it == converters.end() ? FactoryPair() : (*it).second;
|
||||
}
|
||||
|
||||
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNA :: AddPrimitiveStructures()
|
||||
{
|
||||
void DNA ::AddPrimitiveStructures() {
|
||||
// NOTE: these are just dummies. Their presence enforces
|
||||
// Structure::Convert<target_type> to be called on these
|
||||
// empty structures. These converters are special
|
||||
|
@ -320,19 +311,16 @@ void DNA :: AddPrimitiveStructures()
|
|||
structures.back().name = "short";
|
||||
structures.back().size = 2;
|
||||
|
||||
|
||||
indices["char"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "char";
|
||||
structures.back().size = 1;
|
||||
|
||||
|
||||
indices["float"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "float";
|
||||
structures.back().size = 4;
|
||||
|
||||
|
||||
indices["double"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "double";
|
||||
|
@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SectionParser :: Next()
|
||||
{
|
||||
void SectionParser ::Next() {
|
||||
stream.SetCurrentPos(current.start + current.size);
|
||||
|
||||
const char tmp[] = {
|
||||
|
@ -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,10 +49,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// enable verbose log output. really verbose, so be careful.
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
|
@ -63,7 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
template <bool,bool> class StreamReader;
|
||||
template <bool, bool>
|
||||
class StreamReader;
|
||||
typedef StreamReader<true, true> StreamReaderAny;
|
||||
|
||||
namespace Blender {
|
||||
|
@ -82,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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -212,16 +212,15 @@ enum ErrorPolicy {
|
|||
* meaningful contents. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class Structure {
|
||||
template <template <typename> class> friend class ObjectCache;
|
||||
template <template <typename> class>
|
||||
friend class ObjectCache;
|
||||
|
||||
public:
|
||||
Structure()
|
||||
: cache_idx(static_cast<size_t>(-1) ){
|
||||
Structure() :
|
||||
cache_idx(static_cast<size_t>(-1)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// publicly accessible members
|
||||
std::string name;
|
||||
vector<Field> fields;
|
||||
|
@ -229,8 +228,6 @@ public:
|
|||
|
||||
size_t size;
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Access a field of the structure by its canonical name. The pointer version
|
||||
* returns NULL on failure while the reference version raises an import error. */
|
||||
|
@ -251,8 +248,6 @@ public:
|
|||
return name != other.name;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Try to read an instance of the structure from the stream
|
||||
* and attempt to convert to `T`. This is done by
|
||||
|
@ -260,7 +255,8 @@ public:
|
|||
* a compiler complain is the result.
|
||||
* @param dest Destination value to be written
|
||||
* @param db File database, including input stream. */
|
||||
template <typename T> void Convert (T& dest, const FileDatabase& db) const;
|
||||
template <typename T>
|
||||
void Convert(T &dest, const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// generic converter
|
||||
|
@ -269,9 +265,8 @@ public:
|
|||
|
||||
// --------------------------------------------------------
|
||||
// generic allocator
|
||||
template <typename T> std::shared_ptr<ElemBase> Allocate() const;
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<ElemBase> Allocate() const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// field parsing for 1d arrays
|
||||
|
@ -332,7 +327,6 @@ public:
|
|||
bool ReadCustomDataPtr(std::shared_ptr<ElemBase> &out, int cdtype, const char *name, const FileDatabase &db) const;
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------
|
||||
template <template <typename> class TOUT, typename T>
|
||||
bool ResolvePointer(TOUT<T> &out, const Pointer &ptrval,
|
||||
|
@ -354,15 +348,16 @@ private:
|
|||
const FileDatabase &db) const;
|
||||
|
||||
private:
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
|
||||
template <typename T>
|
||||
T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
|
||||
out = std::shared_ptr<T>(new T());
|
||||
s = 1;
|
||||
return out.get();
|
||||
}
|
||||
|
||||
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
|
||||
template <typename T>
|
||||
T *_allocate(vector<T> &out, size_t &s) const {
|
||||
out.resize(s);
|
||||
return s ? &out.front() : NULL;
|
||||
}
|
||||
|
@ -394,12 +389,12 @@ private:
|
|||
};
|
||||
|
||||
private:
|
||||
|
||||
mutable size_t cache_idx;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------
|
||||
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
|
||||
template <>
|
||||
struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T &out, const char *reason = "<add reason>") {
|
||||
|
@ -410,7 +405,8 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
|
|||
}
|
||||
};
|
||||
|
||||
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
|
||||
template <>
|
||||
struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T & /*out*/, const char * = "") {
|
||||
|
@ -421,13 +417,12 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
|
|||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
|
||||
template <>
|
||||
inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
|
||||
const Pointer &ptrval,
|
||||
const FileDatabase &db,
|
||||
const Field &f,
|
||||
bool
|
||||
) const;
|
||||
|
||||
bool) const;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Represents the full data structure information for a single BLEND file.
|
||||
|
@ -435,14 +430,11 @@ template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(st
|
|||
* #DNAParser does the reading and represents currently the only place where
|
||||
* DNA is altered.*/
|
||||
// -------------------------------------------------------------------------------
|
||||
class DNA
|
||||
{
|
||||
class DNA {
|
||||
public:
|
||||
|
||||
typedef void (Structure::*ConvertProcPtr)(
|
||||
std::shared_ptr<ElemBase> in,
|
||||
const FileDatabase&
|
||||
) const;
|
||||
const FileDatabase &) const;
|
||||
|
||||
typedef std::shared_ptr<ElemBase> (
|
||||
Structure::*AllocProcPtr)() const;
|
||||
|
@ -450,13 +442,11 @@ public:
|
|||
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
|
||||
|
||||
public:
|
||||
|
||||
std::map<std::string, FactoryPair> converters;
|
||||
vector<Structure> structures;
|
||||
std::map<std::string, size_t> indices;
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Access a structure by its canonical name, the pointer version returns NULL on failure
|
||||
* while the reference version raises an error. */
|
||||
|
@ -468,7 +458,6 @@ public:
|
|||
inline const Structure &operator[](const size_t i) const;
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Add structure definitions for all the primitive types,
|
||||
* i.e. integer, short, char, float */
|
||||
|
@ -483,7 +472,6 @@ public:
|
|||
* known at compile time (consier Object::data).*/
|
||||
void RegisterConverters();
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Take an input blob from the stream, interpret it according to
|
||||
* a its structure name and convert it to the intermediate
|
||||
|
@ -493,8 +481,7 @@ public:
|
|||
* @return A null pointer if no appropriate converter is available.*/
|
||||
std::shared_ptr<ElemBase> ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Find a suitable conversion function for a given Structure.
|
||||
|
@ -506,9 +493,7 @@ public:
|
|||
* @return A null pointer in .first if no appropriate converter is available.*/
|
||||
FactoryPair GetBlobToStructureConverter(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
|
||||
const FileDatabase &db) const;
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
// --------------------------------------------------------
|
||||
|
@ -528,24 +513,28 @@ public:
|
|||
* encountered. */
|
||||
static void ExtractArraySize(
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]
|
||||
);
|
||||
size_t array_sizes[2]);
|
||||
};
|
||||
|
||||
// special converters for primitive types
|
||||
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
|
||||
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<int>(int &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<short>(short &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<char>(char &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<float>(float &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<double>(double &dest, const FileDatabase &db) const;
|
||||
template <>
|
||||
inline void Structure ::Convert<Pointer>(Pointer &dest, const FileDatabase &db) const;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Describes a master file block header. Each master file sections holds n
|
||||
* elements of a certain SDNA structure (or otherwise unspecified data). */
|
||||
// -------------------------------------------------------------------------------
|
||||
struct FileBlockHead
|
||||
{
|
||||
struct FileBlockHead {
|
||||
// points right after the header of the file block
|
||||
StreamReaderAny::pos start;
|
||||
|
||||
|
@ -561,8 +550,6 @@ struct FileBlockHead
|
|||
// number of structure instances to follow
|
||||
size_t num;
|
||||
|
||||
|
||||
|
||||
// file blocks are sorted by address to quickly locate specific memory addresses
|
||||
bool operator<(const FileBlockHead &o) const {
|
||||
return address.val < o.address.val;
|
||||
|
@ -582,45 +569,36 @@ inline bool operator< (const Pointer& a, const Pointer& b) {
|
|||
// -------------------------------------------------------------------------------
|
||||
/** Utility to read all master file blocks in turn. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class SectionParser
|
||||
{
|
||||
class SectionParser {
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** @param stream Inout stream, must point to the
|
||||
* first section in the file. Call Next() once
|
||||
* to have it read.
|
||||
* @param ptr64 Pointer size in file is 64 bits? */
|
||||
SectionParser(StreamReaderAny& stream,bool ptr64)
|
||||
: stream(stream)
|
||||
, ptr64(ptr64)
|
||||
{
|
||||
SectionParser(StreamReaderAny &stream, bool ptr64) :
|
||||
stream(stream), ptr64(ptr64) {
|
||||
current.size = current.start = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
const FileBlockHead &GetCurrent() const {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Advance to the next section.
|
||||
* @throw DeadlyImportError if the last chunk was passed. */
|
||||
void Next();
|
||||
|
||||
public:
|
||||
|
||||
FileBlockHead current;
|
||||
StreamReaderAny &stream;
|
||||
bool ptr64;
|
||||
};
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Import statistics, i.e. number of file blocks read*/
|
||||
|
@ -628,17 +606,13 @@ public:
|
|||
class Statistics {
|
||||
|
||||
public:
|
||||
|
||||
Statistics ()
|
||||
: fields_read ()
|
||||
, pointers_resolved ()
|
||||
, cache_hits ()
|
||||
Statistics() :
|
||||
fields_read(), pointers_resolved(), cache_hits()
|
||||
// , blocks_read ()
|
||||
, cached_objects ()
|
||||
{}
|
||||
,
|
||||
cached_objects() {}
|
||||
|
||||
public:
|
||||
|
||||
/** total number of fields we read */
|
||||
unsigned int fields_read;
|
||||
|
||||
|
@ -662,17 +636,13 @@ public:
|
|||
* avoids circular references and avoids object duplication. */
|
||||
// -------------------------------------------------------------------------------
|
||||
template <template <typename> class TOUT>
|
||||
class ObjectCache
|
||||
{
|
||||
class ObjectCache {
|
||||
public:
|
||||
|
||||
typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
|
||||
|
||||
public:
|
||||
|
||||
ObjectCache(const FileDatabase& db)
|
||||
: db(db)
|
||||
{
|
||||
ObjectCache(const FileDatabase &db) :
|
||||
db(db) {
|
||||
// currently there are only ~400 structure records per blend file.
|
||||
// we read only a small part of them and don't cache objects
|
||||
// which we don't need, so this should suffice.
|
||||
|
@ -680,14 +650,14 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Check whether a specific item is in the cache.
|
||||
* @param s Data type of the item
|
||||
* @param out Output pointer. Unchanged if the
|
||||
* cache doesn't know the item yet.
|
||||
* @param ptr Item address to look for. */
|
||||
template <typename T> void get (
|
||||
template <typename T>
|
||||
void get(
|
||||
const Structure &s,
|
||||
TOUT<T> &out,
|
||||
const Pointer &ptr) const;
|
||||
|
@ -700,27 +670,27 @@ public:
|
|||
* @param s Data type of the item
|
||||
* @param out Item to insert into the cache
|
||||
* @param ptr address (cache key) of the item. */
|
||||
template <typename T> void set
|
||||
(const Structure& s,
|
||||
template <typename T>
|
||||
void set(const Structure &s,
|
||||
const TOUT<T> &out,
|
||||
const Pointer &ptr);
|
||||
|
||||
private:
|
||||
|
||||
mutable vector<StructureCache> caches;
|
||||
const FileDatabase &db;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
template <> class ObjectCache<Blender::vector>
|
||||
{
|
||||
template <>
|
||||
class ObjectCache<Blender::vector> {
|
||||
public:
|
||||
|
||||
ObjectCache(const FileDatabase &) {}
|
||||
|
||||
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
|
||||
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
|
||||
template <typename T>
|
||||
void get(const Structure &, vector<T> &, const Pointer &) {}
|
||||
template <typename T>
|
||||
void set(const Structure &, const vector<T> &, const Pointer &) {}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -731,16 +701,13 @@ public:
|
|||
/** Memory representation of a full BLEND file and all its dependencies. The
|
||||
* output aiScene is constructed from an instance of this data structure. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class FileDatabase
|
||||
{
|
||||
template <template <typename> class TOUT> friend class ObjectCache;
|
||||
class FileDatabase {
|
||||
template <template <typename> class TOUT>
|
||||
friend class ObjectCache;
|
||||
|
||||
public:
|
||||
FileDatabase()
|
||||
: _cacheArrays(*this)
|
||||
, _cache(*this)
|
||||
, next_cache_idx()
|
||||
{}
|
||||
FileDatabase() :
|
||||
_cacheArrays(*this), _cache(*this), next_cache_idx() {}
|
||||
|
||||
public:
|
||||
// publicly accessible fields
|
||||
|
@ -752,7 +719,6 @@ public:
|
|||
vector<FileBlockHead> entries;
|
||||
|
||||
public:
|
||||
|
||||
Statistics &stats() const {
|
||||
return _stats;
|
||||
}
|
||||
|
@ -772,8 +738,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
mutable Statistics _stats;
|
||||
#endif
|
||||
|
@ -791,18 +755,14 @@ private:
|
|||
// -------------------------------------------------------------------------------
|
||||
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
|
||||
// -------------------------------------------------------------------------------
|
||||
class DNAParser
|
||||
{
|
||||
class DNAParser {
|
||||
|
||||
public:
|
||||
|
||||
/** Bind the parser to a empty DNA and an input stream */
|
||||
DNAParser(FileDatabase& db)
|
||||
: db(db)
|
||||
{}
|
||||
DNAParser(FileDatabase &db) :
|
||||
db(db) {}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Locate the DNA in the file and parse it. The input
|
||||
* stream is expected to point to the beginning of the DN1
|
||||
|
@ -814,14 +774,12 @@ public:
|
|||
void Parse();
|
||||
|
||||
public:
|
||||
|
||||
/** Obtain a reference to the extracted DNA information */
|
||||
const Blender::DNA &GetDNA() const {
|
||||
return db.dna;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
FileDatabase &db;
|
||||
};
|
||||
|
||||
|
@ -835,9 +793,8 @@ private:
|
|||
*/
|
||||
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
|
||||
|
||||
|
||||
} // end Blend
|
||||
} // end Assimp
|
||||
} // namespace Blender
|
||||
} // namespace Assimp
|
||||
|
||||
#include "BlenderDNA.inl"
|
||||
|
|
@ -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,7 +57,8 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -67,18 +68,16 @@ 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
|
||||
|
@ -128,7 +127,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
|||
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
|
||||
cnt++;
|
||||
|
||||
curgod = NULL;
|
||||
curgod = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -146,19 +145,15 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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 )
|
||||
{
|
||||
const Object &orig_object) {
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier);
|
||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
||||
|
@ -178,39 +173,46 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
|||
|
||||
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];
|
||||
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);
|
||||
}
|
||||
}
|
||||
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,16 +220,17 @@ 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 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]);
|
||||
}
|
||||
|
@ -250,23 +253,20 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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 )
|
||||
{
|
||||
const Object &orig_object) {
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
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;
|
|
@ -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
|
||||
|
@ -127,7 +126,6 @@ struct ListBase : ElemBase {
|
|||
std::shared_ptr<ElemBase> last;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct PackedFile : ElemBase {
|
||||
int size WARN;
|
||||
|
@ -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) {}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -490,8 +480,8 @@ struct Library : ElemBase {
|
|||
// -------------------------------------------------------------------------------
|
||||
struct Camera : ElemBase {
|
||||
enum Type {
|
||||
Type_PERSP = 0
|
||||
,Type_ORTHO = 1
|
||||
Type_PERSP = 0,
|
||||
Type_ORTHO = 1
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
|
@ -502,24 +492,23 @@ struct Camera : ElemBase {
|
|||
float clipsta, clipend;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Lamp : ElemBase {
|
||||
|
||||
enum FalloffType {
|
||||
FalloffType_Constant = 0x0
|
||||
,FalloffType_InvLinear = 0x1
|
||||
,FalloffType_InvSquare = 0x2
|
||||
FalloffType_Constant = 0x0,
|
||||
FalloffType_InvLinear = 0x1,
|
||||
FalloffType_InvSquare = 0x2
|
||||
//,FalloffType_Curve = 0x3
|
||||
//,FalloffType_Sliders = 0x4
|
||||
};
|
||||
|
||||
enum Type {
|
||||
Type_Local = 0x0
|
||||
,Type_Sun = 0x1
|
||||
,Type_Spot = 0x2
|
||||
,Type_Hemi = 0x3
|
||||
,Type_Area = 0x4
|
||||
Type_Local = 0x0,
|
||||
Type_Sun = 0x1,
|
||||
Type_Spot = 0x2,
|
||||
Type_Hemi = 0x3,
|
||||
Type_Area = 0x4
|
||||
//,Type_YFPhoton = 0x5
|
||||
};
|
||||
|
||||
|
@ -681,18 +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;
|
||||
|
@ -709,30 +700,20 @@ struct Object : ElemBase {
|
|||
|
||||
ListBase modifiers;
|
||||
|
||||
Object()
|
||||
: ElemBase()
|
||||
, type( Type_EMPTY )
|
||||
, parent( nullptr )
|
||||
, track()
|
||||
, proxy()
|
||||
, proxy_from()
|
||||
, data() {
|
||||
Object() :
|
||||
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Base : ElemBase {
|
||||
Base *prev WARN;
|
||||
std::shared_ptr<Base> next WARN;
|
||||
std::shared_ptr<Object> object WARN;
|
||||
|
||||
Base()
|
||||
: ElemBase()
|
||||
, prev( nullptr )
|
||||
, next()
|
||||
, object() {
|
||||
Base() :
|
||||
ElemBase(), prev(nullptr), next(), object() {
|
||||
// empty
|
||||
// empty
|
||||
}
|
||||
|
@ -748,11 +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;
|
||||
|
@ -972,12 +947,12 @@ struct MTex : ElemBase {
|
|||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
|
||||
MTex()
|
||||
: ElemBase() {
|
||||
MTex() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Blender
|
||||
} // namespace Assimp
|
||||
#endif
|
|
@ -43,21 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the TrueSpace COB/SCN importer class.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
||||
#include "COB/COBLoader.h"
|
||||
#include "COB/COBScene.h"
|
||||
#include "AssetLib/COB/COBLoader.h"
|
||||
#include "AssetLib/COB/COBScene.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/LineSplitter.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -65,7 +64,6 @@ using namespace Assimp;
|
|||
using namespace Assimp::COB;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
|
||||
static const float units[] = {
|
||||
1000.f,
|
||||
100.f,
|
||||
|
@ -90,21 +88,17 @@ static const aiImporterDesc desc = {
|
|||
"cob scn"
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
COBImporter::COBImporter()
|
||||
{}
|
||||
COBImporter::COBImporter() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
COBImporter::~COBImporter()
|
||||
{}
|
||||
COBImporter::~COBImporter() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
|
||||
return true;
|
||||
|
@ -119,21 +113,18 @@ bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* COBImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *COBImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void COBImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
void COBImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||
// nothing to be done for the moment
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string& msg)
|
||||
{
|
||||
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
|
||||
throw DeadlyImportError("COB: " + msg);
|
||||
}
|
||||
|
||||
|
@ -158,8 +149,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
// load data into intermediate structures
|
||||
if (head[15] == 'A') {
|
||||
ReadAsciiFile(scene, stream.get());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ReadBinaryFile(scene, stream.get());
|
||||
}
|
||||
if (scene.nodes.empty()) {
|
||||
|
@ -193,8 +183,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
for (std::shared_ptr<Node> &n : scene.nodes) {
|
||||
if (n->type == Node::TYPE_LIGHT) {
|
||||
++pScene->mNumLights;
|
||||
}
|
||||
else if (n->type == Node::TYPE_CAMERA) {
|
||||
} else if (n->type == Node::TYPE_CAMERA) {
|
||||
++pScene->mNumCameras;
|
||||
}
|
||||
}
|
||||
|
@ -230,16 +219,14 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertTexture(std::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type)
|
||||
{
|
||||
void ConvertTexture(std::shared_ptr<Texture> tex, aiMaterial *out, aiTextureType type) {
|
||||
const aiString path(tex->path);
|
||||
out->AddProperty(&path, AI_MATKEY_TEXTURE(type, 0));
|
||||
out->AddProperty(&tex->transform, 1, AI_MATKEY_UVTRANSFORM(type, 0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill)
|
||||
{
|
||||
aiNode *COBImporter::BuildNodes(const Node &root, const Scene &scin, aiScene *fill) {
|
||||
aiNode *nd = new aiNode();
|
||||
nd->mName.Set(root.name);
|
||||
nd->mTransformation = root.transform;
|
||||
|
@ -250,7 +237,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
const Mesh &ndmesh = (const Mesh &)(root);
|
||||
if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
|
||||
|
||||
typedef std::pair<unsigned int,Mesh::FaceRefList> Entry;
|
||||
typedef std::pair<const unsigned int, Mesh::FaceRefList> Entry;
|
||||
for (const Entry &reflist : ndmesh.temp_map) {
|
||||
{ // create mesh
|
||||
size_t n = 0;
|
||||
|
@ -286,15 +273,15 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D(
|
||||
ndmesh.texture_coords[v.uv_idx].x,
|
||||
ndmesh.texture_coords[v.uv_idx].y,
|
||||
0.f
|
||||
);
|
||||
0.f);
|
||||
|
||||
fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++;
|
||||
}
|
||||
}
|
||||
outmesh->mMaterialIndex = fill->mNumMaterials;
|
||||
}{ // create material
|
||||
const Material* min = NULL;
|
||||
}
|
||||
{ // create material
|
||||
const Material *min = nullptr;
|
||||
for (const Material &m : scin.materials) {
|
||||
if (m.parent_id == ndmesh.id && m.matnum == reflist.first) {
|
||||
min = &m;
|
||||
|
@ -303,7 +290,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
std::unique_ptr<const Material> defmat;
|
||||
if (!min) {
|
||||
ASSIMP_LOG_DEBUG(format()<<"Could not resolve material index "
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(format() << "Could not resolve material index "
|
||||
<< reflist.first << " - creating default material for this slot");
|
||||
|
||||
defmat.reset(min = new Material());
|
||||
|
@ -319,9 +306,9 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
mat->AddProperty(&tmp, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
|
||||
{ int shader;
|
||||
switch(min->shader)
|
||||
{
|
||||
int shader;
|
||||
switch (min->shader) {
|
||||
case Material::FLAT:
|
||||
shader = aiShadingMode_Gouraud;
|
||||
break;
|
||||
|
@ -365,8 +352,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Node::TYPE_LIGHT == root.type) {
|
||||
} else if (Node::TYPE_LIGHT == root.type) {
|
||||
const Light &ndlight = (const Light &)(root);
|
||||
aiLight *outlight = fill->mLights[fill->mNumLights++] = new aiLight();
|
||||
|
||||
|
@ -378,8 +364,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
|
||||
// XXX
|
||||
outlight->mType = ndlight.ltype == Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL;
|
||||
}
|
||||
else if (Node::TYPE_CAMERA == root.type) {
|
||||
} else if (Node::TYPE_CAMERA == root.type) {
|
||||
const Camera &ndcam = (const Camera &)(root);
|
||||
aiCamera *outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera();
|
||||
|
||||
|
@ -387,7 +372,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
|
||||
// add meshes
|
||||
if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0
|
||||
if (nd->mNumMeshes) { // mMeshes must be nullptr if count is 0
|
||||
nd->mMeshes = new unsigned int[nd->mNumMeshes];
|
||||
for (unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||
nd->mMeshes[i] = fill->mNumMeshes - i - 1;
|
||||
|
@ -405,8 +390,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read an ASCII file into the given scene data structure
|
||||
void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
|
||||
{
|
||||
void COBImporter::ReadAsciiFile(Scene &out, StreamReaderLE *stream) {
|
||||
ChunkInfo ci;
|
||||
for (LineSplitter splitter(*stream); splitter; ++splitter) {
|
||||
|
||||
|
@ -456,8 +440,7 @@ void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter)
|
||||
{
|
||||
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo &out, const LineSplitter &splitter) {
|
||||
const char *all_tokens[8];
|
||||
splitter.get_tokens(all_tokens);
|
||||
|
||||
|
@ -468,10 +451,8 @@ void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitt
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name)
|
||||
{
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name <<
|
||||
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
|
||||
void COBImporter::UnsupportedChunk_Ascii(LineSplitter &splitter, const ChunkInfo &nfo, const char *name) {
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
|
||||
|
||||
// we can recover if the chunk size was specified.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
|
@ -483,13 +464,12 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
|
|||
// missing the next line.
|
||||
splitter.get_stream().IncPtr(nfo.size);
|
||||
splitter.swallow_next_increment();
|
||||
}
|
||||
else ThrowException(error);
|
||||
} else
|
||||
ThrowException(error);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
|
||||
{
|
||||
void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, const ChunkInfo & /*nfo*/) {
|
||||
for (; splitter; ++splitter) {
|
||||
if (splitter.match_start("Name")) {
|
||||
msh.name = std::string(splitter[1]);
|
||||
|
@ -497,8 +477,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
|
|||
// make nice names by merging the dupe count
|
||||
std::replace(msh.name.begin(), msh.name.end(),
|
||||
',', '_');
|
||||
}
|
||||
else if (splitter.match_start("Transform")) {
|
||||
} else if (splitter.match_start("Transform")) {
|
||||
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
|
||||
const char *s = splitter->c_str();
|
||||
for (unsigned int x = 0; x < 4; ++x) {
|
||||
|
@ -514,8 +493,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
|
||||
{
|
||||
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in) {
|
||||
const char *rgb = *in;
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
SkipSpaces(&rgb);
|
||||
|
@ -528,8 +506,7 @@ void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadMat1_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Mat1");
|
||||
}
|
||||
|
@ -556,11 +533,9 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
|
||||
if (shader == "metal") {
|
||||
mat.shader = Material::METAL;
|
||||
}
|
||||
else if (shader == "phong") {
|
||||
} else if (shader == "phong") {
|
||||
mat.shader = Material::PHONG;
|
||||
}
|
||||
else if (shader != "flat") {
|
||||
} else if (shader != "flat") {
|
||||
ASSIMP_LOG_WARN_F("Unknown value for `shader` in `Mat1` chunk ", nfo.id);
|
||||
}
|
||||
|
||||
|
@ -588,8 +563,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadUnit_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Unit");
|
||||
}
|
||||
|
@ -606,8 +580,8 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
const unsigned int t = strtoul10(splitter[1]);
|
||||
|
||||
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
|
||||
,1.f):units[t];
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
|
||||
units[t];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -615,16 +589,14 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadChan_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadChan_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Chan");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadLght_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Lght");
|
||||
}
|
||||
|
@ -637,14 +609,11 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
|
||||
if (splitter.match_start("Infinite ")) {
|
||||
msh.ltype = Light::INFINITE;
|
||||
}
|
||||
else if (splitter.match_start("Local ")) {
|
||||
} else if (splitter.match_start("Local ")) {
|
||||
msh.ltype = Light::LOCAL;
|
||||
}
|
||||
else if (splitter.match_start("Spot ")) {
|
||||
} else if (splitter.match_start("Spot ")) {
|
||||
msh.ltype = Light::SPOT;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ASSIMP_LOG_WARN_F("Unknown kind of light source in `Lght` chunk ", nfo.id, " : ", *splitter);
|
||||
msh.ltype = Light::SPOT;
|
||||
}
|
||||
|
@ -675,8 +644,7 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadCame_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Came");
|
||||
}
|
||||
|
@ -693,8 +661,7 @@ void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBone_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 5) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Bone");
|
||||
}
|
||||
|
@ -709,8 +676,7 @@ void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadGrou_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Grou");
|
||||
}
|
||||
|
@ -723,8 +689,7 @@ void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "PolH");
|
||||
}
|
||||
|
@ -755,8 +720,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
SkipSpaces(&s);
|
||||
v.z = fast_atof(&s);
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("Texture Vertices")) {
|
||||
} else if (splitter.match_start("Texture Vertices")) {
|
||||
const unsigned int cnt = strtoul10(splitter[2]);
|
||||
msh.texture_coords.resize(cnt);
|
||||
|
||||
|
@ -770,8 +734,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
SkipSpaces(&s);
|
||||
v.y = fast_atof(&s);
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("Faces")) {
|
||||
} else if (splitter.match_start("Faces")) {
|
||||
const unsigned int cnt = strtoul10(splitter[1]);
|
||||
msh.faces.reserve(cnt);
|
||||
|
||||
|
@ -813,8 +776,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
if (nfo.version <= 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("DrawFlags")) {
|
||||
} else if (splitter.match_start("DrawFlags")) {
|
||||
msh.draw_flags = strtoul10(splitter[1]);
|
||||
break;
|
||||
}
|
||||
|
@ -822,8 +784,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBitM_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "BitM");
|
||||
}
|
||||
|
@ -849,8 +810,7 @@ void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const C
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
|
||||
{
|
||||
void COBImporter::ReadString_Binary(std::string &out, StreamReaderLE &reader) {
|
||||
out.resize(reader.GetI2());
|
||||
for (char &c : out) {
|
||||
c = reader.GetI1();
|
||||
|
@ -858,8 +818,7 @@ void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/)
|
||||
{
|
||||
void COBImporter::ReadBasicNodeInfo_Binary(Node &msh, StreamReaderLE &reader, const ChunkInfo & /*nfo*/) {
|
||||
const unsigned int dupes = reader.GetI2();
|
||||
ReadString_Binary(msh.name, reader);
|
||||
|
||||
|
@ -877,27 +836,23 @@ void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, co
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkInfo& nfo, const char* name)
|
||||
{
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name <<
|
||||
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
|
||||
void COBImporter::UnsupportedChunk_Binary(StreamReaderLE &reader, const ChunkInfo &nfo, const char *name) {
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
|
||||
|
||||
// we can recover if the chunk size was specified.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
ASSIMP_LOG_ERROR(error);
|
||||
reader.IncPtr(nfo.size);
|
||||
}
|
||||
else ThrowException(error);
|
||||
} else
|
||||
ThrowException(error);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// tiny utility guard to aid me at staying within chunk boundaries.
|
||||
class chunk_guard {
|
||||
public:
|
||||
chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader)
|
||||
: nfo(nfo)
|
||||
, reader(reader)
|
||||
, cur(reader.GetCurrentPos()) {
|
||||
chunk_guard(const COB::ChunkInfo &nfo, StreamReaderLE &reader) :
|
||||
nfo(nfo), reader(reader), cur(reader.GetCurrentPos()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -927,11 +882,7 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
|
||||
while (1) {
|
||||
std::string type;
|
||||
type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
;
|
||||
type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1();
|
||||
|
||||
ChunkInfo nfo;
|
||||
nfo.version = reader->GetI2() * 10;
|
||||
|
@ -943,20 +894,15 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
|
||||
if (type == "PolH") {
|
||||
ReadPolH_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "BitM") {
|
||||
} else if (type == "BitM") {
|
||||
ReadBitM_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Grou") {
|
||||
} else if (type == "Grou") {
|
||||
ReadGrou_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Lght") {
|
||||
} else if (type == "Lght") {
|
||||
ReadLght_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Came") {
|
||||
} else if (type == "Came") {
|
||||
ReadCame_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Mat1") {
|
||||
} else if (type == "Mat1") {
|
||||
ReadMat1_Binary(out, *reader, nfo);
|
||||
}
|
||||
/* else if (type == "Bone") {
|
||||
|
@ -967,24 +913,21 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
}*/
|
||||
else if (type == "Unit") {
|
||||
ReadUnit_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "OLay") {
|
||||
} else if (type == "OLay") {
|
||||
// ignore layer index silently.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
reader->IncPtr(nfo.size);
|
||||
}
|
||||
else return UnsupportedChunk_Binary(*reader,nfo,type.c_str());
|
||||
}
|
||||
else if (type == "END ") {
|
||||
} else
|
||||
return UnsupportedChunk_Binary(*reader, nfo, type.c_str());
|
||||
} else if (type == "END ") {
|
||||
return;
|
||||
}
|
||||
else UnsupportedChunk_Binary(*reader,nfo,type.c_str());
|
||||
} else
|
||||
UnsupportedChunk_Binary(*reader, nfo, type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadPolH_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "PolH");
|
||||
}
|
||||
|
@ -1015,16 +958,16 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
// XXX backface culling flag is 0x10 in flags
|
||||
|
||||
// hole?
|
||||
bool hole;
|
||||
if ((hole = (reader.GetI1() & 0x08) != 0)) {
|
||||
bool hole = (reader.GetI1() & 0x08) != 0;
|
||||
if (hole) {
|
||||
// XXX Basically this should just work fine - then triangulator
|
||||
// should output properly triangulated data even for polygons
|
||||
// with holes. Test data specific to COB is needed to confirm it.
|
||||
if (msh.faces.empty()) {
|
||||
ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id);
|
||||
}
|
||||
}
|
||||
else msh.faces.push_back(Face());
|
||||
} else
|
||||
msh.faces.push_back(Face());
|
||||
Face &f = msh.faces.back();
|
||||
|
||||
const size_t num = reader.GetI2();
|
||||
|
@ -1054,8 +997,7 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBitM_Binary(COB::Scene & /*out*/, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "BitM");
|
||||
}
|
||||
|
@ -1070,8 +1012,7 @@ void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, c
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadMat1_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Mat1");
|
||||
}
|
||||
|
@ -1172,8 +1113,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadCame_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Came");
|
||||
}
|
||||
|
@ -1195,8 +1135,7 @@ void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadLght_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Lght");
|
||||
}
|
||||
|
@ -1211,8 +1150,7 @@ void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadGrou_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Grou");
|
||||
}
|
||||
|
@ -1227,8 +1165,7 @@ void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadUnit_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Unit");
|
||||
}
|
||||
|
@ -1241,8 +1178,8 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
if (nd->id == nfo.parent_id) {
|
||||
const unsigned int t = reader.GetI2();
|
||||
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
|
||||
ASSIMP_LOG_WARN_F(t," is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
|
||||
,1.f):units[t];
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
|
||||
units[t];
|
||||
|
||||
return;
|
||||
}
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,29 +225,25 @@ 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;
|
||||
|
@ -288,8 +269,8 @@ struct Node
|
|||
std::string mPrimaryCamera;
|
||||
|
||||
//! Constructor. Begin with a zero parent
|
||||
Node()
|
||||
: mParent( nullptr ){
|
||||
Node() :
|
||||
mParent(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -301,16 +282,14 @@ struct Node
|
|||
};
|
||||
|
||||
/** 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
|
||||
|
@ -321,47 +300,52 @@ struct Accessor
|
|||
std::string mSource; // URL of the source array
|
||||
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
|
||||
|
||||
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()
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -443,29 +425,25 @@ struct Controller
|
|||
};
|
||||
|
||||
/** 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;
|
||||
|
||||
|
@ -632,19 +603,16 @@ struct Animation
|
|||
std::vector<Animation *> mSubAnims;
|
||||
|
||||
/** Destructor */
|
||||
~Animation()
|
||||
{
|
||||
~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,8 +659,7 @@ struct Animation
|
|||
};
|
||||
|
||||
/** Description of a collada animation channel which has been determined to affect the current node */
|
||||
struct ChannelEntry
|
||||
{
|
||||
struct ChannelEntry {
|
||||
const Collada::AnimationChannel *mChannel; ///> the source channel
|
||||
std::string mTargetId;
|
||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
||||
|
@ -710,15 +672,14 @@ struct ChannelEntry
|
|||
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
|
|
@ -46,24 +46,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ColladaLoader.h"
|
||||
#include "ColladaParser.h"
|
||||
|
||||
#include <assimp/ColladaMetaData.h>
|
||||
#include <assimp/Defines.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Defines.h>
|
||||
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/CreateAnimMesh.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/CreateAnimMesh.h>
|
||||
#include <assimp/ZipArchiveIOSystem.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
#include "time.h"
|
||||
#include "math.h"
|
||||
#include "time.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
|
@ -82,22 +83,34 @@ static const aiImporterDesc desc = {
|
|||
"dae zae"
|
||||
};
|
||||
|
||||
static const float kMillisecondsFromSeconds = 1000.f;
|
||||
|
||||
// Add an item of metadata to a node
|
||||
// Assumes the key is not already in the list
|
||||
template <typename T>
|
||||
inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value) {
|
||||
if (nullptr == node->mMetaData) {
|
||||
node->mMetaData = new aiMetadata();
|
||||
}
|
||||
node->mMetaData->Add(key, value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ColladaLoader::ColladaLoader()
|
||||
: mFileName()
|
||||
, mMeshIndexByID()
|
||||
, mMaterialIndexByName()
|
||||
, mMeshes()
|
||||
, newMats()
|
||||
, mCameras()
|
||||
, mLights()
|
||||
, mTextures()
|
||||
, mAnims()
|
||||
, noSkeletonMesh(false)
|
||||
, ignoreUpDirection(false)
|
||||
, useColladaName(false)
|
||||
, mNodeNameCounter(0) {
|
||||
ColladaLoader::ColladaLoader() :
|
||||
mFileName(),
|
||||
mMeshIndexByID(),
|
||||
mMaterialIndexByName(),
|
||||
mMeshes(),
|
||||
newMats(),
|
||||
mCameras(),
|
||||
mLights(),
|
||||
mTextures(),
|
||||
mAnims(),
|
||||
noSkeletonMesh(false),
|
||||
ignoreUpDirection(false),
|
||||
useColladaName(false),
|
||||
mNodeNameCounter(0) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -176,7 +189,6 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO
|
|||
// parse the input file
|
||||
ColladaParser parser(pIOHandler, pFile);
|
||||
|
||||
|
||||
if (!parser.mRootNode) {
|
||||
throw DeadlyImportError("Collada: File came out empty. Something is wrong here.");
|
||||
}
|
||||
|
@ -230,27 +242,15 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO
|
|||
}
|
||||
}
|
||||
|
||||
// store all meshes
|
||||
StoreSceneMeshes(pScene);
|
||||
|
||||
// store all materials
|
||||
StoreSceneMaterials(pScene);
|
||||
|
||||
// store all textures
|
||||
StoreSceneTextures(pScene);
|
||||
|
||||
// store all lights
|
||||
StoreSceneLights(pScene);
|
||||
|
||||
// store all cameras
|
||||
StoreSceneCameras(pScene);
|
||||
|
||||
// store all animations
|
||||
StoreAnimations(pScene, parser);
|
||||
|
||||
// If no meshes have been loaded, it's probably just an animated skeleton.
|
||||
if (0u == pScene->mNumMeshes) {
|
||||
|
||||
if (!noSkeletonMesh) {
|
||||
SkeletonMeshBuilder hero(pScene);
|
||||
}
|
||||
|
@ -266,6 +266,15 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad
|
|||
|
||||
// find a name for the new node. It's more complicated than you might think
|
||||
node->mName.Set(FindNameForNode(pNode));
|
||||
// if we're not using the unique IDs, hold onto them for reference and export
|
||||
if (useColladaName) {
|
||||
if (!pNode->mID.empty()) {
|
||||
AddNodeMetaData(node, AI_METADATA_COLLADA_ID, aiString(pNode->mID));
|
||||
}
|
||||
if (!pNode->mSID.empty()) {
|
||||
AddNodeMetaData(node, AI_METADATA_COLLADA_SID, aiString(pNode->mSID));
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the transformation matrix for it
|
||||
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
|
||||
|
@ -289,13 +298,8 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad
|
|||
node->mChildren[pNode->mChildren.size() + a]->mParent = node;
|
||||
}
|
||||
|
||||
// construct meshes
|
||||
BuildMeshesForNode(pParser, pNode, node);
|
||||
|
||||
// construct cameras
|
||||
BuildCamerasForNode(pParser, pNode, node);
|
||||
|
||||
// construct lights
|
||||
BuildLightsForNode(pParser, pNode, node);
|
||||
|
||||
return node;
|
||||
|
@ -331,9 +335,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Col
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolve UV channels
|
||||
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
||||
|
||||
const Collada::SemanticMappingTable& table) {
|
||||
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
|
||||
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
||||
if (it != table.mMap.end()) {
|
||||
if (it->second.mType != Collada::IT_Texcoord) {
|
||||
|
@ -372,8 +374,7 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla
|
|||
if (out->mType == aiLightSource_AMBIENT) {
|
||||
out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
|
||||
out->mColorAmbient = srcLight->mColor * srcLight->mIntensity;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// collada doesn't differentiate between these color types
|
||||
out->mColorDiffuse = out->mColorSpecular = srcLight->mColor * srcLight->mIntensity;
|
||||
out->mColorAmbient = aiColor3D(0, 0, 0);
|
||||
|
@ -391,14 +392,12 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla
|
|||
// epsilon chosen to be 0.1
|
||||
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
|
||||
out->mAngleInnerCone;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
|
||||
if (out->mAngleOuterCone < out->mAngleInnerCone)
|
||||
std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle);
|
||||
}
|
||||
}
|
||||
|
@ -488,13 +487,11 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (nullptr == srcMesh) {
|
||||
ASSIMP_LOG_WARN_F("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// ID found in the mesh library -> direct reference to an unskinned mesh
|
||||
srcMesh = srcMeshIt->second;
|
||||
}
|
||||
|
@ -515,8 +512,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
|
|||
if (meshMatIt != mid.mMaterials.end()) {
|
||||
table = &meshMatIt->second;
|
||||
meshMaterial = table->mMatName;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
|
||||
mid.mMeshOrController, ">.");
|
||||
if (!mid.mMaterials.empty()) {
|
||||
|
@ -552,8 +548,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
|
|||
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index);
|
||||
if (dstMeshIt != mMeshIndexByID.end()) {
|
||||
newMeshRefs.push_back(dstMeshIt->second);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// else we have to add the mesh to the collection and store its newly assigned index at the node
|
||||
aiMesh *dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
|
||||
|
||||
|
@ -561,7 +556,8 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
|
|||
newMeshRefs.push_back(mMeshes.size());
|
||||
mMeshIndexByID[index] = mMeshes.size();
|
||||
mMeshes.push_back(dstMesh);
|
||||
vertexStart += dstMesh->mNumVertices; faceStart += submesh.mNumFaces;
|
||||
vertexStart += dstMesh->mNumVertices;
|
||||
faceStart += submesh.mNumFaces;
|
||||
|
||||
// assign the material index
|
||||
dstMesh->mMaterialIndex = matIdx;
|
||||
|
@ -589,6 +585,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Find mesh from either meshes or morph target meshes
|
||||
aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
|
||||
if ( meshid.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mMeshes.size(); ++i) {
|
||||
if (std::string(mMeshes[i]->mName.data) == meshid) {
|
||||
return mMeshes[i];
|
||||
|
@ -610,7 +610,11 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
|
||||
std::unique_ptr<aiMesh> dstMesh(new aiMesh);
|
||||
|
||||
if (useColladaName) {
|
||||
dstMesh->mName = pSrcMesh->mName;
|
||||
} else {
|
||||
dstMesh->mName = pSrcMesh->mId;
|
||||
}
|
||||
|
||||
// count the vertices addressed by its faces
|
||||
const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace,
|
||||
|
@ -619,30 +623,26 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
// copy positions
|
||||
dstMesh->mNumVertices = static_cast<unsigned int>(numVertices);
|
||||
dstMesh->mVertices = new aiVector3D[numVertices];
|
||||
std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() +
|
||||
pStartVertex + numVertices, dstMesh->mVertices);
|
||||
std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + pStartVertex + numVertices, dstMesh->mVertices);
|
||||
|
||||
// normals, if given. HACK: (thom) Due to the glorious Collada spec we never
|
||||
// know if we have the same number of normals as there are positions. So we
|
||||
// also ignore any vertex attribute if it has a different count
|
||||
if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) {
|
||||
dstMesh->mNormals = new aiVector3D[numVertices];
|
||||
std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() +
|
||||
pStartVertex + numVertices, dstMesh->mNormals);
|
||||
std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals);
|
||||
}
|
||||
|
||||
// tangents, if given.
|
||||
if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) {
|
||||
dstMesh->mTangents = new aiVector3D[numVertices];
|
||||
std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() +
|
||||
pStartVertex + numVertices, dstMesh->mTangents);
|
||||
std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents);
|
||||
}
|
||||
|
||||
// bitangents, if given.
|
||||
if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) {
|
||||
dstMesh->mBitangents = new aiVector3D[numVertices];
|
||||
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() +
|
||||
pStartVertex + numVertices, dstMesh->mBitangents);
|
||||
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
|
||||
}
|
||||
|
||||
// same for texturecoords, as many as we have
|
||||
|
@ -711,10 +711,10 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) {
|
||||
const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
|
||||
|
||||
aiMesh *aimesh = findMesh(targetMesh->mName);
|
||||
aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
|
||||
if (!aimesh) {
|
||||
if (targetMesh->mSubMeshes.size() > 1) {
|
||||
throw DeadlyImportError("Morhing target mesh must be a single");
|
||||
throw DeadlyImportError("Morphing target mesh must be a single");
|
||||
}
|
||||
aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0);
|
||||
mTargetMeshes.push_back(aimesh);
|
||||
|
@ -736,9 +736,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
animMesh->mName = targetMesh->mName;
|
||||
animMeshes.push_back(animMesh);
|
||||
}
|
||||
dstMesh->mMethod = (method == Collada::Relative)
|
||||
? aiMorphingMethod_MORPH_RELATIVE
|
||||
: aiMorphingMethod_MORPH_NORMALIZED;
|
||||
dstMesh->mMethod = (method == Collada::Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
|
||||
dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
|
||||
dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
|
||||
for (unsigned int i = 0; i < animMeshes.size(); ++i) {
|
||||
|
@ -792,7 +790,6 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex];
|
||||
size_t pairCount = pSrcController->mWeightCounts[orgIndex];
|
||||
|
||||
|
||||
for (size_t b = 0; b < pairCount; ++b, ++iit) {
|
||||
const size_t jointIndex = iit->first;
|
||||
const size_t vertexIndex = iit->second;
|
||||
|
@ -802,8 +799,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
|
|||
}
|
||||
|
||||
// one day I gonna kill that XSI Collada exporter
|
||||
if (weight > 0.0f)
|
||||
{
|
||||
if (weight > 0.0f) {
|
||||
aiVertexWeight w;
|
||||
w.mVertexId = static_cast<unsigned int>(a - pStartVertex);
|
||||
w.mWeight = weight;
|
||||
|
@ -980,8 +976,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
std::set<std::string> animTargets;
|
||||
animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
|
||||
bool collectedAnimationsHaveDifferentChannels = true;
|
||||
for (size_t b = 0; b < collectedAnimIndices.size(); ++b)
|
||||
{
|
||||
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
|
||||
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
|
||||
std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
|
||||
if (animTargets.find(channelName) == animTargets.end()) {
|
||||
|
@ -996,8 +991,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
continue;
|
||||
|
||||
// if there are other animations which fit the template anim, combine all channels into a single anim
|
||||
if (!collectedAnimIndices.empty())
|
||||
{
|
||||
if (!collectedAnimIndices.empty()) {
|
||||
aiAnimation *combinedAnim = new aiAnimation();
|
||||
combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a));
|
||||
combinedAnim->mDuration = templateAnim->mDuration;
|
||||
|
@ -1012,8 +1006,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
mAnims[a] = combinedAnim;
|
||||
|
||||
// move the memory of all other anims to the combined anim and erase them from the source anims
|
||||
for (size_t b = 0; b < collectedAnimIndices.size(); ++b)
|
||||
{
|
||||
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
|
||||
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
|
||||
combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0];
|
||||
srcAnimation->mChannels[0] = NULL;
|
||||
|
@ -1022,8 +1015,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
|
||||
// in a second go, delete all the single-channel-anims that we've stripped from their channels
|
||||
// back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one
|
||||
while (!collectedAnimIndices.empty())
|
||||
{
|
||||
while (!collectedAnimIndices.empty()) {
|
||||
mAnims.erase(mAnims.begin() + collectedAnimIndices.back());
|
||||
collectedAnimIndices.pop_back();
|
||||
}
|
||||
|
@ -1032,8 +1024,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
}
|
||||
|
||||
// now store all anims in the scene
|
||||
if (!mAnims.empty())
|
||||
{
|
||||
if (!mAnims.empty()) {
|
||||
pScene->mNumAnimations = static_cast<unsigned int>(mAnims.size());
|
||||
pScene->mAnimations = new aiAnimation *[mAnims.size()];
|
||||
std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations);
|
||||
|
@ -1044,8 +1035,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs the animations for the given source anim
|
||||
void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string &pPrefix)
|
||||
{
|
||||
void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix) {
|
||||
std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
|
||||
|
||||
// create nested animations, if given
|
||||
|
@ -1057,47 +1047,38 @@ void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParse
|
|||
CreateAnimation(pScene, pParser, pSrcAnim, animName);
|
||||
}
|
||||
|
||||
struct MorphTimeValues
|
||||
{
|
||||
struct MorphTimeValues {
|
||||
float mTime;
|
||||
struct key
|
||||
{
|
||||
struct key {
|
||||
float mWeight;
|
||||
unsigned int mValue;
|
||||
};
|
||||
std::vector<key> mKeys;
|
||||
};
|
||||
|
||||
void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value)
|
||||
{
|
||||
void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value) {
|
||||
MorphTimeValues::key k;
|
||||
k.mValue = value;
|
||||
k.mWeight = weight;
|
||||
if (values.size() == 0 || time < values[0].mTime)
|
||||
{
|
||||
if (values.size() == 0 || time < values[0].mTime) {
|
||||
MorphTimeValues val;
|
||||
val.mTime = time;
|
||||
val.mKeys.push_back(k);
|
||||
values.insert(values.begin(), val);
|
||||
return;
|
||||
}
|
||||
if (time > values.back().mTime)
|
||||
{
|
||||
if (time > values.back().mTime) {
|
||||
MorphTimeValues val;
|
||||
val.mTime = time;
|
||||
val.mKeys.push_back(k);
|
||||
values.insert(values.end(), val);
|
||||
return;
|
||||
}
|
||||
for (unsigned int i = 0; i < values.size(); i++)
|
||||
{
|
||||
if (std::abs(time - values[i].mTime) < 1e-6f)
|
||||
{
|
||||
for (unsigned int i = 0; i < values.size(); i++) {
|
||||
if (std::abs(time - values[i].mTime) < 1e-6f) {
|
||||
values[i].mKeys.push_back(k);
|
||||
return;
|
||||
}
|
||||
else if (time > values[i].mTime && time < values[i + 1].mTime)
|
||||
{
|
||||
} else if (time > values[i].mTime && time < values[i + 1].mTime) {
|
||||
MorphTimeValues val;
|
||||
val.mTime = time;
|
||||
val.mKeys.push_back(k);
|
||||
|
@ -1108,10 +1089,8 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
|
|||
// should not get here
|
||||
}
|
||||
|
||||
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value)
|
||||
{
|
||||
for (unsigned int i = 0; i < values[key].mKeys.size(); i++)
|
||||
{
|
||||
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
|
||||
for (unsigned int i = 0; i < values[key].mKeys.size(); i++) {
|
||||
if (values[key].mKeys[i].mValue == value)
|
||||
return values[key].mKeys[i].mWeight;
|
||||
}
|
||||
|
@ -1122,8 +1101,7 @@ float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsign
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs the animation for the given source anim
|
||||
void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName)
|
||||
{
|
||||
void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName) {
|
||||
// collect a list of animatable nodes
|
||||
std::vector<const aiNode *> nodes;
|
||||
CollectNodes(pScene->mRootNode, nodes);
|
||||
|
@ -1131,8 +1109,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
std::vector<aiNodeAnim *> anims;
|
||||
std::vector<aiMeshMorphAnim *> morphAnims;
|
||||
|
||||
for (std::vector<const aiNode*>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
|
||||
{
|
||||
for (std::vector<const aiNode *>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) {
|
||||
// find all the collada anim channels which refer to the current node
|
||||
std::vector<Collada::ChannelEntry> entries;
|
||||
std::string nodeName = (*nit)->mName.data;
|
||||
|
@ -1146,16 +1123,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
// now check all channels if they affect the current node
|
||||
std::string targetID, subElement;
|
||||
for (std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
|
||||
cit != pSrcAnim->mChannels.end(); ++cit)
|
||||
{
|
||||
cit != pSrcAnim->mChannels.end(); ++cit) {
|
||||
const Collada::AnimationChannel &srcChannel = *cit;
|
||||
Collada::ChannelEntry entry;
|
||||
|
||||
// we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
|
||||
// find the slash that separates the node name - there should be only one
|
||||
std::string::size_type slashPos = srcChannel.mTarget.find('/');
|
||||
if (slashPos == std::string::npos)
|
||||
{
|
||||
if (slashPos == std::string::npos) {
|
||||
std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID);
|
||||
if (targetPos == std::string::npos)
|
||||
continue;
|
||||
|
@ -1179,8 +1154,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
|
||||
// find the dot that separates the transformID - there should be only one or zero
|
||||
std::string::size_type dotPos = srcChannel.mTarget.find('.');
|
||||
if (dotPos != std::string::npos)
|
||||
{
|
||||
if (dotPos != std::string::npos) {
|
||||
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos)
|
||||
continue;
|
||||
|
||||
|
@ -1198,15 +1172,13 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
entry.mSubElement = 2;
|
||||
else
|
||||
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// no subelement following, transformId is remaining string
|
||||
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
|
||||
}
|
||||
|
||||
std::string::size_type bracketPos = srcChannel.mTarget.find('(');
|
||||
if (bracketPos != std::string::npos)
|
||||
{
|
||||
if (bracketPos != std::string::npos) {
|
||||
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
|
||||
subElement.clear();
|
||||
subElement = srcChannel.mTarget.substr(bracketPos);
|
||||
|
@ -1251,14 +1223,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
if (srcNode->mTransforms[a].mID == entry.mTransformId)
|
||||
entry.mTransformIndex = a;
|
||||
|
||||
if (entry.mTransformIndex == SIZE_MAX)
|
||||
{
|
||||
if (entry.mTransformId.find("morph-weights") != std::string::npos)
|
||||
{
|
||||
if (entry.mTransformIndex == SIZE_MAX) {
|
||||
if (entry.mTransformId.find("morph-weights") != std::string::npos) {
|
||||
entry.mTargetId = entry.mTransformId;
|
||||
entry.mTransformId = "";
|
||||
}
|
||||
else
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1272,8 +1241,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
|
||||
// resolve the data pointers for all anim channels. Find the minimum time while we're at it
|
||||
ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
||||
{
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
||||
Collada::ChannelEntry &e = *it;
|
||||
e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
|
||||
e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
|
||||
|
@ -1284,8 +1252,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
|
||||
throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\".");
|
||||
|
||||
if (e.mTimeAccessor->mCount > 0)
|
||||
{
|
||||
if (e.mTimeAccessor->mCount > 0) {
|
||||
// find bounding times
|
||||
startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0));
|
||||
endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0));
|
||||
|
@ -1293,25 +1260,21 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
}
|
||||
|
||||
std::vector<aiMatrix4x4> resultTrafos;
|
||||
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0)
|
||||
{
|
||||
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
|
||||
// create a local transformation chain of the node's transforms
|
||||
std::vector<Collada::Transform> transforms = srcNode->mTransforms;
|
||||
|
||||
// now for every unique point in time, find or interpolate the key values for that time
|
||||
// and apply them to the transform chain. Then the node's present transformation can be calculated.
|
||||
ai_real time = startTime;
|
||||
while (1)
|
||||
{
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
||||
{
|
||||
while (1) {
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
||||
Collada::ChannelEntry &e = *it;
|
||||
|
||||
// find the keyframe behind the current point in time
|
||||
size_t pos = 0;
|
||||
ai_real postTime = 0.0;
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
if (pos >= e.mTimeAccessor->mCount)
|
||||
break;
|
||||
postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
|
||||
|
@ -1328,13 +1291,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c);
|
||||
|
||||
// if not exactly at the key time, interpolate with previous value set
|
||||
if (postTime > time && pos > 0)
|
||||
{
|
||||
if (postTime > time && pos > 0) {
|
||||
ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0);
|
||||
ai_real factor = (time - postTime) / (preTime - postTime);
|
||||
|
||||
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
||||
{
|
||||
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) {
|
||||
ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c);
|
||||
temp[c] += (v - temp[c]) * factor;
|
||||
}
|
||||
|
@ -1353,17 +1314,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
|
||||
// find next point in time to evaluate. That's the closest frame larger than the current in any channel
|
||||
ai_real nextTime = ai_real(1e20);
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
||||
{
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
||||
Collada::ChannelEntry &channelElement = *it;
|
||||
|
||||
// find the next time value larger than the current
|
||||
size_t pos = 0;
|
||||
while (pos < channelElement.mTimeAccessor->mCount)
|
||||
{
|
||||
while (pos < channelElement.mTimeAccessor->mCount) {
|
||||
const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
|
||||
if (t > time)
|
||||
{
|
||||
if (t > time) {
|
||||
nextTime = std::min(nextTime, t);
|
||||
break;
|
||||
}
|
||||
|
@ -1403,8 +1361,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
// ai_assert( resultTrafos.size() > 0);
|
||||
|
||||
// build an animation channel for the given node out of these trafo keys
|
||||
if (!resultTrafos.empty())
|
||||
{
|
||||
if (!resultTrafos.empty()) {
|
||||
aiNodeAnim *dstAnim = new aiNodeAnim;
|
||||
dstAnim->mNodeName = nodeName;
|
||||
dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
|
||||
|
@ -1414,30 +1371,25 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
|
||||
dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
|
||||
|
||||
for (size_t a = 0; a < resultTrafos.size(); ++a)
|
||||
{
|
||||
for (size_t a = 0; a < resultTrafos.size(); ++a) {
|
||||
aiMatrix4x4 mat = resultTrafos[a];
|
||||
double time = double(mat.d4); // remember? time is stored in mat.d4
|
||||
mat.d4 = 1.0f;
|
||||
|
||||
dstAnim->mPositionKeys[a].mTime = time;
|
||||
dstAnim->mRotationKeys[a].mTime = time;
|
||||
dstAnim->mScalingKeys[a].mTime = time;
|
||||
dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ;
|
||||
dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ;
|
||||
dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ;
|
||||
mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
|
||||
}
|
||||
|
||||
anims.push_back(dstAnim);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter.");
|
||||
}
|
||||
|
||||
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0)
|
||||
{
|
||||
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
|
||||
std::vector<Collada::ChannelEntry> morphChannels;
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
||||
{
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
||||
Collada::ChannelEntry &e = *it;
|
||||
|
||||
// skip non-transform types
|
||||
|
@ -1447,8 +1399,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
if (e.mTargetId.find("morph-weights") != std::string::npos)
|
||||
morphChannels.push_back(e);
|
||||
}
|
||||
if (morphChannels.size() > 0)
|
||||
{
|
||||
if (!morphChannels.empty() ) {
|
||||
// either 1) morph weight animation count should contain morph target count channels
|
||||
// or 2) one channel with morph target count arrays
|
||||
// assume first
|
||||
|
@ -1457,10 +1408,8 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
morphAnim->mName.Set(nodeName);
|
||||
|
||||
std::vector<MorphTimeValues> morphTimeValues;
|
||||
|
||||
int morphAnimChannelIndex = 0;
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it)
|
||||
{
|
||||
for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) {
|
||||
Collada::ChannelEntry &e = *it;
|
||||
std::string::size_type apos = e.mTargetId.find('(');
|
||||
std::string::size_type bpos = e.mTargetId.find(')');
|
||||
|
@ -1470,23 +1419,22 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
|
||||
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
|
||||
// we ignore the name and just assume the channels are in the right order
|
||||
for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++)
|
||||
insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues.at(i), e.mValueData->mValues.at(i), morphAnimChannelIndex);
|
||||
for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++) {
|
||||
insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues[i], e.mValueData->mValues[i], morphAnimChannelIndex);
|
||||
}
|
||||
|
||||
++morphAnimChannelIndex;
|
||||
}
|
||||
|
||||
morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size());
|
||||
morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
|
||||
for (unsigned int key = 0; key < morphAnim->mNumKeys; key++)
|
||||
{
|
||||
for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) {
|
||||
morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size());
|
||||
morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
|
||||
morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
|
||||
|
||||
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime;
|
||||
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++)
|
||||
{
|
||||
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ;
|
||||
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) {
|
||||
morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
|
||||
morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
|
||||
}
|
||||
|
@ -1497,31 +1445,26 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
}
|
||||
}
|
||||
|
||||
if (!anims.empty() || !morphAnims.empty())
|
||||
{
|
||||
if (!anims.empty() || !morphAnims.empty()) {
|
||||
aiAnimation *anim = new aiAnimation;
|
||||
anim->mName.Set(pName);
|
||||
anim->mNumChannels = static_cast<unsigned int>(anims.size());
|
||||
if (anim->mNumChannels > 0)
|
||||
{
|
||||
if (anim->mNumChannels > 0) {
|
||||
anim->mChannels = new aiNodeAnim *[anims.size()];
|
||||
std::copy(anims.begin(), anims.end(), anim->mChannels);
|
||||
}
|
||||
anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size());
|
||||
if (anim->mNumMorphMeshChannels > 0)
|
||||
{
|
||||
if (anim->mNumMorphMeshChannels > 0) {
|
||||
anim->mMorphMeshChannels = new aiMeshMorphAnim *[anim->mNumMorphMeshChannels];
|
||||
std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
|
||||
}
|
||||
anim->mDuration = 0.0f;
|
||||
for (size_t a = 0; a < anims.size(); ++a)
|
||||
{
|
||||
for (size_t a = 0; a < anims.size(); ++a) {
|
||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime);
|
||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime);
|
||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime);
|
||||
}
|
||||
for (size_t a = 0; a < morphAnims.size(); ++a)
|
||||
{
|
||||
for (size_t a = 0; a < morphAnims.size(); ++a) {
|
||||
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
|
||||
}
|
||||
anim->mTicksPerSecond = 1;
|
||||
|
@ -1534,26 +1477,29 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
|
|||
void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser,
|
||||
const Collada::Effect &effect,
|
||||
const Collada::Sampler &sampler,
|
||||
aiTextureType type, unsigned int idx)
|
||||
{
|
||||
aiTextureType type, unsigned int idx) {
|
||||
// first of all, basic file name
|
||||
const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
|
||||
mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
|
||||
|
||||
// mapping mode
|
||||
int map = aiTextureMapMode_Clamp;
|
||||
if (sampler.mWrapU)
|
||||
if (sampler.mWrapU) {
|
||||
map = aiTextureMapMode_Wrap;
|
||||
if (sampler.mWrapU && sampler.mMirrorU)
|
||||
}
|
||||
if (sampler.mWrapU && sampler.mMirrorU) {
|
||||
map = aiTextureMapMode_Mirror;
|
||||
}
|
||||
|
||||
mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx);
|
||||
|
||||
map = aiTextureMapMode_Clamp;
|
||||
if (sampler.mWrapV)
|
||||
if (sampler.mWrapV) {
|
||||
map = aiTextureMapMode_Wrap;
|
||||
if (sampler.mWrapV && sampler.mMirrorV)
|
||||
}
|
||||
if (sampler.mWrapV && sampler.mMirrorV) {
|
||||
map = aiTextureMapMode_Mirror;
|
||||
}
|
||||
|
||||
mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx);
|
||||
|
||||
|
@ -1574,9 +1520,9 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser,
|
|||
// number in the channel name. We assume it is the zero-based index into the
|
||||
// UV channel array of all corresponding meshes. It could also be one-based
|
||||
// for some exporters, but we won't care of it unless someone complains about.
|
||||
if (sampler.mUVId != UINT_MAX)
|
||||
if (sampler.mUVId != UINT_MAX) {
|
||||
map = sampler.mUVId;
|
||||
else {
|
||||
} else {
|
||||
map = -1;
|
||||
for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
|
||||
if (IsNumeric(*it)) {
|
||||
|
@ -1594,20 +1540,17 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Fills materials from the collada material definitions
|
||||
void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScene*/)
|
||||
{
|
||||
for (auto &elem : newMats)
|
||||
{
|
||||
void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pScene*/) {
|
||||
for (auto &elem : newMats) {
|
||||
aiMaterial &mat = (aiMaterial &)*elem.second;
|
||||
Collada::Effect &effect = *elem.first;
|
||||
|
||||
// resolve shading mode
|
||||
int shadeMode;
|
||||
if (effect.mFaceted) /* fixme */
|
||||
if (effect.mFaceted) {
|
||||
shadeMode = aiShadingMode_Flat;
|
||||
else {
|
||||
switch (effect.mShadeType)
|
||||
{
|
||||
} else {
|
||||
switch (effect.mShadeType) {
|
||||
case Collada::Shade_Constant:
|
||||
shadeMode = aiShadingMode_NoShading;
|
||||
break;
|
||||
|
@ -1657,17 +1600,14 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen
|
|||
// handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304
|
||||
if (effect.mRGBTransparency) {
|
||||
// use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4)
|
||||
effect.mTransparency *= (
|
||||
0.212671f * effect.mTransparent.r +
|
||||
effect.mTransparency *= (0.212671f * effect.mTransparent.r +
|
||||
0.715160f * effect.mTransparent.g +
|
||||
0.072169f * effect.mTransparent.b
|
||||
);
|
||||
0.072169f * effect.mTransparent.b);
|
||||
|
||||
effect.mTransparent.a = 1.f;
|
||||
|
||||
mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
effect.mTransparency *= effect.mTransparent.a;
|
||||
}
|
||||
|
||||
|
@ -1709,8 +1649,7 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs materials from the collada material definitions
|
||||
void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/)
|
||||
{
|
||||
void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/) {
|
||||
newMats.reserve(pParser.mMaterialLibrary.size());
|
||||
|
||||
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
|
||||
|
@ -1734,37 +1673,18 @@ void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/)
|
|||
// ScenePreprocessor generates a default material automatically if none is there.
|
||||
// All further code here in this loader works well without a valid material so
|
||||
// we can safely let it to ScenePreprocessor.
|
||||
#if 0
|
||||
if (newMats.size() == 0)
|
||||
{
|
||||
aiMaterial* mat = new aiMaterial;
|
||||
aiString name(AI_DEFAULT_MATERIAL_NAME);
|
||||
mat->AddProperty(&name, AI_MATKEY_NAME);
|
||||
|
||||
const int shadeMode = aiShadingMode_Phong;
|
||||
mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
aiColor4D colAmbient(0.2, 0.2, 0.2, 1.0), colDiffuse(0.8, 0.8, 0.8, 1.0), colSpecular(0.5, 0.5, 0.5, 0.5);
|
||||
mat->AddProperty(&colAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
mat->AddProperty(&colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mat->AddProperty(&colSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
const ai_real specExp = 5.0;
|
||||
mat->AddProperty(&specExp, 1, AI_MATKEY_SHININESS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolves the texture name for the given effect texture entry
|
||||
// and loads the texture data
|
||||
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser,
|
||||
const Collada::Effect& pEffect, const std::string& pName)
|
||||
{
|
||||
const Collada::Effect &pEffect, const std::string &pName) {
|
||||
aiString result;
|
||||
|
||||
// recurse through the param references until we end up at an image
|
||||
std::string name = pName;
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
// the given string is a param entry. Find it
|
||||
Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
|
||||
// if not found, we're at the end of the recursion. The resulting string should be the image ID
|
||||
|
@ -1777,8 +1697,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
|
||||
// find the image referred by this name in the image library of the scene
|
||||
ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name);
|
||||
if (imIt == pParser.mImageLibrary.end())
|
||||
{
|
||||
if (imIt == pParser.mImageLibrary.end()) {
|
||||
ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
|
||||
|
||||
//set default texture file name
|
||||
|
@ -1788,8 +1707,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
}
|
||||
|
||||
// if this is an embedded texture image setup an aiTexture for it
|
||||
if (!imIt->second.mImageData.empty())
|
||||
{
|
||||
if (!imIt->second.mImageData.empty()) {
|
||||
aiTexture *tex = new aiTexture();
|
||||
|
||||
// Store embedded texture name reference
|
||||
|
@ -1800,7 +1718,6 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
// result.data[0] = '*';
|
||||
// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
||||
|
||||
|
||||
// setup format hint
|
||||
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
|
||||
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
||||
|
@ -1815,23 +1732,21 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
|
||||
// and add this texture to the list
|
||||
mTextures.push_back(tex);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (imIt->second.mFileName.empty()) {
|
||||
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
|
||||
}
|
||||
|
||||
result.Set(imIt->second.mFileName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a float value from an accessor and its data array.
|
||||
ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const
|
||||
{
|
||||
// FIXME: (thom) Test for data type here in every access? For the moment, I leave this to the caller
|
||||
ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const {
|
||||
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
|
||||
ai_assert(pos < pData.mValues.size());
|
||||
return pData.mValues[pos];
|
||||
|
@ -1839,8 +1754,7 @@ ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Colla
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a string value from an accessor and its data array.
|
||||
const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const
|
||||
{
|
||||
const std::string &ColladaLoader::ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const {
|
||||
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
|
||||
ai_assert(pos < pData.mStrings.size());
|
||||
return pData.mStrings[pos];
|
||||
|
@ -1848,8 +1762,7 @@ const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Collects all nodes into the given array
|
||||
void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector<const aiNode*>& poNodes) const
|
||||
{
|
||||
void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector<const aiNode *> &poNodes) const {
|
||||
poNodes.push_back(pNode);
|
||||
for (size_t a = 0; a < pNode->mNumChildren; ++a) {
|
||||
CollectNodes(pNode->mChildren[a], poNodes);
|
||||
|
@ -1858,13 +1771,11 @@ void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector<const aiNode*>
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Finds a node in the collada scene by the given name
|
||||
const Collada::Node* ColladaLoader::FindNode(const Collada::Node* pNode, const std::string& pName) const
|
||||
{
|
||||
const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const std::string &pName) const {
|
||||
if (pNode->mName == pName || pNode->mID == pName)
|
||||
return pNode;
|
||||
|
||||
for (size_t a = 0; a < pNode->mChildren.size(); ++a)
|
||||
{
|
||||
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
|
||||
const Collada::Node *node = FindNode(pNode->mChildren[a], pName);
|
||||
if (node)
|
||||
return node;
|
||||
|
@ -1897,28 +1808,22 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Finds a proper unique name for a node derived from the collada-node's properties.
|
||||
// The name must be unique for proper node-bone association.
|
||||
std::string ColladaLoader::FindNameForNode(const Collada::Node* pNode)
|
||||
{
|
||||
std::string ColladaLoader::FindNameForNode(const Collada::Node *pNode) {
|
||||
// If explicitly requested, just use the collada name.
|
||||
if (useColladaName)
|
||||
{
|
||||
if (useColladaName) {
|
||||
if (!pNode->mName.empty()) {
|
||||
return pNode->mName;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Now setup the name of the assimp node. The collada name might not be
|
||||
// unique, so we use the collada ID.
|
||||
if (!pNode->mID.empty())
|
||||
return pNode->mID;
|
||||
else if (!pNode->mSID.empty())
|
||||
return pNode->mSID;
|
||||
else
|
||||
{
|
||||
else {
|
||||
// No need to worry. Unnamed nodes are no problem at all, except
|
||||
// if cameras or lights need to be assigned to them.
|
||||
return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
|
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,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX
|
||||
{
|
||||
namespace FBX {
|
||||
|
||||
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||
|
@ -80,8 +80,8 @@ namespace FBX
|
|||
|
||||
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