Merge branch 'master' into isue_1621
commit
483541ee25
117
CMakeLists.txt
117
CMakeLists.txt
|
@ -110,7 +110,6 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(MSVC)
|
IF(MSVC)
|
||||||
SET (CMAKE_PREFIX_PATH "D:\\libs\\devil")
|
|
||||||
OPTION( ASSIMP_INSTALL_PDB
|
OPTION( ASSIMP_INSTALL_PDB
|
||||||
"Install MSVC debug files."
|
"Install MSVC debug files."
|
||||||
ON
|
ON
|
||||||
|
@ -139,8 +138,7 @@ SET (PROJECT_VERSION "${ASSIMP_VERSION}")
|
||||||
|
|
||||||
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
||||||
|
|
||||||
# Needed for openddl_parser config, no use of c++11 at this moment
|
# Enable C++1 globally
|
||||||
ADD_DEFINITIONS( -DOPENDDL_NO_USE_CPP11 )
|
|
||||||
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
||||||
|
|
||||||
# Get the current working branch
|
# Get the current working branch
|
||||||
|
@ -162,7 +160,7 @@ EXECUTE_PROCESS(
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(NOT GIT_COMMIT_HASH)
|
IF(NOT GIT_COMMIT_HASH)
|
||||||
SET(GIT_COMMIT_HASH 0)
|
SET(GIT_COMMIT_HASH 0)
|
||||||
ENDIF(NOT GIT_COMMIT_HASH)
|
ENDIF(NOT GIT_COMMIT_HASH)
|
||||||
|
|
||||||
IF(ASSIMP_DOUBLE_PRECISION)
|
IF(ASSIMP_DOUBLE_PRECISION)
|
||||||
|
@ -180,10 +178,10 @@ CONFIGURE_FILE(
|
||||||
)
|
)
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(
|
INCLUDE_DIRECTORIES(
|
||||||
./
|
./
|
||||||
include
|
include
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
|
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
|
||||||
|
@ -193,14 +191,6 @@ SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPO
|
||||||
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
|
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
|
||||||
|
|
||||||
IF( UNIX )
|
IF( UNIX )
|
||||||
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
|
|
||||||
IF( ${OPERATING_SYSTEM} MATCHES "Android")
|
|
||||||
ELSE()
|
|
||||||
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
|
|
||||||
#ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
|
|
||||||
ENDIF()
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
# Use GNUInstallDirs for Unix predefined directories
|
# Use GNUInstallDirs for Unix predefined directories
|
||||||
INCLUDE(GNUInstallDirs)
|
INCLUDE(GNUInstallDirs)
|
||||||
ENDIF( UNIX )
|
ENDIF( UNIX )
|
||||||
|
@ -213,13 +203,13 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
|
||||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||||
ELSEIF(MSVC)
|
ELSEIF(MSVC)
|
||||||
# enable multi-core compilation with MSVC
|
# enable multi-core compilation with MSVC
|
||||||
add_compile_options(/MP)
|
ADD_COMPILE_OPTIONS(/MP)
|
||||||
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
||||||
add_compile_options( /bigobj )
|
ADD_COMPILE_OPTIONS( /bigobj )
|
||||||
endif()
|
ENDIF()
|
||||||
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
||||||
IF(MSVC12)
|
IF(MSVC12)
|
||||||
add_compile_options(/wd4351)
|
ADD_COMPILE_OPTIONS(/wd4351)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" )
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" )
|
||||||
|
@ -230,34 +220,39 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
||||||
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
if (ASSIMP_COVERALLS)
|
IF (IOS)
|
||||||
MESSAGE(STATUS "Coveralls enabled")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
|
||||||
INCLUDE(Coveralls)
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
ENDIF()
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ASSIMP_WERROR)
|
IF (ASSIMP_COVERALLS)
|
||||||
|
MESSAGE(STATUS "Coveralls enabled")
|
||||||
|
INCLUDE(Coveralls)
|
||||||
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
||||||
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF (ASSIMP_WERROR)
|
||||||
MESSAGE(STATUS "Treating warnings as errors")
|
MESSAGE(STATUS "Treating warnings as errors")
|
||||||
IF (MSVC)
|
IF (MSVC)
|
||||||
add_compile_options(/WX)
|
ADD_COMPILE_OPTIONS(/WX)
|
||||||
ELSE()
|
ELSE()
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
endif()
|
ENDIF()
|
||||||
|
|
||||||
if (ASSIMP_ASAN)
|
IF (ASSIMP_ASAN)
|
||||||
MESSAGE(STATUS "AddressSanitizer enabled")
|
MESSAGE(STATUS "AddressSanitizer enabled")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||||
endif()
|
ENDIF()
|
||||||
|
|
||||||
if (ASSIMP_UBSAN)
|
IF (ASSIMP_UBSAN)
|
||||||
MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
|
MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
|
||||||
endif()
|
ENDIF()
|
||||||
|
|
||||||
INCLUDE (FindPkgMacros)
|
INCLUDE (FindPkgMacros)
|
||||||
INCLUDE (PrecompiledHeader)
|
INCLUDE (PrecompiledHeader)
|
||||||
|
@ -290,42 +285,42 @@ ENDIF()
|
||||||
IF (NOT TARGET uninstall)
|
IF (NOT TARGET uninstall)
|
||||||
# add make uninstall capability
|
# add make uninstall capability
|
||||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||||
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
# cmake configuration files
|
# cmake configuration files
|
||||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
||||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
|
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
|
||||||
|
|
||||||
FIND_PACKAGE( DirectX )
|
FIND_PACKAGE( DirectX )
|
||||||
|
|
||||||
IF( BUILD_DOCS )
|
IF( BUILD_DOCS )
|
||||||
add_subdirectory(doc)
|
ADD_SUBDIRECTORY(doc)
|
||||||
ENDIF( BUILD_DOCS )
|
ENDIF( BUILD_DOCS )
|
||||||
|
|
||||||
# Look for system installed irrXML
|
# Look for system installed irrXML
|
||||||
IF ( SYSTEM_IRRXML )
|
IF ( SYSTEM_IRRXML )
|
||||||
find_package( IrrXML REQUIRED )
|
FIND_PACKAGE( IrrXML REQUIRED )
|
||||||
ENDIF( SYSTEM_IRRXML )
|
ENDIF( SYSTEM_IRRXML )
|
||||||
|
|
||||||
# Search for external dependencies, and build them from source if not found
|
# Search for external dependencies, and build them from source if not found
|
||||||
# Search for zlib
|
# Search for zlib
|
||||||
IF ( NOT ASSIMP_BUILD_ZLIB )
|
IF ( NOT ASSIMP_BUILD_ZLIB )
|
||||||
find_package(ZLIB)
|
FIND_PACKAGE(ZLIB)
|
||||||
ENDIF( NOT ASSIMP_BUILD_ZLIB )
|
ENDIF( NOT ASSIMP_BUILD_ZLIB )
|
||||||
|
|
||||||
IF( NOT ZLIB_FOUND )
|
IF( NOT ZLIB_FOUND )
|
||||||
message(STATUS "compiling zlib from souces")
|
MESSAGE(STATUS "compiling zlib from souces")
|
||||||
INCLUDE(CheckIncludeFile)
|
INCLUDE(CheckIncludeFile)
|
||||||
INCLUDE(CheckTypeSize)
|
INCLUDE(CheckTypeSize)
|
||||||
INCLUDE(CheckFunctionExists)
|
INCLUDE(CheckFunctionExists)
|
||||||
# compile from sources
|
# compile from sources
|
||||||
add_subdirectory(contrib/zlib)
|
ADD_SUBDIRECTORY(contrib/zlib)
|
||||||
SET(ZLIB_FOUND 1)
|
SET(ZLIB_FOUND 1)
|
||||||
SET(ZLIB_LIBRARIES zlibstatic)
|
SET(ZLIB_LIBRARIES zlibstatic)
|
||||||
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
|
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
|
||||||
else(NOT ZLIB_FOUND)
|
ELSE(NOT ZLIB_FOUND)
|
||||||
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
|
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
|
||||||
SET(ZLIB_LIBRARIES_LINKED -lz)
|
SET(ZLIB_LIBRARIES_LINKED -lz)
|
||||||
ENDIF(NOT ZLIB_FOUND)
|
ENDIF(NOT ZLIB_FOUND)
|
||||||
|
@ -367,7 +362,9 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
||||||
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
|
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
|
||||||
|
|
||||||
# pick the correct prebuilt library
|
# pick the correct prebuilt library
|
||||||
IF(MSVC14)
|
IF(MSVC15)
|
||||||
|
SET(C4D_LIB_POSTFIX "_2017")
|
||||||
|
ELSEIF(MSVC14)
|
||||||
SET(C4D_LIB_POSTFIX "_2015")
|
SET(C4D_LIB_POSTFIX "_2015")
|
||||||
ELSEIF(MSVC12)
|
ELSEIF(MSVC12)
|
||||||
SET(C4D_LIB_POSTFIX "_2013")
|
SET(C4D_LIB_POSTFIX "_2013")
|
||||||
|
@ -408,7 +405,7 @@ ADD_SUBDIRECTORY(contrib)
|
||||||
ADD_SUBDIRECTORY( code/ )
|
ADD_SUBDIRECTORY( code/ )
|
||||||
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||||
IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
||||||
option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
|
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
|
||||||
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||||
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
||||||
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||||
|
@ -472,8 +469,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
||||||
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
|
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
|
||||||
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||||
|
|
||||||
string(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
|
STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
|
||||||
string(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
|
STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
|
||||||
|
|
||||||
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
|
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
|
||||||
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
|
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
|
||||||
|
@ -503,8 +500,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
|
||||||
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
|
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
|
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
|
||||||
include(CPack)
|
INCLUDE(CPack)
|
||||||
include(DebSourcePPA)
|
INCLUDE(DebSourcePPA)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -516,14 +513,16 @@ if(WIN32)
|
||||||
SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/")
|
SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
if(MSVC12)
|
IF(MSVC12)
|
||||||
SET(ASSIMP_MSVC_VERSION "vc120")
|
SET(ASSIMP_MSVC_VERSION "vc120")
|
||||||
elseif(MSVC14)
|
ELSEIF(MSVC14)
|
||||||
SET(ASSIMP_MSVC_VERSION "vc140")
|
SET(ASSIMP_MSVC_VERSION "vc140")
|
||||||
|
ELSEIF(MSVC15)
|
||||||
|
SET(ASSIMP_MSVC_VERSION "vc141")
|
||||||
ENDIF(MSVC12)
|
ENDIF(MSVC12)
|
||||||
|
|
||||||
if(MSVC12 OR MSVC14)
|
IF(MSVC12 OR MSVC14 OR MSVC15 )
|
||||||
add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
|
ADD_CUSTOM_TARGET(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
|
||||||
IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
|
IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
|
||||||
|
@ -544,5 +543,5 @@ if(WIN32)
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||||
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF(MSVC12 OR MSVC14)
|
ENDIF(MSVC12 OR MSVC14 OR MSVC15 )
|
||||||
ENDIF (WIN32)
|
ENDIF (WIN32)
|
||||||
|
|
17
CREDITS
17
CREDITS
|
@ -157,12 +157,27 @@ Contributed ExportProperties interface
|
||||||
Contributed X File exporter
|
Contributed X File exporter
|
||||||
Contributed Step (stp) exporter
|
Contributed Step (stp) exporter
|
||||||
|
|
||||||
|
- Thomas Iorns (mesilliac)
|
||||||
|
Initial FBX Export support
|
||||||
|
|
||||||
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
||||||
|
|
||||||
Patreons:
|
|
||||||
|
========
|
||||||
|
Patreons
|
||||||
|
========
|
||||||
|
|
||||||
|
Huge thanks to our Patreons!
|
||||||
|
|
||||||
- migenius
|
- migenius
|
||||||
- Marcus
|
- Marcus
|
||||||
- Cort
|
- Cort
|
||||||
- elect
|
- elect
|
||||||
- Steffen
|
- Steffen
|
||||||
|
|
||||||
|
|
||||||
|
===================
|
||||||
|
Commercial Sponsors
|
||||||
|
===================
|
||||||
|
|
||||||
|
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
|
||||||
|
|
46
Readme.md
46
Readme.md
|
@ -32,32 +32,32 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki
|
||||||
|
|
||||||
#### Supported file formats ####
|
#### Supported file formats ####
|
||||||
|
|
||||||
A full list [is here](http://assimp.org/main_features_formats.html).
|
|
||||||
__Importers__:
|
__Importers__:
|
||||||
|
|
||||||
- 3D
|
- 3D
|
||||||
- 3DS
|
- [3DS](https://en.wikipedia.org/wiki/.3ds)
|
||||||
- 3MF
|
- [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format)
|
||||||
- AC
|
- AC
|
||||||
- AC3D
|
- [AC3D](https://en.wikipedia.org/wiki/AC3D)
|
||||||
- ACC
|
- ACC
|
||||||
- AMJ
|
- AMJ
|
||||||
- ASE
|
- ASE
|
||||||
- ASK
|
- ASK
|
||||||
- B3D
|
- B3D
|
||||||
- BLEND (Blender)
|
- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
|
||||||
- BVH
|
- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
|
||||||
- COB
|
|
||||||
- CMS
|
- CMS
|
||||||
- DAE/Collada
|
- COB
|
||||||
- DXF
|
- [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA)
|
||||||
|
- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF)
|
||||||
- ENFF
|
- ENFF
|
||||||
- FBX
|
- [FBX](https://en.wikipedia.org/wiki/FBX)
|
||||||
- glTF 1.0 + GLB
|
- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
|
||||||
- glTF 2.0
|
- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0)
|
||||||
- HMB
|
- HMB
|
||||||
- IFC-STEP
|
- IFC-STEP
|
||||||
- IRR / IRRMESH
|
- IRR / IRRMESH
|
||||||
- LWO
|
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
|
||||||
- LWS
|
- LWS
|
||||||
- LXO
|
- LXO
|
||||||
- MD2
|
- MD2
|
||||||
|
@ -70,10 +70,10 @@ __Importers__:
|
||||||
- MS3D
|
- MS3D
|
||||||
- NDO
|
- NDO
|
||||||
- NFF
|
- NFF
|
||||||
- OBJ
|
- [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
|
||||||
- OFF
|
- [OFF](https://en.wikipedia.org/wiki/OFF_(file_format))
|
||||||
- OGEX
|
- [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange)
|
||||||
- PLY
|
- [PLY](https://en.wikipedia.org/wiki/PLY_(file_format))
|
||||||
- PMX
|
- PMX
|
||||||
- PRJ
|
- PRJ
|
||||||
- Q3O
|
- Q3O
|
||||||
|
@ -82,19 +82,19 @@ __Importers__:
|
||||||
- SCN
|
- SCN
|
||||||
- SIB
|
- SIB
|
||||||
- SMD
|
- SMD
|
||||||
- STL
|
- [STP](https://en.wikipedia.org/wiki/ISO_10303-21)
|
||||||
- STP
|
- [STL](https://en.wikipedia.org/wiki/STL_(file_format))
|
||||||
- TER
|
- TER
|
||||||
- UC
|
- UC
|
||||||
- VTA
|
- VTA
|
||||||
- X
|
- X
|
||||||
- X3D
|
- [X3D](https://en.wikipedia.org/wiki/X3D)
|
||||||
- XGL
|
- XGL
|
||||||
- ZGL
|
- ZGL
|
||||||
|
|
||||||
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
|
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
|
||||||
|
|
||||||
- C4D (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange)
|
- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange)
|
||||||
|
|
||||||
__Exporters__:
|
__Exporters__:
|
||||||
|
|
||||||
|
@ -109,6 +109,8 @@ __Exporters__:
|
||||||
- STEP
|
- STEP
|
||||||
- glTF 1.0 (partial)
|
- glTF 1.0 (partial)
|
||||||
- glTF 2.0 (partial)
|
- glTF 2.0 (partial)
|
||||||
|
- 3MF ( experimental )
|
||||||
|
- FBX ( experimental )
|
||||||
|
|
||||||
### Building ###
|
### Building ###
|
||||||
Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
|
Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
|
||||||
|
@ -120,7 +122,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
|
||||||
* [Pascal](port/AssimpPascal/Readme.md)
|
* [Pascal](port/AssimpPascal/Readme.md)
|
||||||
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
||||||
* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
|
* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
|
||||||
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, collada, md2)
|
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
|
||||||
|
|
||||||
### Other tools ###
|
### Other tools ###
|
||||||
[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
|
[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
|
||||||
|
|
|
@ -34,36 +34,18 @@ if( MSVC )
|
||||||
else()
|
else()
|
||||||
set(MSVC_PREFIX "vc150")
|
set(MSVC_PREFIX "vc150")
|
||||||
endif()
|
endif()
|
||||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE)
|
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
|
||||||
else()
|
else()
|
||||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" FORCE)
|
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
|
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
|
||||||
if( WIN32 )
|
|
||||||
# for visual studio linking, most of the time boost dlls will be used
|
|
||||||
set( ASSIMP_CXX_FLAGS " -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB")
|
|
||||||
endif()
|
|
||||||
set( ASSIMP_LINK_FLAGS "" )
|
set( ASSIMP_LINK_FLAGS "" )
|
||||||
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
|
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
|
||||||
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
|
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
|
||||||
set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX})
|
set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX})
|
||||||
set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}@CMAKE_DEBUG_POSTFIX@)
|
set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}@CMAKE_DEBUG_POSTFIX@)
|
||||||
|
|
||||||
# search for the boost version assimp was compiled with
|
|
||||||
#set(Boost_USE_MULTITHREAD ON)
|
|
||||||
#set(Boost_USE_STATIC_LIBS OFF)
|
|
||||||
#set(Boost_USE_STATIC_RUNTIME OFF)
|
|
||||||
#find_package(Boost ${ASSIMP_Boost_VERSION} EXACT COMPONENTS thread date_time)
|
|
||||||
#if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
|
|
||||||
# set( ASSIMP_INCLUDE_DIRS "${ASSIMP_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS})
|
|
||||||
#else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
|
|
||||||
# message(WARNING "Failed to find Boost ${ASSIMP_Boost_VERSION} necessary for assimp")
|
|
||||||
#endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
|
|
||||||
|
|
||||||
# the boost version assimp was compiled with
|
|
||||||
set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@")
|
|
||||||
|
|
||||||
# for compatibility with pkg-config
|
# for compatibility with pkg-config
|
||||||
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
|
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
|
||||||
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
|
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
|
||||||
|
@ -74,7 +56,6 @@ MARK_AS_ADVANCED(
|
||||||
ASSIMP_LINK_FLAGS
|
ASSIMP_LINK_FLAGS
|
||||||
ASSIMP_INCLUDE_DIRS
|
ASSIMP_INCLUDE_DIRS
|
||||||
ASSIMP_LIBRARIES
|
ASSIMP_LIBRARIES
|
||||||
ASSIMP_Boost_VERSION
|
|
||||||
ASSIMP_CFLAGS_OTHER
|
ASSIMP_CFLAGS_OTHER
|
||||||
ASSIMP_LDFLAGS_OTHER
|
ASSIMP_LDFLAGS_OTHER
|
||||||
ASSIMP_LIBRARY_SUFFIX
|
ASSIMP_LIBRARY_SUFFIX
|
||||||
|
|
|
@ -72,7 +72,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
||||||
unsigned int idx( NotSet );
|
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;
|
std::string &s = mScene->mMaterials[i].mName;
|
||||||
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
|
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
|
||||||
*it = static_cast< char >( ::tolower( *it ) );
|
*it = static_cast< char >( ::tolower( *it ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* scene)
|
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
|
||||||
: scene(scene)
|
: scene(scene)
|
||||||
, writer(outfile)
|
, writer(outfile)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace Assimp
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
class Discreet3DSExporter {
|
class Discreet3DSExporter {
|
||||||
public:
|
public:
|
||||||
Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene);
|
Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* pScene);
|
||||||
~Discreet3DSExporter();
|
~Discreet3DSExporter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -71,7 +71,7 @@ static const aiImporterDesc desc = {
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
"3ds prj"
|
"3ds prj 3DS PRJ"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,22 +113,24 @@ Discreet3DSImporter::Discreet3DSImporter()
|
||||||
, mScene()
|
, mScene()
|
||||||
, mMasterScale()
|
, mMasterScale()
|
||||||
, bHasBG()
|
, bHasBG()
|
||||||
, bIsPrj()
|
, bIsPrj() {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
Discreet3DSImporter::~Discreet3DSImporter()
|
Discreet3DSImporter::~Discreet3DSImporter() {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||||
{
|
|
||||||
std::string extension = GetExtension(pFile);
|
std::string extension = GetExtension(pFile);
|
||||||
if(extension == "3ds" || extension == "prj" ) {
|
if(extension == "3ds" || extension == "3DS" || extension == "prj"|| extension == "PRJ" ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extension.length() || checkSig) {
|
if (!extension.length() || checkSig) {
|
||||||
uint16_t token[3];
|
uint16_t token[3];
|
||||||
token[0] = 0x4d4d;
|
token[0] = 0x4d4d;
|
||||||
|
@ -210,7 +212,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
||||||
ConvertScene(pScene);
|
ConvertScene(pScene);
|
||||||
|
|
||||||
// Generate the node graph for the scene. This is a little bit
|
// Generate the node graph for the scene. This is a little bit
|
||||||
// tricky since we'll need to split some meshes into submeshes
|
// tricky since we'll need to split some meshes into sub-meshes
|
||||||
GenerateNodeGraph(pScene);
|
GenerateNodeGraph(pScene);
|
||||||
|
|
||||||
// Now apply the master scaling factor to the scene
|
// Now apply the master scaling factor to the scene
|
||||||
|
@ -347,7 +349,7 @@ void Discreet3DSImporter::ParseObjectChunk()
|
||||||
case Discreet3DS::CHUNK_MAT_MATERIAL:
|
case Discreet3DS::CHUNK_MAT_MATERIAL:
|
||||||
|
|
||||||
// Add a new material to the list
|
// Add a new material to the list
|
||||||
mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + std::to_string(mScene->mMaterials.size()))));
|
mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + to_string(mScene->mMaterials.size()))));
|
||||||
ParseMaterialChunk();
|
ParseMaterialChunk();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,11 @@ namespace Assimp {
|
||||||
namespace D3MF {
|
namespace D3MF {
|
||||||
|
|
||||||
namespace XmlTag {
|
namespace XmlTag {
|
||||||
|
// Meta-data
|
||||||
|
static const std::string meta = "metadata";
|
||||||
|
static const std::string meta_name = "name";
|
||||||
|
|
||||||
|
// Model-data specific tags
|
||||||
static const std::string model = "model";
|
static const std::string model = "model";
|
||||||
static const std::string model_unit = "unit";
|
static const std::string model_unit = "unit";
|
||||||
static const std::string metadata = "metadata";
|
static const std::string metadata = "metadata";
|
||||||
|
@ -62,6 +67,8 @@ namespace XmlTag {
|
||||||
static const std::string v2 = "v2";
|
static const std::string v2 = "v2";
|
||||||
static const std::string v3 = "v3";
|
static const std::string v3 = "v3";
|
||||||
static const std::string id = "id";
|
static const std::string id = "id";
|
||||||
|
static const std::string pid = "pid";
|
||||||
|
static const std::string p1 = "p1";
|
||||||
static const std::string name = "name";
|
static const std::string name = "name";
|
||||||
static const std::string type = "type";
|
static const std::string type = "type";
|
||||||
static const std::string build = "build";
|
static const std::string build = "build";
|
||||||
|
@ -69,6 +76,14 @@ namespace XmlTag {
|
||||||
static const std::string objectid = "objectid";
|
static const std::string objectid = "objectid";
|
||||||
static const std::string transform = "transform";
|
static const std::string transform = "transform";
|
||||||
|
|
||||||
|
// Material definitions
|
||||||
|
static const std::string basematerials = "basematerials";
|
||||||
|
static const std::string basematerials_id = "id";
|
||||||
|
static const std::string basematerials_base = "base";
|
||||||
|
static const std::string basematerials_name = "name";
|
||||||
|
static const std::string basematerials_displaycolor = "displaycolor";
|
||||||
|
|
||||||
|
// Meta info tags
|
||||||
static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
|
static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
|
||||||
static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
|
static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
|
||||||
static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
|
static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
|
||||||
|
@ -83,7 +98,6 @@ namespace XmlTag {
|
||||||
static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
|
static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
|
||||||
static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
||||||
static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
|
static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace D3MF
|
} // Namespace D3MF
|
||||||
|
|
|
@ -156,10 +156,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
|
||||||
TextureConverted_Index = 0;
|
TextureConverted_Index = 0;
|
||||||
for(const SPP_Texture& tex_convd: mTexture_Converted)
|
for(const SPP_Texture& tex_convd: mTexture_Converted)
|
||||||
{
|
{
|
||||||
if(tex_convd.ID == TextureConverted_ID)
|
if ( tex_convd.ID == TextureConverted_ID ) {
|
||||||
return TextureConverted_Index;
|
return TextureConverted_Index;
|
||||||
else
|
} else {
|
||||||
TextureConverted_Index++;
|
++TextureConverted_Index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -583,7 +583,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
||||||
node->mTransformation = mParentAdjust*snode->mTransform;
|
node->mTransformation = mParentAdjust*snode->mTransform;
|
||||||
|
|
||||||
// Add sub nodes - prevent stack overflow due to recursive parenting
|
// Add sub nodes - prevent stack overflow due to recursive parenting
|
||||||
if (node->mName != node->mParent->mName) {
|
if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName ) {
|
||||||
AddNodes(nodes,node,node->mName.data,snode->mTransform);
|
AddNodes(nodes,node,node->mName.data,snode->mTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,9 @@ void Parser::Parse()
|
||||||
// at the file extension (ASE, ASK, ASC)
|
// at the file extension (ASE, ASK, ASC)
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
|
|
||||||
if (fmt)iFileFormat = fmt;
|
if ( fmt ) {
|
||||||
|
iFileFormat = fmt;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// main scene information
|
// main scene information
|
||||||
|
@ -427,28 +429,25 @@ void Parser::ParseLV1SoftSkinBlock()
|
||||||
// Reserve enough storage
|
// Reserve enough storage
|
||||||
vert.mBoneWeights.reserve(numWeights);
|
vert.mBoneWeights.reserve(numWeights);
|
||||||
|
|
||||||
for (unsigned int w = 0; w < numWeights;++w)
|
std::string bone;
|
||||||
{
|
for (unsigned int w = 0; w < numWeights;++w) {
|
||||||
std::string bone;
|
bone.clear();
|
||||||
ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
|
ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
|
||||||
|
|
||||||
// Find the bone in the mesh's list
|
// Find the bone in the mesh's list
|
||||||
std::pair<int,ai_real> me;
|
std::pair<int,ai_real> me;
|
||||||
me.first = -1;
|
me.first = -1;
|
||||||
|
|
||||||
for (unsigned int n = 0; n < curMesh->mBones.size();++n)
|
for (unsigned int n = 0; n < curMesh->mBones.size();++n) {
|
||||||
{
|
if (curMesh->mBones[n].mName == bone) {
|
||||||
if (curMesh->mBones[n].mName == bone)
|
|
||||||
{
|
|
||||||
me.first = n;
|
me.first = n;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-1 == me.first)
|
if (-1 == me.first) {
|
||||||
{
|
|
||||||
// We don't have this bone yet, so add it to the list
|
// We don't have this bone yet, so add it to the list
|
||||||
me.first = (int)curMesh->mBones.size();
|
me.first = static_cast<int>( curMesh->mBones.size() );
|
||||||
curMesh->mBones.push_back(ASE::Bone(bone));
|
curMesh->mBones.push_back( ASE::Bone( bone ) );
|
||||||
}
|
}
|
||||||
ParseLV4MeshFloat( me.second );
|
ParseLV4MeshFloat( me.second );
|
||||||
|
|
||||||
|
@ -745,6 +744,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
|
||||||
// empty the texture won't be used later.
|
// empty the texture won't be used later.
|
||||||
// ***********************************************************
|
// ***********************************************************
|
||||||
bool parsePath = true;
|
bool parsePath = true;
|
||||||
|
std::string temp;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if ('*' == *filePtr)
|
if ('*' == *filePtr)
|
||||||
|
@ -753,7 +753,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
|
||||||
// type of map
|
// type of map
|
||||||
if (TokenMatch(filePtr,"MAP_CLASS" ,9))
|
if (TokenMatch(filePtr,"MAP_CLASS" ,9))
|
||||||
{
|
{
|
||||||
std::string temp;
|
temp.clear();
|
||||||
if(!ParseString(temp,"*MAP_CLASS"))
|
if(!ParseString(temp,"*MAP_CLASS"))
|
||||||
SkipToNextToken();
|
SkipToNextToken();
|
||||||
if (temp != "Bitmap" && temp != "Normal Bump")
|
if (temp != "Bitmap" && temp != "Normal Bump")
|
||||||
|
|
|
@ -199,6 +199,7 @@ aiNode* BVHLoader::ReadNode()
|
||||||
Node& internNode = mNodes.back();
|
Node& internNode = mNodes.back();
|
||||||
|
|
||||||
// now read the node's contents
|
// now read the node's contents
|
||||||
|
std::string siteToken;
|
||||||
while( 1)
|
while( 1)
|
||||||
{
|
{
|
||||||
std::string token = GetNextToken();
|
std::string token = GetNextToken();
|
||||||
|
@ -218,7 +219,8 @@ aiNode* BVHLoader::ReadNode()
|
||||||
else if( token == "End")
|
else if( token == "End")
|
||||||
{
|
{
|
||||||
// The real symbol is "End Site". Second part comes in a separate token
|
// The real symbol is "End Site". Second part comes in a separate token
|
||||||
std::string siteToken = GetNextToken();
|
siteToken.clear();
|
||||||
|
siteToken = GetNextToken();
|
||||||
if( siteToken != "Site")
|
if( siteToken != "Site")
|
||||||
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
|
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
|
||||||
|
|
||||||
|
@ -262,21 +264,18 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
||||||
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
||||||
|
|
||||||
// now read the node's contents. Only possible entry is "OFFSET"
|
// now read the node's contents. Only possible entry is "OFFSET"
|
||||||
while( 1)
|
std::string token;
|
||||||
{
|
while( 1) {
|
||||||
std::string token = GetNextToken();
|
token.clear();
|
||||||
|
token = GetNextToken();
|
||||||
|
|
||||||
// end node's offset
|
// end node's offset
|
||||||
if( token == "OFFSET")
|
if( token == "OFFSET") {
|
||||||
{
|
|
||||||
ReadNodeOffset( node);
|
ReadNodeOffset( node);
|
||||||
}
|
} else if( token == "}") {
|
||||||
else if( token == "}")
|
|
||||||
{
|
|
||||||
// we're done with the end node
|
// we're done with the end node
|
||||||
break;
|
break;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// everything else is a parse error
|
// everything else is a parse error
|
||||||
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
|
||||||
}
|
}
|
||||||
|
@ -296,8 +295,10 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||||
offset.z = GetNextTokenAsFloat();
|
offset.z = GetNextTokenAsFloat();
|
||||||
|
|
||||||
// build a transformation matrix from it
|
// build a transformation matrix from it
|
||||||
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
|
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
|
||||||
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
|
0.0f, 1.0f, 0.0f, offset.y,
|
||||||
|
0.0f, 0.0f, 1.0f, offset.z,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -84,7 +84,10 @@ class BVHLoader : public BaseImporter
|
||||||
std::vector<ChannelType> mChannels;
|
std::vector<ChannelType> mChannels;
|
||||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||||
|
|
||||||
Node() { }
|
Node()
|
||||||
|
: mNode(nullptr)
|
||||||
|
{ }
|
||||||
|
|
||||||
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -115,13 +115,12 @@ void BaseImporter::SetupProperties(const Importer* /*pImp*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
|
||||||
{
|
|
||||||
const aiImporterDesc* desc = GetInfo();
|
const aiImporterDesc* desc = GetInfo();
|
||||||
ai_assert(desc != NULL);
|
ai_assert(desc != nullptr);
|
||||||
|
|
||||||
const char* ext = desc->mFileExtensions;
|
const char* ext = desc->mFileExtensions;
|
||||||
ai_assert(ext != NULL);
|
ai_assert(ext != nullptr );
|
||||||
|
|
||||||
const char* last = ext;
|
const char* last = ext;
|
||||||
do {
|
do {
|
||||||
|
@ -145,21 +144,19 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
||||||
unsigned int searchBytes /* = 200 */,
|
unsigned int searchBytes /* = 200 */,
|
||||||
bool tokensSol /* false */)
|
bool tokensSol /* false */)
|
||||||
{
|
{
|
||||||
ai_assert( NULL != tokens );
|
ai_assert( nullptr != tokens );
|
||||||
ai_assert( 0 != numTokens );
|
ai_assert( 0 != numTokens );
|
||||||
ai_assert( 0 != searchBytes);
|
ai_assert( 0 != searchBytes);
|
||||||
|
|
||||||
if (!pIOHandler)
|
if ( nullptr == pIOHandler ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||||
if (pStream.get() ) {
|
if (pStream.get() ) {
|
||||||
// read 200 characters from the file
|
// read 200 characters from the file
|
||||||
std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
||||||
char* buffer = _buffer.get();
|
char* buffer = _buffer.get();
|
||||||
if( NULL == buffer ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t read = pStream->Read(buffer,1,searchBytes);
|
const size_t read = pStream->Read(buffer,1,searchBytes);
|
||||||
if( !read ) {
|
if( !read ) {
|
||||||
|
@ -181,9 +178,17 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
||||||
}
|
}
|
||||||
*cur2 = '\0';
|
*cur2 = '\0';
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numTokens;++i) {
|
std::string token;
|
||||||
ai_assert(NULL != tokens[i]);
|
for (unsigned int i = 0; i < numTokens; ++i ) {
|
||||||
const char* r = strstr(buffer,tokens[i]);
|
ai_assert( nullptr != tokens[i] );
|
||||||
|
const size_t len( strlen( tokens[ i ] ) );
|
||||||
|
token.clear();
|
||||||
|
const char *ptr( tokens[ i ] );
|
||||||
|
for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
|
||||||
|
token.push_back( tolower( *ptr ) );
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
const char* r = strstr( buffer, token.c_str() );
|
||||||
if( !r ) {
|
if( !r ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +251,8 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
||||||
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
|
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
|
||||||
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
||||||
{
|
{
|
||||||
ai_assert(size <= 16 && _magic);
|
ai_assert( size <= 16 );
|
||||||
|
ai_assert( _magic );
|
||||||
|
|
||||||
if (!pIOHandler) {
|
if (!pIOHandler) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -58,12 +58,11 @@ using namespace Assimp::Formatter;
|
||||||
|
|
||||||
static bool match4(StreamReaderAny& stream, const char* string) {
|
static bool match4(StreamReaderAny& stream, const char* string) {
|
||||||
ai_assert( nullptr != string );
|
ai_assert( nullptr != string );
|
||||||
char tmp[] = {
|
char tmp[4];
|
||||||
(const char)(stream).GetI1(),
|
tmp[ 0 ] = ( stream ).GetI1();
|
||||||
(const char)(stream).GetI1(),
|
tmp[ 1 ] = ( stream ).GetI1();
|
||||||
(const char)(stream).GetI1(),
|
tmp[ 2 ] = ( stream ).GetI1();
|
||||||
(const char)(stream).GetI1()
|
tmp[ 3 ] = ( stream ).GetI1();
|
||||||
};
|
|
||||||
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ enum ErrorPolicy {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Represents a data structure in a BLEND file. A Structure defines n fields
|
/** Represents a data structure in a BLEND file. A Structure defines n fields
|
||||||
* and their locatios and encodings the input stream. Usually, every
|
* and their locations and encodings the input stream. Usually, every
|
||||||
* Structure instance pertains to one equally-named data structure in the
|
* Structure instance pertains to one equally-named data structure in the
|
||||||
* BlenderScene.h header. This class defines various utilities to map a
|
* BlenderScene.h header. This class defines various utilities to map a
|
||||||
* binary `blob` read from the file to such a structure instance with
|
* binary `blob` read from the file to such a structure instance with
|
||||||
|
|
|
@ -502,7 +502,7 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
|
||||||
{
|
{
|
||||||
// the file blocks appear in list sorted by
|
// the file blocks appear in list sorted by
|
||||||
// with ascending base addresses so we can run a
|
// with ascending base addresses so we can run a
|
||||||
// binary search to locate the pointee quickly.
|
// binary search to locate the pointer quickly.
|
||||||
|
|
||||||
// NOTE: Blender seems to distinguish between side-by-side
|
// NOTE: Blender seems to distinguish between side-by-side
|
||||||
// data (stored in the same data block) and far pointers,
|
// data (stored in the same data block) and far pointers,
|
||||||
|
|
|
@ -122,9 +122,11 @@ namespace Blender {
|
||||||
# pragma warning(disable:4351)
|
# pragma warning(disable:4351)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// As counter-intuitive as it may seem, a comparator must return false for equal values.
|
||||||
|
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
|
||||||
struct ObjectCompare {
|
struct ObjectCompare {
|
||||||
bool operator() (const Object* left, const Object* right) const {
|
bool operator() (const Object* left, const Object* right) const {
|
||||||
return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
|
return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,9 +145,11 @@ namespace Blender {
|
||||||
, db(db)
|
, db(db)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// As counter-intuitive as it may seem, a comparator must return false for equal values.
|
||||||
|
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
|
||||||
struct ObjectCompare {
|
struct ObjectCompare {
|
||||||
bool operator() (const Object* left, const Object* right) const {
|
bool operator() (const Object* left, const Object* right) const {
|
||||||
return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
|
return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -154,14 +154,6 @@ void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
|
||||||
// nothing to be done for the moment
|
// nothing to be done for the moment
|
||||||
}
|
}
|
||||||
|
|
||||||
struct free_it {
|
|
||||||
free_it(void* free) : free(free) {}
|
|
||||||
~free_it() {
|
|
||||||
::free(this->free);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* free;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
|
@ -169,8 +161,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
||||||
aiScene* pScene, IOSystem* pIOHandler)
|
aiScene* pScene, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||||
Bytef* dest = NULL;
|
std::vector<Bytef> uncompressed;
|
||||||
free_it free_it_really(dest);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,6 +209,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
||||||
|
|
||||||
size_t total = 0l;
|
size_t total = 0l;
|
||||||
|
|
||||||
|
// TODO: be smarter about this, decompress directly into heap buffer
|
||||||
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
|
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
|
||||||
#define MYBLOCK 1024
|
#define MYBLOCK 1024
|
||||||
Bytef block[MYBLOCK];
|
Bytef block[MYBLOCK];
|
||||||
|
@ -232,8 +224,8 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
const size_t have = MYBLOCK - zstream.avail_out;
|
const size_t have = MYBLOCK - zstream.avail_out;
|
||||||
total += have;
|
total += have;
|
||||||
dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
|
uncompressed.resize(total);
|
||||||
memcpy(dest + total - have,block,have);
|
memcpy(uncompressed.data() + total - have,block,have);
|
||||||
}
|
}
|
||||||
while (ret != Z_STREAM_END);
|
while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
|
@ -241,7 +233,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
||||||
inflateEnd(&zstream);
|
inflateEnd(&zstream);
|
||||||
|
|
||||||
// replace the input stream with a memory stream
|
// replace the input stream with a memory stream
|
||||||
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
|
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
|
||||||
|
|
||||||
// .. and retry
|
// .. and retry
|
||||||
stream->Read(magic,7,1);
|
stream->Read(magic,7,1);
|
||||||
|
|
|
@ -116,7 +116,7 @@ template <> void Structure :: Convert<MTex> (
|
||||||
ReadField<ErrorPolicy_Igno>(temp,"projy",db);
|
ReadField<ErrorPolicy_Igno>(temp,"projy",db);
|
||||||
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
|
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
|
||||||
ReadField<ErrorPolicy_Igno>(temp,"projz",db);
|
ReadField<ErrorPolicy_Igno>(temp,"projz",db);
|
||||||
dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
|
dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
|
||||||
ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
|
ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
|
||||||
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
|
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
|
||||||
ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
|
ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
|
||||||
|
|
|
@ -72,6 +72,7 @@ SET( PUBLIC_HEADERS
|
||||||
${HEADER_PATH}/matrix4x4.h
|
${HEADER_PATH}/matrix4x4.h
|
||||||
${HEADER_PATH}/matrix4x4.inl
|
${HEADER_PATH}/matrix4x4.inl
|
||||||
${HEADER_PATH}/mesh.h
|
${HEADER_PATH}/mesh.h
|
||||||
|
${HEADER_PATH}/pbrmaterial.h
|
||||||
${HEADER_PATH}/postprocess.h
|
${HEADER_PATH}/postprocess.h
|
||||||
${HEADER_PATH}/quaternion.h
|
${HEADER_PATH}/quaternion.h
|
||||||
${HEADER_PATH}/quaternion.inl
|
${HEADER_PATH}/quaternion.inl
|
||||||
|
@ -176,8 +177,6 @@ SET( Common_SRCS
|
||||||
SkeletonMeshBuilder.cpp
|
SkeletonMeshBuilder.cpp
|
||||||
SplitByBoneCountProcess.cpp
|
SplitByBoneCountProcess.cpp
|
||||||
SplitByBoneCountProcess.h
|
SplitByBoneCountProcess.h
|
||||||
ScaleProcess.cpp
|
|
||||||
ScaleProcess.h
|
|
||||||
StandardShapes.cpp
|
StandardShapes.cpp
|
||||||
TargetAnimation.cpp
|
TargetAnimation.cpp
|
||||||
TargetAnimation.h
|
TargetAnimation.h
|
||||||
|
@ -187,6 +186,8 @@ SET( Common_SRCS
|
||||||
Bitmap.cpp
|
Bitmap.cpp
|
||||||
Version.cpp
|
Version.cpp
|
||||||
CreateAnimMesh.cpp
|
CreateAnimMesh.cpp
|
||||||
|
simd.h
|
||||||
|
simd.cpp
|
||||||
)
|
)
|
||||||
SOURCE_GROUP(Common FILES ${Common_SRCS})
|
SOURCE_GROUP(Common FILES ${Common_SRCS})
|
||||||
|
|
||||||
|
@ -484,9 +485,9 @@ ADD_ASSIMP_IMPORTER( IFC
|
||||||
)
|
)
|
||||||
if (ASSIMP_BUILD_IFC_IMPORTER)
|
if (ASSIMP_BUILD_IFC_IMPORTER)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
|
set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
|
||||||
elseif(CMAKE_COMPILER_IS_MINGW)
|
elseif(CMAKE_COMPILER_IS_MINGW)
|
||||||
set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj")
|
set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj")
|
||||||
endif()
|
endif()
|
||||||
endif (ASSIMP_BUILD_IFC_IMPORTER)
|
endif (ASSIMP_BUILD_IFC_IMPORTER)
|
||||||
|
|
||||||
|
@ -522,6 +523,13 @@ ADD_ASSIMP_IMPORTER( FBX
|
||||||
FBXDeformer.cpp
|
FBXDeformer.cpp
|
||||||
FBXBinaryTokenizer.cpp
|
FBXBinaryTokenizer.cpp
|
||||||
FBXDocumentUtil.cpp
|
FBXDocumentUtil.cpp
|
||||||
|
FBXExporter.h
|
||||||
|
FBXExporter.cpp
|
||||||
|
FBXExportNode.h
|
||||||
|
FBXExportNode.cpp
|
||||||
|
FBXExportProperty.h
|
||||||
|
FBXExportProperty.cpp
|
||||||
|
FBXCommon.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET( PostProcessing_SRCS
|
SET( PostProcessing_SRCS
|
||||||
|
@ -578,6 +586,8 @@ SET( PostProcessing_SRCS
|
||||||
PolyTools.h
|
PolyTools.h
|
||||||
MakeVerboseFormat.cpp
|
MakeVerboseFormat.cpp
|
||||||
MakeVerboseFormat.h
|
MakeVerboseFormat.h
|
||||||
|
ScaleProcess.cpp
|
||||||
|
ScaleProcess.h
|
||||||
)
|
)
|
||||||
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
|
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
|
||||||
|
|
||||||
|
@ -641,7 +651,7 @@ ADD_ASSIMP_IMPORTER( X
|
||||||
XFileExporter.cpp
|
XFileExporter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_ASSIMP_IMPORTER(X3D
|
ADD_ASSIMP_IMPORTER( X3D
|
||||||
X3DExporter.cpp
|
X3DExporter.cpp
|
||||||
X3DExporter.hpp
|
X3DExporter.hpp
|
||||||
X3DImporter.cpp
|
X3DImporter.cpp
|
||||||
|
|
|
@ -47,11 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
||||||
#include "COBLoader.h"
|
#include "COBLoader.h"
|
||||||
#include "COBScene.h"
|
#include "COBScene.h"
|
||||||
|
#include "ConvertToLHProcess.h"
|
||||||
#include <assimp/StreamReader.h>
|
#include <assimp/StreamReader.h>
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
|
|
||||||
#include <assimp/LineSplitter.h>
|
#include <assimp/LineSplitter.h>
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -105,7 +104,7 @@ COBImporter::~COBImporter()
|
||||||
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);
|
const std::string& extension = GetExtension(pFile);
|
||||||
if (extension == "cob" || extension == "scn") {
|
if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +224,9 @@ void COBImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
pScene->mRootNode = BuildNodes(*root.get(),scene,pScene);
|
pScene->mRootNode = BuildNodes(*root.get(),scene,pScene);
|
||||||
|
//flip normals after import
|
||||||
|
FlipWindingOrderProcess flip;
|
||||||
|
flip.Execute( pScene );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1299,3 +1301,4 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
TextFileToBuffer(file.get(),mBuffer2);
|
TextFileToBuffer(file.get(),mBuffer2);
|
||||||
const char* buffer = &mBuffer2[0];
|
const char* buffer = &mBuffer2[0];
|
||||||
|
|
||||||
aiAnimation* anim = new aiAnimation();
|
std::unique_ptr<aiAnimation> anim(new aiAnimation());
|
||||||
int first = 0, last = 0x00ffffff;
|
int first = 0, last = 0x00ffffff;
|
||||||
|
|
||||||
// now process the file and look out for '$' sections
|
// now process the file and look out for '$' sections
|
||||||
|
@ -294,8 +294,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
||||||
|
|
||||||
// Store the one and only animation in the scene
|
// Store the one and only animation in the scene
|
||||||
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
|
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
|
||||||
pScene->mAnimations[0] = anim;
|
|
||||||
anim->mName.Set("$CSM_MasterAnim");
|
anim->mName.Set("$CSM_MasterAnim");
|
||||||
|
pScene->mAnimations[0] = anim.release();
|
||||||
|
|
||||||
// mark the scene as incomplete and run SkeletonMeshBuilder on it
|
// mark the scene as incomplete and run SkeletonMeshBuilder on it
|
||||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||||
|
|
|
@ -190,7 +190,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
||||||
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
|
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
|
||||||
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
||||||
// when t1, t2, t3 in same position in UV space, just use default UV direction.
|
// when t1, t2, t3 in same position in UV space, just use default UV direction.
|
||||||
if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
|
if ( sx * ty == sy * tx ) {
|
||||||
sx = 0.0; sy = 1.0;
|
sx = 0.0; sy = 1.0;
|
||||||
tx = 1.0; ty = 0.0;
|
tx = 1.0; ty = 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1270,6 +1270,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
||||||
mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
|
mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
|
||||||
PushTag();
|
PushTag();
|
||||||
|
|
||||||
|
std::string node_idstr;
|
||||||
for (size_t a = 0; a < anim->mNumChannels; ++a) {
|
for (size_t a = 0; a < anim->mNumChannels; ++a) {
|
||||||
const aiNodeAnim * nodeAnim = anim->mChannels[a];
|
const aiNodeAnim * nodeAnim = anim->mChannels[a];
|
||||||
|
|
||||||
|
@ -1277,7 +1278,9 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
||||||
if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
|
if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-input");
|
node_idstr.clear();
|
||||||
|
node_idstr += nodeAnim->mNodeName.data;
|
||||||
|
node_idstr += std::string( "_matrix-input" );
|
||||||
|
|
||||||
std::vector<ai_real> frames;
|
std::vector<ai_real> frames;
|
||||||
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
|
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
|
||||||
|
@ -1289,12 +1292,14 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-output");
|
node_idstr.clear();
|
||||||
|
|
||||||
|
node_idstr += nodeAnim->mNodeName.data;
|
||||||
|
node_idstr += std::string("_matrix-output");
|
||||||
|
|
||||||
std::vector<ai_real> keyframes;
|
std::vector<ai_real> keyframes;
|
||||||
keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
|
keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
|
||||||
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
|
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
|
||||||
|
|
||||||
aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
|
aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
|
||||||
aiMatrix4x4 ScalingM; // identity
|
aiMatrix4x4 ScalingM; // identity
|
||||||
ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
|
ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
|
||||||
|
@ -1361,7 +1366,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
||||||
PopTag();
|
PopTag();
|
||||||
mOutput << startstr << "</source>" << endstr;
|
mOutput << startstr << "</source>" << endstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t a = 0; a < anim->mNumChannels; ++a) {
|
for (size_t a = 0; a < anim->mNumChannels; ++a) {
|
||||||
|
|
|
@ -131,6 +131,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||||
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
|
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
|
||||||
|
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1120,6 +1121,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// now check all channels if they affect the current node
|
// 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();
|
for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
|
||||||
cit != pSrcAnim->mChannels.end(); ++cit)
|
cit != pSrcAnim->mChannels.end(); ++cit)
|
||||||
{
|
{
|
||||||
|
@ -1146,7 +1148,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
}
|
}
|
||||||
if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
|
if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
|
||||||
continue;
|
continue;
|
||||||
std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
|
|
||||||
|
targetID.clear();
|
||||||
|
targetID = srcChannel.mTarget.substr( 0, slashPos);
|
||||||
if( targetID != srcNode->mID)
|
if( targetID != srcNode->mID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1159,7 +1163,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
|
|
||||||
entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
|
entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
|
||||||
|
|
||||||
std::string subElement = srcChannel.mTarget.substr( dotPos+1);
|
subElement.clear();
|
||||||
|
subElement = srcChannel.mTarget.substr( dotPos+1);
|
||||||
if( subElement == "ANGLE")
|
if( subElement == "ANGLE")
|
||||||
entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
|
entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
|
||||||
else if( subElement == "X")
|
else if( subElement == "X")
|
||||||
|
@ -1180,7 +1185,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
if (bracketPos != std::string::npos)
|
if (bracketPos != std::string::npos)
|
||||||
{
|
{
|
||||||
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
|
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
|
||||||
std::string subElement = srcChannel.mTarget.substr(bracketPos);
|
subElement.clear();
|
||||||
|
subElement = srcChannel.mTarget.substr(bracketPos);
|
||||||
|
|
||||||
if (subElement == "(0)(0)")
|
if (subElement == "(0)(0)")
|
||||||
entry.mSubElement = 0;
|
entry.mSubElement = 0;
|
||||||
|
@ -1214,7 +1220,6 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
entry.mSubElement = 14;
|
entry.mSubElement = 14;
|
||||||
else if (subElement == "(3)(3)")
|
else if (subElement == "(3)(3)")
|
||||||
entry.mSubElement = 15;
|
entry.mSubElement = 15;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine which transform step is affected by this channel
|
// determine which transform step is affected by this channel
|
||||||
|
@ -1913,6 +1918,11 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
|
||||||
// The name must be unique for proper node-bone association.
|
// 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) {
|
||||||
|
return pNode->mName;
|
||||||
|
}
|
||||||
|
|
||||||
// Now setup the name of the assimp node. The collada name might not be
|
// Now setup the name of the assimp node. The collada name might not be
|
||||||
// unique, so we use the collada ID.
|
// unique, so we use the collada ID.
|
||||||
if (!pNode->mID.empty())
|
if (!pNode->mID.empty())
|
||||||
|
|
|
@ -248,6 +248,7 @@ protected:
|
||||||
|
|
||||||
bool noSkeletonMesh;
|
bool noSkeletonMesh;
|
||||||
bool ignoreUpDirection;
|
bool ignoreUpDirection;
|
||||||
|
bool useColladaName;
|
||||||
|
|
||||||
/** Used by FindNameForNode() to generate unique node names */
|
/** Used by FindNameForNode() to generate unique node names */
|
||||||
unsigned int mNodeNameCounter;
|
unsigned int mNodeNameCounter;
|
||||||
|
|
|
@ -222,6 +222,7 @@ void ColladaParser::ReadStructure()
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessRootAnimations();
|
PostProcessRootAnimations();
|
||||||
|
PostProcessControllers();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -360,6 +361,21 @@ void ColladaParser::ReadAnimationClipLibrary()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColladaParser::PostProcessControllers()
|
||||||
|
{
|
||||||
|
for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it)
|
||||||
|
{
|
||||||
|
std::string meshId = it->second.mMeshId;
|
||||||
|
ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
|
||||||
|
while(findItr != mControllerLibrary.end()) {
|
||||||
|
meshId = findItr->second.mMeshId;
|
||||||
|
findItr = mControllerLibrary.find(meshId);
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second.mMeshId = meshId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Re-build animations from animation clip library, if present, otherwise combine single-channel animations
|
// Re-build animations from animation clip library, if present, otherwise combine single-channel animations
|
||||||
void ColladaParser::PostProcessRootAnimations()
|
void ColladaParser::PostProcessRootAnimations()
|
||||||
|
|
|
@ -87,6 +87,9 @@ namespace Assimp
|
||||||
/** Reads the animation clip library */
|
/** Reads the animation clip library */
|
||||||
void ReadAnimationClipLibrary();
|
void ReadAnimationClipLibrary();
|
||||||
|
|
||||||
|
/** Unwrap controllers dependency hierarchy */
|
||||||
|
void PostProcessControllers();
|
||||||
|
|
||||||
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
|
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
|
||||||
void PostProcessRootAnimations();
|
void PostProcessRootAnimations();
|
||||||
|
|
||||||
|
|
|
@ -91,12 +91,14 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
|
||||||
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
||||||
|
|
||||||
// process the meshes accordingly
|
// process the meshes accordingly
|
||||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
|
||||||
ProcessMesh( pScene->mMeshes[a]);
|
ProcessMesh( pScene->mMeshes[ a ] );
|
||||||
|
}
|
||||||
|
|
||||||
// process the materials accordingly
|
// process the materials accordingly
|
||||||
for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
|
for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
|
||||||
ProcessMaterial( pScene->mMaterials[a]);
|
ProcessMaterial( pScene->mMaterials[ a ] );
|
||||||
|
}
|
||||||
|
|
||||||
// transform all animation channels as well
|
// transform all animation channels as well
|
||||||
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
||||||
|
@ -136,8 +138,11 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Converts a single mesh to left handed coordinates.
|
// Converts a single mesh to left handed coordinates.
|
||||||
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
|
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
|
||||||
{
|
if ( nullptr == pMesh ) {
|
||||||
|
DefaultLogger::get()->error( "Nullptr to mesh found." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
// mirror positions, normals and stuff along the Z axis
|
// mirror positions, normals and stuff along the Z axis
|
||||||
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
||||||
{
|
{
|
||||||
|
@ -173,8 +178,12 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Converts a single material to left handed coordinates.
|
// Converts a single material to left handed coordinates.
|
||||||
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
|
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
|
||||||
{
|
if ( nullptr == _mat ) {
|
||||||
|
DefaultLogger::get()->error( "Nullptr to aiMaterial found." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
aiMaterial* mat = (aiMaterial*)_mat;
|
aiMaterial* mat = (aiMaterial*)_mat;
|
||||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||||
aiMaterialProperty* prop = mat->mProperties[a];
|
aiMaterialProperty* prop = mat->mProperties[a];
|
||||||
|
@ -183,7 +192,6 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
|
||||||
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
||||||
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
||||||
aiVector3D* pff = (aiVector3D*)prop->mData;
|
aiVector3D* pff = (aiVector3D*)prop->mData;
|
||||||
|
|
||||||
pff->z *= -1.f;
|
pff->z *= -1.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/IOStream.hpp>
|
#include <assimp/IOStream.hpp>
|
||||||
#include <assimp/Exporter.hpp>
|
#include <assimp/Exporter.hpp>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
|
|
||||||
#include "3MFXmlTags.h"
|
#include "3MFXmlTags.h"
|
||||||
#include "D3MFOpcPackage.h"
|
#include "D3MFOpcPackage.h"
|
||||||
|
|
||||||
|
@ -116,6 +117,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
|
||||||
if ( nullptr == m_zipArchive ) {
|
if ( nullptr == m_zipArchive ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok |= exportContentTypes();
|
ok |= exportContentTypes();
|
||||||
ok |= export3DModel();
|
ok |= export3DModel();
|
||||||
ok |= exportRelations();
|
ok |= exportRelations();
|
||||||
|
@ -126,7 +128,6 @@ bool D3MFExporter::exportArchive( const char *file ) {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool D3MFExporter::exportContentTypes() {
|
bool D3MFExporter::exportContentTypes() {
|
||||||
mContentOutput.clear();
|
mContentOutput.clear();
|
||||||
|
|
||||||
|
@ -153,7 +154,11 @@ bool D3MFExporter::exportRelations() {
|
||||||
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
||||||
|
|
||||||
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
for ( size_t i = 0; i < mRelations.size(); ++i ) {
|
||||||
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
|
if ( mRelations[ i ]->target[ 0 ] == '/' ) {
|
||||||
|
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
|
||||||
|
} else {
|
||||||
|
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
|
||||||
|
}
|
||||||
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
|
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
|
||||||
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
|
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
|
||||||
mRelOutput << std::endl;
|
mRelOutput << std::endl;
|
||||||
|
@ -177,6 +182,10 @@ bool D3MFExporter::export3DModel() {
|
||||||
mModelOutput << "<" << XmlTag::resources << ">";
|
mModelOutput << "<" << XmlTag::resources << ">";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
|
|
||||||
|
writeMetaData();
|
||||||
|
|
||||||
|
writeBaseMaterials();
|
||||||
|
|
||||||
writeObjects();
|
writeObjects();
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,6 +212,63 @@ void D3MFExporter::writeHeader() {
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void D3MFExporter::writeMetaData() {
|
||||||
|
if ( nullptr == mScene->mMetaData ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
|
||||||
|
if ( 0 == numMetaEntries ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiString *key;
|
||||||
|
const aiMetadataEntry *entry(nullptr);
|
||||||
|
for ( size_t i = 0; i < numMetaEntries; ++i ) {
|
||||||
|
mScene->mMetaData->Get( i, key, entry );
|
||||||
|
std::string k( key->C_Str() );
|
||||||
|
aiString value;
|
||||||
|
mScene->mMetaData->Get( k, value );
|
||||||
|
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
|
||||||
|
mModelOutput << value.C_Str();
|
||||||
|
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3MFExporter::writeBaseMaterials() {
|
||||||
|
mModelOutput << "<basematerials id=\"1\">\n";
|
||||||
|
std::string strName, hexDiffuseColor , tmp;
|
||||||
|
for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
|
||||||
|
aiMaterial *mat = mScene->mMaterials[ i ];
|
||||||
|
aiString name;
|
||||||
|
if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
|
||||||
|
strName = "basemat_" + to_string( i );
|
||||||
|
} else {
|
||||||
|
strName = name.C_Str();
|
||||||
|
}
|
||||||
|
aiColor4D color;
|
||||||
|
if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
|
||||||
|
hexDiffuseColor.clear();
|
||||||
|
tmp.clear();
|
||||||
|
hexDiffuseColor = "#";
|
||||||
|
|
||||||
|
tmp = DecimalToHexa( color.r );
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa( color.g );
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa( color.b );
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
tmp = DecimalToHexa( color.a );
|
||||||
|
hexDiffuseColor += tmp;
|
||||||
|
} else {
|
||||||
|
hexDiffuseColor = "#FFFFFFFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
|
||||||
|
}
|
||||||
|
mModelOutput << "</basematerials>\n";
|
||||||
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeObjects() {
|
void D3MFExporter::writeObjects() {
|
||||||
if ( nullptr == mScene->mRootNode ) {
|
if ( nullptr == mScene->mRootNode ) {
|
||||||
return;
|
return;
|
||||||
|
@ -242,7 +308,9 @@ void D3MFExporter::writeMesh( aiMesh *mesh ) {
|
||||||
}
|
}
|
||||||
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
|
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
|
||||||
|
|
||||||
writeFaces( mesh );
|
const unsigned int matIdx( mesh->mMaterialIndex );
|
||||||
|
|
||||||
|
writeFaces( mesh, matIdx );
|
||||||
|
|
||||||
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
|
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +320,7 @@ void D3MFExporter::writeVertex( const aiVector3D &pos ) {
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFExporter::writeFaces( aiMesh *mesh ) {
|
void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
|
||||||
if ( nullptr == mesh ) {
|
if ( nullptr == mesh ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +332,8 @@ void D3MFExporter::writeFaces( aiMesh *mesh ) {
|
||||||
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
|
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
|
||||||
aiFace ¤tFace = mesh->mFaces[ i ];
|
aiFace ¤tFace = mesh->mFaces[ i ];
|
||||||
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
|
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
|
||||||
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] << "\"/>";
|
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
|
||||||
|
<< "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
|
||||||
mModelOutput << std::endl;
|
mModelOutput << std::endl;
|
||||||
}
|
}
|
||||||
mModelOutput << "</" << XmlTag::triangles << ">";
|
mModelOutput << "</" << XmlTag::triangles << ">";
|
||||||
|
|
|
@ -76,10 +76,12 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
|
void writeMetaData();
|
||||||
|
void writeBaseMaterials();
|
||||||
void writeObjects();
|
void writeObjects();
|
||||||
void writeMesh( aiMesh *mesh );
|
void writeMesh( aiMesh *mesh );
|
||||||
void writeVertex( const aiVector3D &pos );
|
void writeVertex( const aiVector3D &pos );
|
||||||
void writeFaces( aiMesh *mesh );
|
void writeFaces( aiMesh *mesh, unsigned int matIdx );
|
||||||
void writeBuild();
|
void writeBuild();
|
||||||
void exportContentTyp( const std::string &filename );
|
void exportContentTyp( const std::string &filename );
|
||||||
void writeModelToArchive( const std::string &folder, const std::string &modelName );
|
void writeModelToArchive( const std::string &folder, const std::string &modelName );
|
||||||
|
|
|
@ -61,14 +61,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <unzip.h>
|
#include <unzip.h>
|
||||||
#include <assimp/irrXMLWrapper.h>
|
#include <assimp/irrXMLWrapper.h>
|
||||||
#include "3MFXmlTags.h"
|
#include "3MFXmlTags.h"
|
||||||
|
#include <assimp/fast_atof.h>
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace D3MF {
|
namespace D3MF {
|
||||||
|
|
||||||
class XmlSerializer {
|
class XmlSerializer {
|
||||||
public:
|
public:
|
||||||
|
using MatArray = std::vector<aiMaterial*>;
|
||||||
|
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
|
||||||
|
|
||||||
XmlSerializer(XmlReader* xmlReader)
|
XmlSerializer(XmlReader* xmlReader)
|
||||||
: xmlReader(xmlReader) {
|
: mMeshes()
|
||||||
|
, mMatArray()
|
||||||
|
, mActiveMatGroup( 99999999 )
|
||||||
|
, mMatId2MatArray()
|
||||||
|
, xmlReader(xmlReader){
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +87,24 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportXml(aiScene* scene) {
|
void ImportXml(aiScene* scene) {
|
||||||
|
if ( nullptr == scene ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scene->mRootNode = new aiNode();
|
scene->mRootNode = new aiNode();
|
||||||
std::vector<aiNode*> children;
|
std::vector<aiNode*> children;
|
||||||
|
|
||||||
|
std::string nodeName;
|
||||||
while(ReadToEndElement(D3MF::XmlTag::model)) {
|
while(ReadToEndElement(D3MF::XmlTag::model)) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::object) {
|
nodeName = xmlReader->getNodeName();
|
||||||
|
if( nodeName == D3MF::XmlTag::object) {
|
||||||
children.push_back(ReadObject(scene));
|
children.push_back(ReadObject(scene));
|
||||||
} else if(xmlReader->getNodeName() == D3MF::XmlTag::build) {
|
} else if( nodeName == D3MF::XmlTag::build) {
|
||||||
|
//
|
||||||
|
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
|
||||||
|
ReadBaseMaterials();
|
||||||
|
} else if ( nodeName == D3MF::XmlTag::meta ) {
|
||||||
|
ReadMetadata();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,31 +112,47 @@ public:
|
||||||
scene->mRootNode->mName.Set( "3MF" );
|
scene->mRootNode->mName.Set( "3MF" );
|
||||||
}
|
}
|
||||||
|
|
||||||
scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
|
// import the metadata
|
||||||
|
if ( !mMetaData.empty() ) {
|
||||||
|
const size_t numMeta( mMetaData.size() );
|
||||||
|
scene->mMetaData = aiMetadata::Alloc( numMeta );
|
||||||
|
for ( size_t i = 0; i < numMeta; ++i ) {
|
||||||
|
aiString val( mMetaData[ i ].value );
|
||||||
|
scene->mMetaData->Set( i, mMetaData[ i ].name, val );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// import the meshes
|
||||||
|
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
|
||||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
|
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
|
||||||
|
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
|
||||||
|
|
||||||
std::copy(meshes.begin(), meshes.end(), scene->mMeshes);
|
// import the materials
|
||||||
|
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
|
||||||
|
if ( 0 != scene->mNumMaterials ) {
|
||||||
|
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
|
||||||
|
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the scenegraph
|
||||||
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
||||||
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
|
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
|
||||||
|
|
||||||
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aiNode* ReadObject(aiScene* scene)
|
aiNode* ReadObject(aiScene* scene) {
|
||||||
{
|
|
||||||
std::unique_ptr<aiNode> node(new aiNode());
|
std::unique_ptr<aiNode> node(new aiNode());
|
||||||
|
|
||||||
std::vector<unsigned long> meshIds;
|
std::vector<unsigned long> meshIds;
|
||||||
|
|
||||||
const char *attrib( nullptr );
|
const char *attrib( nullptr );
|
||||||
std::string name, type;
|
std::string name, type;
|
||||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
|
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
|
||||||
if ( nullptr != attrib ) {
|
if ( nullptr != attrib ) {
|
||||||
name = attrib;
|
name = attrib;
|
||||||
}
|
}
|
||||||
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
|
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
|
||||||
if ( nullptr != attrib ) {
|
if ( nullptr != attrib ) {
|
||||||
type = attrib;
|
type = attrib;
|
||||||
}
|
}
|
||||||
|
@ -124,19 +160,16 @@ private:
|
||||||
node->mParent = scene->mRootNode;
|
node->mParent = scene->mRootNode;
|
||||||
node->mName.Set(name);
|
node->mName.Set(name);
|
||||||
|
|
||||||
size_t meshIdx = meshes.size();
|
size_t meshIdx = mMeshes.size();
|
||||||
|
|
||||||
while(ReadToEndElement(D3MF::XmlTag::object))
|
while(ReadToEndElement(D3MF::XmlTag::object)) {
|
||||||
{
|
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
|
|
||||||
{
|
|
||||||
auto mesh = ReadMesh();
|
auto mesh = ReadMesh();
|
||||||
|
|
||||||
mesh->mName.Set(name);
|
mesh->mName.Set(name);
|
||||||
meshes.push_back(mesh);
|
mMeshes.push_back(mesh);
|
||||||
meshIds.push_back(static_cast<unsigned long>(meshIdx));
|
meshIds.push_back(static_cast<unsigned long>(meshIdx));
|
||||||
meshIdx++;
|
++meshIdx;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,19 +180,14 @@ private:
|
||||||
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
|
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
|
||||||
|
|
||||||
return node.release();
|
return node.release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aiMesh* ReadMesh() {
|
aiMesh *ReadMesh() {
|
||||||
aiMesh* mesh = new aiMesh();
|
aiMesh* mesh = new aiMesh();
|
||||||
while(ReadToEndElement(D3MF::XmlTag::mesh))
|
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
|
||||||
{
|
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
|
|
||||||
{
|
|
||||||
ImportVertices(mesh);
|
ImportVertices(mesh);
|
||||||
}
|
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
|
||||||
else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
|
|
||||||
{
|
|
||||||
ImportTriangles(mesh);
|
ImportTriangles(mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,14 +195,25 @@ private:
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportVertices(aiMesh* mesh)
|
void ReadMetadata() {
|
||||||
{
|
const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
|
||||||
std::vector<aiVector3D> vertices;
|
xmlReader->read();
|
||||||
|
const std::string value = xmlReader->getNodeData();
|
||||||
|
|
||||||
while(ReadToEndElement(D3MF::XmlTag::vertices))
|
if ( name.empty() ) {
|
||||||
{
|
return;
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex)
|
}
|
||||||
{
|
|
||||||
|
MetaEntry entry;
|
||||||
|
entry.name = name;
|
||||||
|
entry.value = value;
|
||||||
|
mMetaData.push_back( entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportVertices(aiMesh* mesh) {
|
||||||
|
std::vector<aiVector3D> vertices;
|
||||||
|
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
|
||||||
|
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
|
||||||
vertices.push_back(ReadVertex());
|
vertices.push_back(ReadVertex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,11 +221,9 @@ private:
|
||||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||||
|
|
||||||
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
|
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aiVector3D ReadVertex()
|
aiVector3D ReadVertex() {
|
||||||
{
|
|
||||||
aiVector3D vertex;
|
aiVector3D vertex;
|
||||||
|
|
||||||
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
|
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
|
||||||
|
@ -196,16 +233,18 @@ private:
|
||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportTriangles(aiMesh* mesh)
|
void ImportTriangles(aiMesh* mesh) {
|
||||||
{
|
|
||||||
std::vector<aiFace> faces;
|
std::vector<aiFace> faces;
|
||||||
|
|
||||||
|
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
|
||||||
while(ReadToEndElement(D3MF::XmlTag::triangles))
|
const std::string nodeName( xmlReader->getNodeName() );
|
||||||
{
|
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
|
||||||
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
|
|
||||||
{
|
|
||||||
faces.push_back(ReadTriangle());
|
faces.push_back(ReadTriangle());
|
||||||
|
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
|
||||||
|
if ( nullptr != pidToken ) {
|
||||||
|
int matIdx( std::atoi( pidToken ) );
|
||||||
|
mesh->mMaterialIndex = matIdx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,8 +255,7 @@ private:
|
||||||
std::copy(faces.begin(), faces.end(), mesh->mFaces);
|
std::copy(faces.begin(), faces.end(), mesh->mFaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
aiFace ReadTriangle()
|
aiFace ReadTriangle() {
|
||||||
{
|
|
||||||
aiFace face;
|
aiFace face;
|
||||||
|
|
||||||
face.mNumIndices = 3;
|
face.mNumIndices = 3;
|
||||||
|
@ -229,45 +267,150 @@ private:
|
||||||
return face;
|
return face;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void ReadBaseMaterials() {
|
||||||
bool ReadToStartElement(const std::string& startTag)
|
std::vector<unsigned int> MatIdArray;
|
||||||
{
|
const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
|
||||||
while(xmlReader->read())
|
if ( nullptr != baseMaterialId ) {
|
||||||
{
|
unsigned int id = std::atoi( baseMaterialId );
|
||||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag)
|
const size_t newMatIdx( mMatArray.size() );
|
||||||
{
|
if ( id != mActiveMatGroup ) {
|
||||||
return true;
|
mActiveMatGroup = id;
|
||||||
|
MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
|
||||||
|
if ( mMatId2MatArray.end() == it ) {
|
||||||
|
MatIdArray.clear();
|
||||||
|
mMatId2MatArray[ id ] = MatIdArray;
|
||||||
|
} else {
|
||||||
|
MatIdArray = it->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END &&
|
MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
|
||||||
xmlReader->getNodeName() == startTag)
|
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
|
||||||
{
|
}
|
||||||
|
|
||||||
|
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
|
||||||
|
mMatArray.push_back( readMaterialDef() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseColor( const char *color, aiColor4D &diffuse ) {
|
||||||
|
if ( nullptr == color ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t len( strlen( color ) );
|
||||||
|
if ( 9 != len ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *buf( color );
|
||||||
|
if ( '#' != *buf ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++buf;
|
||||||
|
char comp[ 3 ] = { 0,0,'\0' };
|
||||||
|
|
||||||
|
comp[ 0 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
comp[ 1 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
|
||||||
|
|
||||||
|
|
||||||
|
comp[ 0 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
comp[ 1 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
|
||||||
|
|
||||||
|
comp[ 0 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
comp[ 1 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
|
||||||
|
|
||||||
|
comp[ 0 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
comp[ 1 ] = *buf;
|
||||||
|
++buf;
|
||||||
|
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assignDiffuseColor( aiMaterial *mat ) {
|
||||||
|
const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
|
||||||
|
aiColor4D diffuse;
|
||||||
|
if ( parseColor( color, diffuse ) ) {
|
||||||
|
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
aiMaterial *readMaterialDef() {
|
||||||
|
aiMaterial *mat( nullptr );
|
||||||
|
const char *name( nullptr );
|
||||||
|
const std::string nodeName( xmlReader->getNodeName() );
|
||||||
|
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
|
||||||
|
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
|
||||||
|
std::string stdMatName;
|
||||||
|
aiString matName;
|
||||||
|
std::string strId( to_string( mActiveMatGroup ) );
|
||||||
|
stdMatName += "id";
|
||||||
|
stdMatName += strId;
|
||||||
|
stdMatName += "_";
|
||||||
|
if ( nullptr != name ) {
|
||||||
|
stdMatName += std::string( name );
|
||||||
|
} else {
|
||||||
|
stdMatName += "basemat";
|
||||||
|
}
|
||||||
|
matName.Set( stdMatName );
|
||||||
|
|
||||||
|
mat = new aiMaterial;
|
||||||
|
mat->AddProperty( &matName, AI_MATKEY_NAME );
|
||||||
|
|
||||||
|
assignDiffuseColor( mat );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ReadToStartElement(const std::string& startTag) {
|
||||||
|
while(xmlReader->read()) {
|
||||||
|
const std::string &nodeName( xmlReader->getNodeName() );
|
||||||
|
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
|
||||||
|
return true;
|
||||||
|
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadToEndElement(const std::string& closeTag)
|
bool ReadToEndElement(const std::string& closeTag) {
|
||||||
{
|
while(xmlReader->read()) {
|
||||||
while(xmlReader->read())
|
const std::string &nodeName( xmlReader->getNodeName() );
|
||||||
{
|
|
||||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
|
||||||
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
|
|
||||||
&& xmlReader->getNodeName() == closeTag)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
|
DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<aiMesh*> meshes;
|
struct MetaEntry {
|
||||||
|
std::string name;
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
std::vector<MetaEntry> mMetaData;
|
||||||
|
std::vector<aiMesh*> mMeshes;
|
||||||
|
MatArray mMatArray;
|
||||||
|
unsigned int mActiveMatGroup;
|
||||||
|
MatId2MatArray mMatId2MatArray;
|
||||||
XmlReader* xmlReader;
|
XmlReader* xmlReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,7 +431,6 @@ static const aiImporterDesc desc = {
|
||||||
Extension.c_str()
|
Extension.c_str()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
D3MFImporter::D3MFImporter()
|
D3MFImporter::D3MFImporter()
|
||||||
: BaseImporter() {
|
: BaseImporter() {
|
||||||
// empty
|
// empty
|
||||||
|
@ -298,14 +440,19 @@ D3MFImporter::~D3MFImporter() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension( GetExtension( filename ) );
|
||||||
if(extension == Extension ) {
|
if(extension == Extension ) {
|
||||||
return true;
|
return true;
|
||||||
} else if ( !extension.length() || checkSig ) {
|
} else if ( !extension.length() || checkSig ) {
|
||||||
if (nullptr == pIOHandler ) {
|
if ( nullptr == pIOHandler ) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
|
||||||
|
return opcPackage.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -319,8 +466,8 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
|
||||||
D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile);
|
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
|
||||||
|
|
||||||
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
|
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
|
||||||
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
|
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||||
|
|
|
@ -247,13 +247,13 @@ private:
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor.
|
// Constructor.
|
||||||
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
|
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
|
||||||
: m_ZipFileHandle(NULL)
|
: m_ZipFileHandle( nullptr )
|
||||||
, m_ArchiveMap() {
|
, m_ArchiveMap() {
|
||||||
if (! rFile.empty()) {
|
if (! rFile.empty()) {
|
||||||
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
|
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
|
||||||
|
|
||||||
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
|
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
|
||||||
if(m_ZipFileHandle != NULL) {
|
if(m_ZipFileHandle != nullptr ) {
|
||||||
mapArchive();
|
mapArchive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,32 +267,32 @@ D3MFZipArchive::~D3MFZipArchive() {
|
||||||
}
|
}
|
||||||
m_ArchiveMap.clear();
|
m_ArchiveMap.clear();
|
||||||
|
|
||||||
if(m_ZipFileHandle != NULL) {
|
if(m_ZipFileHandle != nullptr) {
|
||||||
unzClose(m_ZipFileHandle);
|
unzClose(m_ZipFileHandle);
|
||||||
m_ZipFileHandle = NULL;
|
m_ZipFileHandle = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns true, if the archive is already open.
|
// Returns true, if the archive is already open.
|
||||||
bool D3MFZipArchive::isOpen() const {
|
bool D3MFZipArchive::isOpen() const {
|
||||||
return (m_ZipFileHandle != NULL);
|
return (m_ZipFileHandle != nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns true, if the filename is part of the archive.
|
// Returns true, if the filename is part of the archive.
|
||||||
bool D3MFZipArchive::Exists(const char* pFile) const {
|
bool D3MFZipArchive::Exists(const char* pFile) const {
|
||||||
ai_assert(pFile != NULL);
|
ai_assert(pFile != nullptr );
|
||||||
|
|
||||||
bool exist = false;
|
if ( pFile == nullptr ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (pFile != NULL) {
|
std::string filename(pFile);
|
||||||
std::string rFile(pFile);
|
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
|
||||||
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
|
bool exist( false );
|
||||||
|
if(it != m_ArchiveMap.end()) {
|
||||||
if(it != m_ArchiveMap.end()) {
|
exist = true;
|
||||||
exist = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exist;
|
return exist;
|
||||||
|
@ -434,8 +434,8 @@ public:
|
||||||
|
|
||||||
std::vector<OpcPackageRelationshipPtr> m_relationShips;
|
std::vector<OpcPackageRelationshipPtr> m_relationShips;
|
||||||
};
|
};
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||||
: mRootStream(nullptr)
|
: mRootStream(nullptr)
|
||||||
, mZipArchive() {
|
, mZipArchive() {
|
||||||
|
@ -460,7 +460,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||||
if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
|
if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
|
||||||
rootFile = rootFile.substr( 1 );
|
rootFile = rootFile.substr( 1 );
|
||||||
if ( rootFile[ 0 ] == '/' ) {
|
if ( rootFile[ 0 ] == '/' ) {
|
||||||
// deal with zipbug
|
// deal with zip-bug
|
||||||
rootFile = rootFile.substr( 1 );
|
rootFile = rootFile.substr( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,18 +470,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||||
mRootStream = mZipArchive->Open(rootFile.c_str());
|
mRootStream = mZipArchive->Open(rootFile.c_str());
|
||||||
ai_assert( mRootStream != nullptr );
|
ai_assert( mRootStream != nullptr );
|
||||||
if ( nullptr == mRootStream ) {
|
if ( nullptr == mRootStream ) {
|
||||||
throw DeadlyExportError( "Cannot open rootfile in archive : " + rootFile );
|
throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
|
||||||
}
|
}
|
||||||
|
|
||||||
// const size_t size = zipArchive->FileSize();
|
|
||||||
// m_Data.resize( size );
|
|
||||||
|
|
||||||
// const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
|
|
||||||
// if ( readSize != size )
|
|
||||||
// {
|
|
||||||
// m_Data.clear();
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
mZipArchive->Close( fileStream );
|
mZipArchive->Close( fileStream );
|
||||||
|
|
||||||
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
|
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
|
||||||
|
@ -498,6 +489,25 @@ IOStream* D3MFOpcPackage::RootStream() const {
|
||||||
return mRootStream;
|
return mRootStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const std::string ModelRef = "3D/3dmodel.model";
|
||||||
|
|
||||||
|
bool D3MFOpcPackage::validate() {
|
||||||
|
if ( nullptr == mRootStream || nullptr == mZipArchive ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mZipArchive->Exists( ModelRef.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) {
|
||||||
|
D3MF::D3MFZipArchive ar( pIOHandler, rFile );
|
||||||
|
if ( !ar.isOpen() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
|
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
|
||||||
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
|
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
|
||||||
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
|
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||||
|
@ -508,14 +518,14 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
|
||||||
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
|
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(itr == reader.m_relationShips.end())
|
if ( itr == reader.m_relationShips.end() ) {
|
||||||
throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
|
throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE );
|
||||||
|
}
|
||||||
|
|
||||||
return (*itr)->target;
|
return (*itr)->target;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace D3MF
|
} // Namespace D3MF
|
||||||
|
|
||||||
} // Namespace Assimp
|
} // Namespace Assimp
|
||||||
|
|
||||||
#endif //ASSIMP_BUILD_NO_3MF_IMPORTER
|
#endif //ASSIMP_BUILD_NO_3MF_IMPORTER
|
||||||
|
|
|
@ -51,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace D3MF {
|
namespace D3MF {
|
||||||
|
|
||||||
typedef irr::io::IrrXMLReader XmlReader;
|
using XmlReader = irr::io::IrrXMLReader ;
|
||||||
typedef std::shared_ptr<XmlReader> XmlReaderPtr;
|
using XmlReaderPtr = std::shared_ptr<XmlReader> ;
|
||||||
|
|
||||||
struct OpcPackageRelationship {
|
struct OpcPackageRelationship {
|
||||||
std::string id;
|
std::string id;
|
||||||
|
@ -64,9 +64,11 @@ class D3MFZipArchive;
|
||||||
|
|
||||||
class D3MFOpcPackage {
|
class D3MFOpcPackage {
|
||||||
public:
|
public:
|
||||||
D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile);
|
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
|
||||||
~D3MFOpcPackage();
|
~D3MFOpcPackage();
|
||||||
IOStream* RootStream() const;
|
IOStream* RootStream() const;
|
||||||
|
bool validate();
|
||||||
|
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string ReadPackageRootRelationship(IOStream* stream);
|
std::string ReadPackageRootRelationship(IOStream* stream);
|
||||||
|
@ -76,7 +78,7 @@ private:
|
||||||
std::unique_ptr<D3MFZipArchive> mZipArchive;
|
std::unique_ptr<D3MFZipArchive> mZipArchive;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // Namespace D3MF
|
||||||
}
|
} // Namespace Assimp
|
||||||
|
|
||||||
#endif // D3MFOPCPACKAGE_H
|
#endif // D3MFOPCPACKAGE_H
|
||||||
|
|
|
@ -169,7 +169,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
LineSplitter splitter;
|
LineSplitter splitter;
|
||||||
int groupcode;
|
int groupcode;
|
||||||
std::string value;
|
std::string value;
|
||||||
|
|
|
@ -76,7 +76,7 @@ bool DefaultIOSystem::Exists( const char* pFile) const
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wchar_t fileName16[PATHLIMIT];
|
wchar_t fileName16[PATHLIMIT];
|
||||||
|
|
||||||
bool isUnicode = IsTextUnicode(pFile, strlen(pFile), NULL);
|
bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL);
|
||||||
if (isUnicode) {
|
if (isUnicode) {
|
||||||
|
|
||||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
|
||||||
|
@ -110,7 +110,7 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
|
||||||
FILE* file;
|
FILE* file;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wchar_t fileName16[PATHLIMIT];
|
wchar_t fileName16[PATHLIMIT];
|
||||||
bool isUnicode = IsTextUnicode(strFile, strlen(strFile), NULL );
|
bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL );
|
||||||
if (isUnicode) {
|
if (isUnicode) {
|
||||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
|
||||||
std::string mode8(strMode);
|
std::string mode8(strMode);
|
||||||
|
@ -158,7 +158,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
|
||||||
{
|
{
|
||||||
ai_assert(in && _out);
|
ai_assert(in && _out);
|
||||||
#if defined( _MSC_VER ) || defined( __MINGW32__ )
|
#if defined( _MSC_VER ) || defined( __MINGW32__ )
|
||||||
bool isUnicode = IsTextUnicode(in, strlen(in), NULL);
|
bool isUnicode = IsTextUnicode(in, static_cast<int>(strlen(in)), NULL);
|
||||||
if (isUnicode) {
|
if (isUnicode) {
|
||||||
wchar_t out16[PATHLIMIT];
|
wchar_t out16[PATHLIMIT];
|
||||||
wchar_t in16[PATHLIMIT];
|
wchar_t in16[PATHLIMIT];
|
||||||
|
|
|
@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of DefaultLogger (and Logger)
|
* @brief Implementation of DefaultLogger (and Logger)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Default log streams
|
// Default log streams
|
||||||
#include "Win32DebugLogStream.h"
|
#include "Win32DebugLogStream.h"
|
||||||
#include "StdOStreamLogStream.h"
|
#include "StdOStreamLogStream.h"
|
||||||
|
@ -62,8 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||||
# include <thread>
|
# include <thread>
|
||||||
# include <mutex>
|
# include <mutex>
|
||||||
|
std::mutex loggerMutex;
|
||||||
std::mutex loggerMutex;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
@ -76,22 +74,19 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Represents a log-stream + its error severity
|
// Represents a log-stream + its error severity
|
||||||
struct LogStreamInfo
|
struct LogStreamInfo {
|
||||||
{
|
unsigned int m_uiErrorSeverity;
|
||||||
unsigned int m_uiErrorSeverity;
|
LogStream *m_pStream;
|
||||||
LogStream *m_pStream;
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
|
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
|
||||||
m_uiErrorSeverity( uiErrorSev ),
|
m_uiErrorSeverity( uiErrorSev ),
|
||||||
m_pStream( pStream )
|
m_pStream( pStream ) {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~LogStreamInfo()
|
~LogStreamInfo() {
|
||||||
{
|
|
||||||
delete m_pStream;
|
delete m_pStream;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -109,7 +104,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
return new Win32DebugLogStream();
|
return new Win32DebugLogStream();
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Platform-independent default streams
|
// Platform-independent default streams
|
||||||
|
@ -118,7 +113,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||||
case aiDefaultLogStream_STDOUT:
|
case aiDefaultLogStream_STDOUT:
|
||||||
return new StdOStreamLogStream(std::cout);
|
return new StdOStreamLogStream(std::cout);
|
||||||
case aiDefaultLogStream_FILE:
|
case aiDefaultLogStream_FILE:
|
||||||
return (name && *name ? new FileLogStream(name,io) : NULL);
|
return (name && *name ? new FileLogStream(name,io) : nullptr );
|
||||||
default:
|
default:
|
||||||
// We don't know this default log stream, so raise an assertion
|
// We don't know this default log stream, so raise an assertion
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
|
@ -134,34 +129,38 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||||
Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
|
Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
|
||||||
LogSeverity severity /*= NORMAL*/,
|
LogSeverity severity /*= NORMAL*/,
|
||||||
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
|
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
|
||||||
IOSystem* io /*= NULL*/)
|
IOSystem* io /*= NULL*/) {
|
||||||
{
|
|
||||||
// enter the mutex here to avoid concurrency problems
|
// enter the mutex here to avoid concurrency problems
|
||||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_pLogger && !isNullLogger() )
|
if ( m_pLogger && !isNullLogger() ) {
|
||||||
delete m_pLogger;
|
delete m_pLogger;
|
||||||
|
}
|
||||||
|
|
||||||
m_pLogger = new DefaultLogger( severity );
|
m_pLogger = new DefaultLogger( severity );
|
||||||
|
|
||||||
// Attach default log streams
|
// Attach default log streams
|
||||||
// Stream the log to the MSVC debugger?
|
// Stream the log to the MSVC debugger?
|
||||||
if (defStreams & aiDefaultLogStream_DEBUGGER)
|
if ( defStreams & aiDefaultLogStream_DEBUGGER ) {
|
||||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
|
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Stream the log to COUT?
|
// Stream the log to COUT?
|
||||||
if (defStreams & aiDefaultLogStream_STDOUT)
|
if ( defStreams & aiDefaultLogStream_STDOUT ) {
|
||||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
|
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Stream the log to CERR?
|
// Stream the log to CERR?
|
||||||
if (defStreams & aiDefaultLogStream_STDERR)
|
if ( defStreams & aiDefaultLogStream_STDERR ) {
|
||||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
|
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Stream the log to a file
|
// Stream the log to a file
|
||||||
if (defStreams & aiDefaultLogStream_FILE && name && *name)
|
if ( defStreams & aiDefaultLogStream_FILE && name && *name ) {
|
||||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
|
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) );
|
||||||
|
}
|
||||||
|
|
||||||
return m_pLogger;
|
return m_pLogger;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +199,6 @@ void Logger::warn(const char* message) {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
void Logger::error(const char* message) {
|
void Logger::error(const char* message) {
|
||||||
|
|
||||||
// SECURITY FIX: see above
|
// SECURITY FIX: see above
|
||||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||||
return;
|
return;
|
||||||
|
@ -209,23 +207,24 @@ void Logger::error(const char* message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
void DefaultLogger::set( Logger *logger )
|
void DefaultLogger::set( Logger *logger ) {
|
||||||
{
|
|
||||||
// enter the mutex here to avoid concurrency problems
|
// enter the mutex here to avoid concurrency problems
|
||||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!logger)logger = &s_pNullLogger;
|
if ( nullptr == logger ) {
|
||||||
if (m_pLogger && !isNullLogger() )
|
logger = &s_pNullLogger;
|
||||||
|
}
|
||||||
|
if ( nullptr != m_pLogger && !isNullLogger() ) {
|
||||||
delete m_pLogger;
|
delete m_pLogger;
|
||||||
|
}
|
||||||
|
|
||||||
DefaultLogger::m_pLogger = logger;
|
DefaultLogger::m_pLogger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
bool DefaultLogger::isNullLogger()
|
bool DefaultLogger::isNullLogger() {
|
||||||
{
|
|
||||||
return m_pLogger == &s_pNullLogger;
|
return m_pLogger == &s_pNullLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,8 +235,7 @@ Logger *DefaultLogger::get() {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Kills the only instance
|
// Kills the only instance
|
||||||
void DefaultLogger::kill()
|
void DefaultLogger::kill() {
|
||||||
{
|
|
||||||
// enter the mutex here to avoid concurrency problems
|
// enter the mutex here to avoid concurrency problems
|
||||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||||
|
@ -252,10 +250,10 @@ void DefaultLogger::kill()
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Debug message
|
// Debug message
|
||||||
void DefaultLogger::OnDebug( const char* message )
|
void DefaultLogger::OnDebug( const char* message ) {
|
||||||
{
|
if ( m_Severity == Logger::NORMAL ) {
|
||||||
if ( m_Severity == Logger::NORMAL )
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||||
char msg[Size];
|
char msg[Size];
|
||||||
|
@ -266,8 +264,7 @@ void DefaultLogger::OnDebug( const char* message )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Logs an info
|
// Logs an info
|
||||||
void DefaultLogger::OnInfo( const char* message )
|
void DefaultLogger::OnInfo( const char* message ){
|
||||||
{
|
|
||||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||||
char msg[Size];
|
char msg[Size];
|
||||||
ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message );
|
ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message );
|
||||||
|
@ -277,8 +274,7 @@ void DefaultLogger::OnInfo( const char* message )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Logs a warning
|
// Logs a warning
|
||||||
void DefaultLogger::OnWarn( const char* message )
|
void DefaultLogger::OnWarn( const char* message ) {
|
||||||
{
|
|
||||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||||
char msg[Size];
|
char msg[Size];
|
||||||
ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message );
|
ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message );
|
||||||
|
@ -288,8 +284,7 @@ void DefaultLogger::OnWarn( const char* message )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Logs an error
|
// Logs an error
|
||||||
void DefaultLogger::OnError( const char* message )
|
void DefaultLogger::OnError( const char* message ) {
|
||||||
{
|
|
||||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||||
char msg[ Size ];
|
char msg[ Size ];
|
||||||
ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
|
ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
|
||||||
|
@ -299,10 +294,10 @@ void DefaultLogger::OnError( const char* message )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Will attach a new stream
|
// Will attach a new stream
|
||||||
bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
|
bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) {
|
||||||
{
|
if ( nullptr == pStream ) {
|
||||||
if (!pStream)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 == severity) {
|
if (0 == severity) {
|
||||||
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
||||||
|
@ -312,8 +307,7 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
|
||||||
it != m_StreamArray.end();
|
it != m_StreamArray.end();
|
||||||
++it )
|
++it )
|
||||||
{
|
{
|
||||||
if ( (*it)->m_pStream == pStream )
|
if ( (*it)->m_pStream == pStream ) {
|
||||||
{
|
|
||||||
(*it)->m_uiErrorSeverity |= severity;
|
(*it)->m_uiErrorSeverity |= severity;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -326,34 +320,31 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Detach a stream
|
// Detach a stream
|
||||||
bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
|
bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) {
|
||||||
{
|
if ( nullptr == pStream ) {
|
||||||
if (!pStream)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 == severity) {
|
if (0 == severity) {
|
||||||
severity = SeverityAll;
|
severity = SeverityAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( StreamIt it = m_StreamArray.begin();
|
bool res( false );
|
||||||
it != m_StreamArray.end();
|
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||||
++it )
|
if ( (*it)->m_pStream == pStream ) {
|
||||||
{
|
|
||||||
if ( (*it)->m_pStream == pStream )
|
|
||||||
{
|
|
||||||
(*it)->m_uiErrorSeverity &= ~severity;
|
(*it)->m_uiErrorSeverity &= ~severity;
|
||||||
if ( (*it)->m_uiErrorSeverity == 0 )
|
if ( (*it)->m_uiErrorSeverity == 0 ) {
|
||||||
{
|
|
||||||
// don't delete the underlying stream 'cause the caller gains ownership again
|
// don't delete the underlying stream 'cause the caller gains ownership again
|
||||||
(**it).m_pStream = NULL;
|
(**it).m_pStream = nullptr;
|
||||||
delete *it;
|
delete *it;
|
||||||
m_StreamArray.erase( it );
|
m_StreamArray.erase( it );
|
||||||
|
res = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
@ -361,15 +352,13 @@ bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
|
||||||
DefaultLogger::DefaultLogger(LogSeverity severity)
|
DefaultLogger::DefaultLogger(LogSeverity severity)
|
||||||
: Logger ( severity )
|
: Logger ( severity )
|
||||||
, noRepeatMsg (false)
|
, noRepeatMsg (false)
|
||||||
, lastLen( 0 )
|
, lastLen( 0 ) {
|
||||||
{
|
|
||||||
lastMsg[0] = '\0';
|
lastMsg[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Destructor
|
// Destructor
|
||||||
DefaultLogger::~DefaultLogger()
|
DefaultLogger::~DefaultLogger() {
|
||||||
{
|
|
||||||
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||||
// also frees the underlying stream, we are its owner.
|
// also frees the underlying stream, we are its owner.
|
||||||
delete *it;
|
delete *it;
|
||||||
|
@ -378,9 +367,8 @@ DefaultLogger::~DefaultLogger()
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Writes message to stream
|
// Writes message to stream
|
||||||
void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev )
|
void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) {
|
||||||
{
|
ai_assert(nullptr != message);
|
||||||
ai_assert(NULL != message);
|
|
||||||
|
|
||||||
// Check whether this is a repeated message
|
// Check whether this is a repeated message
|
||||||
if (! ::strncmp( message,lastMsg, lastLen-1))
|
if (! ::strncmp( message,lastMsg, lastLen-1))
|
||||||
|
|
|
@ -99,22 +99,22 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
||||||
uint32_t imageSize = 0;
|
std::streampos imageSize = 0;
|
||||||
std::string imagePath = path;
|
std::string imagePath = path;
|
||||||
|
|
||||||
// Test path directly
|
// Test path directly
|
||||||
std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
|
std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
|
||||||
if ((imageSize = file.tellg()) == -1u) {
|
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||||
DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
|
DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
|
||||||
|
|
||||||
// Test path in root path
|
// Test path in root path
|
||||||
imagePath = mRootPath + path;
|
imagePath = mRootPath + path;
|
||||||
file.open(imagePath, std::ios::binary | std::ios::ate);
|
file.open(imagePath, std::ios::binary | std::ios::ate);
|
||||||
if ((imageSize = file.tellg()) == -1u) {
|
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||||
// Test path basename in root path
|
// Test path basename in root path
|
||||||
imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
|
imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
|
||||||
file.open(imagePath, std::ios::binary | std::ios::ate);
|
file.open(imagePath, std::ios::binary | std::ios::ate);
|
||||||
if ((imageSize = file.tellg()) == -1u) {
|
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||||
DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
|
DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
||||||
// Add the new texture
|
// Add the new texture
|
||||||
auto pTexture = new aiTexture();
|
auto pTexture = new aiTexture();
|
||||||
pTexture->mHeight = 0; // Means that this is still compressed
|
pTexture->mHeight = 0; // Means that this is still compressed
|
||||||
pTexture->mWidth = imageSize;
|
pTexture->mWidth = static_cast<uint32_t>(imageSize);
|
||||||
pTexture->pcData = imageContent;
|
pTexture->pcData = imageContent;
|
||||||
|
|
||||||
auto extension = path.substr(path.find_last_of('.') + 1u);
|
auto extension = path.substr(path.find_last_of('.') + 1u);
|
||||||
|
|
|
@ -97,6 +97,8 @@ void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportPropert
|
||||||
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
|
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
|
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
|
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -169,6 +171,11 @@ Exporter::ExportFormatEntry gExporters[] =
|
||||||
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
|
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
|
||||||
|
Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
||||||
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
|
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
|
||||||
#endif
|
#endif
|
||||||
|
@ -301,7 +308,8 @@ bool IsVerboseFormat(const aiScene* pScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
|
||||||
|
unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
||||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||||
|
|
||||||
// when they create scenes from scratch, users will likely create them not in verbose
|
// when they create scenes from scratch, users will likely create them not in verbose
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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 FBXCommon.h
|
||||||
|
* Some useful constants and enums for dealing with FBX files.
|
||||||
|
*/
|
||||||
|
#ifndef AI_FBXCOMMON_H_INC
|
||||||
|
#define AI_FBXCOMMON_H_INC
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
|
||||||
|
namespace FBX
|
||||||
|
{
|
||||||
|
const std::string NULL_RECORD = { // 13 null bytes
|
||||||
|
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
|
||||||
|
}; // who knows why
|
||||||
|
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
|
||||||
|
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||||
|
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||||
|
|
||||||
|
// rotation order. We'll probably use EulerXYZ for everything
|
||||||
|
enum RotOrder {
|
||||||
|
RotOrder_EulerXYZ = 0,
|
||||||
|
RotOrder_EulerXZY,
|
||||||
|
RotOrder_EulerYZX,
|
||||||
|
RotOrder_EulerYXZ,
|
||||||
|
RotOrder_EulerZXY,
|
||||||
|
RotOrder_EulerZYX,
|
||||||
|
|
||||||
|
RotOrder_SphericXYZ,
|
||||||
|
|
||||||
|
RotOrder_MAX // end-of-enum sentinel
|
||||||
|
};
|
||||||
|
|
||||||
|
// transformation inheritance method. Most of the time RSrs
|
||||||
|
enum TransformInheritance {
|
||||||
|
TransformInheritance_RrSs = 0,
|
||||||
|
TransformInheritance_RSrs,
|
||||||
|
TransformInheritance_Rrs,
|
||||||
|
|
||||||
|
TransformInheritance_MAX // end-of-enum sentinel
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#endif // AI_FBXCOMMON_H_INC
|
|
@ -61,6 +61,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
@ -133,15 +135,14 @@ void Converter::ConvertRootNode() {
|
||||||
ConvertNodes( 0L, *out->mRootNode );
|
ConvertNodes( 0L, *out->mRootNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) {
|
||||||
void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform )
|
|
||||||
{
|
|
||||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" );
|
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" );
|
||||||
|
|
||||||
std::vector<aiNode*> nodes;
|
std::vector<aiNode*> nodes;
|
||||||
nodes.reserve( conns.size() );
|
nodes.reserve( conns.size() );
|
||||||
|
|
||||||
std::vector<aiNode*> nodes_chain;
|
std::vector<aiNode*> nodes_chain;
|
||||||
|
std::vector<aiNode*> post_nodes_chain;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for( const Connection* con : conns ) {
|
for( const Connection* con : conns ) {
|
||||||
|
@ -152,15 +153,16 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
|
||||||
}
|
}
|
||||||
|
|
||||||
const Object* const object = con->SourceObject();
|
const Object* const object = con->SourceObject();
|
||||||
if ( !object ) {
|
if ( nullptr == object ) {
|
||||||
FBXImporter::LogWarn( "failed to convert source object for Model link" );
|
FBXImporter::LogWarn( "failed to convert source object for Model link" );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Model* const model = dynamic_cast<const Model*>( object );
|
const Model* const model = dynamic_cast<const Model*>( object );
|
||||||
|
|
||||||
if ( model ) {
|
if ( nullptr != model ) {
|
||||||
nodes_chain.clear();
|
nodes_chain.clear();
|
||||||
|
post_nodes_chain.clear();
|
||||||
|
|
||||||
aiMatrix4x4 new_abs_transform = parent_transform;
|
aiMatrix4x4 new_abs_transform = parent_transform;
|
||||||
|
|
||||||
|
@ -168,11 +170,11 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
|
||||||
// assimp (or rather: the complicated transformation chain that
|
// assimp (or rather: the complicated transformation chain that
|
||||||
// is employed by fbx) means that we may need multiple aiNode's
|
// is employed by fbx) means that we may need multiple aiNode's
|
||||||
// to represent a fbx node's transformation.
|
// to represent a fbx node's transformation.
|
||||||
GenerateTransformationNodeChain( *model, nodes_chain );
|
GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
|
||||||
|
|
||||||
ai_assert( nodes_chain.size() );
|
ai_assert( nodes_chain.size() );
|
||||||
|
|
||||||
const std::string& original_name = FixNodeName( model->Name() );
|
std::string original_name = FixNodeName( model->Name() );
|
||||||
|
|
||||||
// check if any of the nodes in the chain has the name the fbx node
|
// check if any of the nodes in the chain has the name the fbx node
|
||||||
// is supposed to have. If there is none, add another node to
|
// is supposed to have. If there is none, add another node to
|
||||||
|
@ -187,7 +189,15 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !name_carrier ) {
|
if ( !name_carrier ) {
|
||||||
|
NodeNameCache::const_iterator it( std::find( mNodeNames.begin(), mNodeNames.end(), original_name ) );
|
||||||
|
if ( it != mNodeNames.end() ) {
|
||||||
|
original_name = original_name + std::string( "001" );
|
||||||
|
}
|
||||||
|
|
||||||
|
mNodeNames.push_back( original_name );
|
||||||
nodes_chain.push_back( new aiNode( original_name ) );
|
nodes_chain.push_back( new aiNode( original_name ) );
|
||||||
|
} else {
|
||||||
|
original_name = nodes_chain.back()->mName.C_Str();
|
||||||
}
|
}
|
||||||
|
|
||||||
//setup metadata on newest node
|
//setup metadata on newest node
|
||||||
|
@ -213,15 +223,46 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
|
||||||
// attach geometry
|
// attach geometry
|
||||||
ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
|
ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
|
||||||
|
|
||||||
// attach sub-nodes
|
// check if there will be any child nodes
|
||||||
ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform );
|
const std::vector<const Connection*>& child_conns
|
||||||
|
= doc.GetConnectionsByDestinationSequenced( model->ID(), "Model" );
|
||||||
|
|
||||||
|
// if so, link the geometric transform inverse nodes
|
||||||
|
// before we attach any child nodes
|
||||||
|
if (child_conns.size()) {
|
||||||
|
for( aiNode* postnode : post_nodes_chain ) {
|
||||||
|
ai_assert( postnode );
|
||||||
|
|
||||||
|
if ( last_parent != &parent ) {
|
||||||
|
last_parent->mNumChildren = 1;
|
||||||
|
last_parent->mChildren = new aiNode*[ 1 ];
|
||||||
|
last_parent->mChildren[ 0 ] = postnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
postnode->mParent = last_parent;
|
||||||
|
last_parent = postnode;
|
||||||
|
|
||||||
|
new_abs_transform *= postnode->mTransformation;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// free the nodes we allocated as we don't need them
|
||||||
|
Util::delete_fun<aiNode> deleter;
|
||||||
|
std::for_each(
|
||||||
|
post_nodes_chain.begin(),
|
||||||
|
post_nodes_chain.end(),
|
||||||
|
deleter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach sub-nodes (if any)
|
||||||
|
ConvertNodes( model->ID(), *last_parent, new_abs_transform );
|
||||||
|
|
||||||
if ( doc.Settings().readLights ) {
|
if ( doc.Settings().readLights ) {
|
||||||
ConvertLights( *model );
|
ConvertLights( *model, original_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( doc.Settings().readCameras ) {
|
if ( doc.Settings().readCameras ) {
|
||||||
ConvertCameras( *model );
|
ConvertCameras( *model, original_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.push_back( nodes_chain.front() );
|
nodes.push_back( nodes_chain.front() );
|
||||||
|
@ -240,38 +281,36 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
|
||||||
Util::delete_fun<aiNode> deleter;
|
Util::delete_fun<aiNode> deleter;
|
||||||
std::for_each( nodes.begin(), nodes.end(), deleter );
|
std::for_each( nodes.begin(), nodes.end(), deleter );
|
||||||
std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter );
|
std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter );
|
||||||
|
std::for_each( post_nodes_chain.begin(), post_nodes_chain.end(), deleter );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Converter::ConvertLights( const Model& model )
|
void Converter::ConvertLights( const Model& model, const std::string &orig_name ) {
|
||||||
{
|
|
||||||
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
|
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
|
||||||
for( const NodeAttribute* attr : node_attrs ) {
|
for( const NodeAttribute* attr : node_attrs ) {
|
||||||
const Light* const light = dynamic_cast<const Light*>( attr );
|
const Light* const light = dynamic_cast<const Light*>( attr );
|
||||||
if ( light ) {
|
if ( light ) {
|
||||||
ConvertLight( model, *light );
|
ConvertLight( *light, orig_name );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::ConvertCameras( const Model& model )
|
void Converter::ConvertCameras( const Model& model, const std::string &orig_name ) {
|
||||||
{
|
|
||||||
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
|
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
|
||||||
for( const NodeAttribute* attr : node_attrs ) {
|
for( const NodeAttribute* attr : node_attrs ) {
|
||||||
const Camera* const cam = dynamic_cast<const Camera*>( attr );
|
const Camera* const cam = dynamic_cast<const Camera*>( attr );
|
||||||
if ( cam ) {
|
if ( cam ) {
|
||||||
ConvertCamera( model, *cam );
|
ConvertCamera( *cam, orig_name );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::ConvertLight( const Model& model, const Light& light )
|
void Converter::ConvertLight( const Light& light, const std::string &orig_name ) {
|
||||||
{
|
|
||||||
lights.push_back( new aiLight() );
|
lights.push_back( new aiLight() );
|
||||||
aiLight* const out_light = lights.back();
|
aiLight* const out_light = lights.back();
|
||||||
|
|
||||||
out_light->mName.Set( FixNodeName( model.Name() ) );
|
out_light->mName.Set( orig_name );
|
||||||
|
|
||||||
const float intensity = light.Intensity() / 100.0f;
|
const float intensity = light.Intensity() / 100.0f;
|
||||||
const aiVector3D& col = light.Color();
|
const aiVector3D& col = light.Color();
|
||||||
|
@ -344,12 +383,12 @@ void Converter::ConvertLight( const Model& model, const Light& light )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::ConvertCamera( const Model& model, const Camera& cam )
|
void Converter::ConvertCamera( const Camera& cam, const std::string &orig_name )
|
||||||
{
|
{
|
||||||
cameras.push_back( new aiCamera() );
|
cameras.push_back( new aiCamera() );
|
||||||
aiCamera* const out_camera = cameras.back();
|
aiCamera* const out_camera = cameras.back();
|
||||||
|
|
||||||
out_camera->mName.Set( FixNodeName( model.Name() ) );
|
out_camera->mName.Set( orig_name );
|
||||||
|
|
||||||
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
||||||
|
|
||||||
|
@ -363,6 +402,31 @@ void Converter::ConvertCamera( const Model& model, const Camera& cam )
|
||||||
out_camera->mClipPlaneFar = cam.FarPlane();
|
out_camera->mClipPlaneFar = cam.FarPlane();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HasName( NodeNameCache &cache, const std::string &name ) {
|
||||||
|
NodeNameCache::const_iterator it( std::find( cache.begin(), cache.end(), name ) );
|
||||||
|
return it != cache.end();
|
||||||
|
|
||||||
|
}
|
||||||
|
void Converter::GetUniqueName( const std::string &name, std::string uniqueName ) {
|
||||||
|
if ( !HasName( mNodeNames, name ) ) {
|
||||||
|
uniqueName = name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i( 0 );
|
||||||
|
std::string newName;
|
||||||
|
while ( HasName( mNodeNames, newName ) ) {
|
||||||
|
++i;
|
||||||
|
newName.clear();
|
||||||
|
newName += name;
|
||||||
|
std::stringstream ext;
|
||||||
|
ext << std::setfill( '0' ) << std::setw( 3 ) << i;
|
||||||
|
newName += ext.str();
|
||||||
|
}
|
||||||
|
uniqueName = newName;
|
||||||
|
mNodeNames.push_back( uniqueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* Converter::NameTransformationComp( TransformationComp comp )
|
const char* Converter::NameTransformationComp( TransformationComp comp )
|
||||||
{
|
{
|
||||||
|
@ -396,6 +460,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
|
||||||
return "GeometricRotation";
|
return "GeometricRotation";
|
||||||
case TransformationComp_GeometricTranslation:
|
case TransformationComp_GeometricTranslation:
|
||||||
return "GeometricTranslation";
|
return "GeometricTranslation";
|
||||||
|
case TransformationComp_GeometricScalingInverse:
|
||||||
|
return "GeometricScalingInverse";
|
||||||
|
case TransformationComp_GeometricRotationInverse:
|
||||||
|
return "GeometricRotationInverse";
|
||||||
|
case TransformationComp_GeometricTranslationInverse:
|
||||||
|
return "GeometricTranslationInverse";
|
||||||
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
|
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -437,6 +507,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
|
||||||
return "GeometricRotation";
|
return "GeometricRotation";
|
||||||
case TransformationComp_GeometricTranslation:
|
case TransformationComp_GeometricTranslation:
|
||||||
return "GeometricTranslation";
|
return "GeometricTranslation";
|
||||||
|
case TransformationComp_GeometricScalingInverse:
|
||||||
|
return "GeometricScalingInverse";
|
||||||
|
case TransformationComp_GeometricRotationInverse:
|
||||||
|
return "GeometricRotationInverse";
|
||||||
|
case TransformationComp_GeometricTranslationInverse:
|
||||||
|
return "GeometricTranslationInverse";
|
||||||
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
|
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -548,17 +624,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
const float zero_epsilon = 1e-6f;
|
const float zero_epsilon = 1e-6f;
|
||||||
|
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||||
for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
|
for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
|
||||||
const TransformationComp comp = static_cast< TransformationComp >( i );
|
const TransformationComp comp = static_cast< TransformationComp >( i );
|
||||||
|
|
||||||
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
|
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
|
||||||
comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
|
||||||
|
|
||||||
const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
|
const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
|
||||||
if ( ok && v.SquareLength() > zero_epsilon ) {
|
if ( ok && scale_compare ) {
|
||||||
return true;
|
if ( (v - all_ones).SquareLength() > zero_epsilon ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if ( ok ) {
|
||||||
|
if ( v.SquareLength() > zero_epsilon ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +654,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
|
||||||
return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
|
return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes )
|
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
|
||||||
{
|
{
|
||||||
const PropertyTable& props = model.Props();
|
const PropertyTable& props = model.Props();
|
||||||
const Model::RotOrder rot = model.RotationOrder();
|
const Model::RotOrder rot = model.RotationOrder();
|
||||||
|
@ -582,20 +666,21 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
|
|
||||||
// generate transformation matrices for all the different transformation components
|
// generate transformation matrices for all the different transformation components
|
||||||
const float zero_epsilon = 1e-6f;
|
const float zero_epsilon = 1e-6f;
|
||||||
|
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||||
bool is_complex = false;
|
bool is_complex = false;
|
||||||
|
|
||||||
const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
|
const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
|
||||||
if ( ok && PreRotation.SquareLength() > zero_epsilon ) {
|
if ( ok && PreRotation.SquareLength() > zero_epsilon ) {
|
||||||
is_complex = true;
|
is_complex = true;
|
||||||
|
|
||||||
GetRotationMatrix( rot, PreRotation, chain[ TransformationComp_PreRotation ] );
|
GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[ TransformationComp_PreRotation ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok );
|
const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok );
|
||||||
if ( ok && PostRotation.SquareLength() > zero_epsilon ) {
|
if ( ok && PostRotation.SquareLength() > zero_epsilon ) {
|
||||||
is_complex = true;
|
is_complex = true;
|
||||||
|
|
||||||
GetRotationMatrix( rot, PostRotation, chain[ TransformationComp_PostRotation ] );
|
GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[ TransformationComp_PostRotation ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok );
|
const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok );
|
||||||
|
@ -634,7 +719,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
|
const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
|
||||||
if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) {
|
if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
|
||||||
aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
|
aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,18 +729,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
|
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
|
||||||
if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) {
|
if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
|
||||||
|
is_complex = true;
|
||||||
aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
|
aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
|
||||||
|
aiVector3D GeometricScalingInverse = GeometricScaling;
|
||||||
|
bool canscale = true;
|
||||||
|
for (unsigned int i = 0; i < 3; ++i) {
|
||||||
|
if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
|
||||||
|
GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
|
||||||
|
} else {
|
||||||
|
FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
|
||||||
|
canscale = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canscale) {
|
||||||
|
aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
|
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
|
||||||
if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
|
if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
|
||||||
|
is_complex = true;
|
||||||
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
|
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
|
||||||
|
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
|
||||||
|
chain[ TransformationComp_GeometricRotationInverse ].Inverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
|
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
|
||||||
if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
|
if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
|
||||||
|
is_complex = true;
|
||||||
aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
|
aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
|
||||||
|
aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_complex needs to be consistent with NeedsComplexTransformationChain()
|
// is_complex needs to be consistent with NeedsComplexTransformationChain()
|
||||||
|
@ -663,7 +768,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
// not be guaranteed.
|
// not be guaranteed.
|
||||||
ai_assert( NeedsComplexTransformationChain( model ) == is_complex );
|
ai_assert( NeedsComplexTransformationChain( model ) == is_complex );
|
||||||
|
|
||||||
const std::string& name = FixNodeName( model.Name() );
|
std::string name = FixNodeName( model.Name() );
|
||||||
|
|
||||||
// now, if we have more than just Translation, Scaling and Rotation,
|
// now, if we have more than just Translation, Scaling and Rotation,
|
||||||
// we need to generate a full node chain to accommodate for assimp's
|
// we need to generate a full node chain to accommodate for assimp's
|
||||||
|
@ -690,10 +795,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
}
|
}
|
||||||
|
|
||||||
aiNode* nd = new aiNode();
|
aiNode* nd = new aiNode();
|
||||||
output_nodes.push_back( nd );
|
|
||||||
|
|
||||||
nd->mName.Set( NameTransformationChainNode( name, comp ) );
|
nd->mName.Set( NameTransformationChainNode( name, comp ) );
|
||||||
nd->mTransformation = chain[ i ];
|
nd->mTransformation = chain[ i ];
|
||||||
|
|
||||||
|
// geometric inverses go in a post-node chain
|
||||||
|
if ( comp == TransformationComp_GeometricScalingInverse ||
|
||||||
|
comp == TransformationComp_GeometricRotationInverse ||
|
||||||
|
comp == TransformationComp_GeometricTranslationInverse
|
||||||
|
) {
|
||||||
|
post_output_nodes.push_back( nd );
|
||||||
|
} else {
|
||||||
|
output_nodes.push_back( nd );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_assert( output_nodes.size() );
|
ai_assert( output_nodes.size() );
|
||||||
|
@ -703,8 +816,10 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
|
||||||
// else, we can just multiply the matrices together
|
// else, we can just multiply the matrices together
|
||||||
aiNode* nd = new aiNode();
|
aiNode* nd = new aiNode();
|
||||||
output_nodes.push_back( nd );
|
output_nodes.push_back( nd );
|
||||||
|
std::string uniqueName;
|
||||||
|
GetUniqueName( name, uniqueName );
|
||||||
|
|
||||||
nd->mName.Set( name );
|
nd->mName.Set( uniqueName );
|
||||||
|
|
||||||
for (const auto &transform : chain) {
|
for (const auto &transform : chain) {
|
||||||
nd->mTransformation = nd->mTransformation * transform;
|
nd->mTransformation = nd->mTransformation * transform;
|
||||||
|
@ -1559,9 +1674,8 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
|
void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
|
||||||
const std::string& propName,
|
const std::string& propName,
|
||||||
aiTextureType target, const MeshGeometry* const mesh )
|
aiTextureType target, const MeshGeometry* const mesh ) {
|
||||||
{
|
|
||||||
LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
|
LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
|
||||||
if ( it == layeredTextures.end() ) {
|
if ( it == layeredTextures.end() ) {
|
||||||
return;
|
return;
|
||||||
|
@ -1805,11 +1919,11 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
|
||||||
|
|
||||||
// TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
|
// TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
|
||||||
const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
|
const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
|
||||||
float CalculatedOpacity = 1.0;
|
float CalculatedOpacity = 1.0f;
|
||||||
if ( ok ) {
|
if ( ok ) {
|
||||||
out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
|
out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
|
||||||
// as calculated by FBX SDK 2017:
|
// as calculated by FBX SDK 2017:
|
||||||
CalculatedOpacity = 1.0 - ((Transparent.r + Transparent.g + Transparent.b) / 3.0);
|
CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// use of TransparencyFactor is inconsistent.
|
// use of TransparencyFactor is inconsistent.
|
||||||
|
@ -1923,81 +2037,17 @@ void Converter::ConvertAnimations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name ) {
|
std::string Converter::FixNodeName( const std::string& name ) {
|
||||||
if ( node_names.find( fixed_name ) == node_names.end() ) {
|
|
||||||
FBXImporter::LogError( "Cannot rename node " + fixed_name + ", not existing.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( node_names.find( new_name ) != node_names.end() ) {
|
|
||||||
FBXImporter::LogError( "Cannot rename node " + fixed_name + " to " + new_name +", name already existing." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ai_assert( node_names.find( fixed_name ) != node_names.end() );
|
|
||||||
ai_assert( node_names.find( new_name ) == node_names.end() );
|
|
||||||
|
|
||||||
renamed_nodes[ fixed_name ] = new_name;
|
|
||||||
|
|
||||||
const aiString fn( fixed_name );
|
|
||||||
|
|
||||||
for( aiCamera* cam : cameras ) {
|
|
||||||
if ( cam->mName == fn ) {
|
|
||||||
cam->mName.Set( new_name );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( aiLight* light : lights ) {
|
|
||||||
if ( light->mName == fn ) {
|
|
||||||
light->mName.Set( new_name );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( aiAnimation* anim : animations ) {
|
|
||||||
for ( unsigned int i = 0; i < anim->mNumChannels; ++i ) {
|
|
||||||
aiNodeAnim* const na = anim->mChannels[ i ];
|
|
||||||
if ( na->mNodeName == fn ) {
|
|
||||||
na->mNodeName.Set( new_name );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string Converter::FixNodeName( const std::string& name )
|
|
||||||
{
|
|
||||||
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
|
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
|
||||||
// this causes ambiguities, well possible between empty identifiers,
|
// this causes ambiguities, well possible between empty identifiers,
|
||||||
// such as "Model::" and ""). Make sure the behaviour is consistent
|
// such as "Model::" and ""). Make sure the behaviour is consistent
|
||||||
// across multiple calls to FixNodeName().
|
// across multiple calls to FixNodeName().
|
||||||
if ( name.substr( 0, 7 ) == "Model::" ) {
|
if ( name.substr( 0, 7 ) == "Model::" ) {
|
||||||
std::string temp = name.substr( 7 );
|
std::string temp = name.substr( 7 );
|
||||||
|
return temp;
|
||||||
const NodeNameMap::const_iterator it = node_names.find( temp );
|
|
||||||
if ( it != node_names.end() ) {
|
|
||||||
if ( !( *it ).second ) {
|
|
||||||
return FixNodeName( name + "_" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node_names[ temp ] = true;
|
|
||||||
|
|
||||||
const NameNameMap::const_iterator rit = renamed_nodes.find( temp );
|
|
||||||
return rit == renamed_nodes.end() ? temp : ( *rit ).second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeNameMap::const_iterator it = node_names.find( name );
|
return name;
|
||||||
if ( it != node_names.end() ) {
|
|
||||||
if ( ( *it ).second ) {
|
|
||||||
return FixNodeName( name + "_" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node_names[ name ] = false;
|
|
||||||
|
|
||||||
const NameNameMap::const_iterator rit = renamed_nodes.find( name );
|
|
||||||
return rit == renamed_nodes.end() ? name : ( *rit ).second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Converter::ConvertAnimationStack( const AnimationStack& st )
|
void Converter::ConvertAnimationStack( const AnimationStack& st )
|
||||||
|
@ -2209,8 +2259,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
|
||||||
|
|
||||||
has_any = true;
|
has_any = true;
|
||||||
|
|
||||||
if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation &&
|
if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation )
|
||||||
comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
|
|
||||||
{
|
{
|
||||||
has_complex = true;
|
has_complex = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ namespace FBX {
|
||||||
|
|
||||||
class Document;
|
class Document;
|
||||||
|
|
||||||
|
using NodeNameCache = std::vector<std::string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a FBX #Document to #aiScene
|
* Convert a FBX #Document to #aiScene
|
||||||
* @param out Empty scene to be populated
|
* @param out Empty scene to be populated
|
||||||
|
@ -82,7 +84,10 @@ public:
|
||||||
* The different parts that make up the final local transformation of a fbx-node
|
* The different parts that make up the final local transformation of a fbx-node
|
||||||
*/
|
*/
|
||||||
enum TransformationComp {
|
enum TransformationComp {
|
||||||
TransformationComp_Translation = 0,
|
TransformationComp_GeometricScalingInverse = 0,
|
||||||
|
TransformationComp_GeometricRotationInverse,
|
||||||
|
TransformationComp_GeometricTranslationInverse,
|
||||||
|
TransformationComp_Translation,
|
||||||
TransformationComp_RotationOffset,
|
TransformationComp_RotationOffset,
|
||||||
TransformationComp_RotationPivot,
|
TransformationComp_RotationPivot,
|
||||||
TransformationComp_PreRotation,
|
TransformationComp_PreRotation,
|
||||||
|
@ -114,16 +119,19 @@ private:
|
||||||
void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4());
|
void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4());
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertLights(const Model& model);
|
void ConvertLights(const Model& model, const std::string &orig_name );
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertCameras(const Model& model);
|
void ConvertCameras(const Model& model, const std::string &orig_name );
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertLight(const Model& model, const Light& light);
|
void ConvertLight( const Light& light, const std::string &orig_name );
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertCamera(const Model& model, const Camera& cam);
|
void ConvertCamera( const Camera& cam, const std::string &orig_name );
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void GetUniqueName( const std::string &name, std::string uniqueName );
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// this returns unified names usable within assimp identifiers (i.e. no space characters -
|
// this returns unified names usable within assimp identifiers (i.e. no space characters -
|
||||||
|
@ -153,7 +161,7 @@ private:
|
||||||
/**
|
/**
|
||||||
* note: memory for output_nodes will be managed by the caller
|
* note: memory for output_nodes will be managed by the caller
|
||||||
*/
|
*/
|
||||||
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes);
|
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
||||||
|
@ -255,18 +263,6 @@ private:
|
||||||
// convert animation data to aiAnimation et al
|
// convert animation data to aiAnimation et al
|
||||||
void ConvertAnimations();
|
void ConvertAnimations();
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// rename a node already partially converted. fixed_name is a string previously returned by
|
|
||||||
// FixNodeName, new_name specifies the string FixNodeName should return on all further invocations
|
|
||||||
// which would previously have returned the old value.
|
|
||||||
//
|
|
||||||
// this also updates names in node animations, cameras and light sources and is thus slow.
|
|
||||||
//
|
|
||||||
// NOTE: the caller is responsible for ensuring that the new name is unique and does
|
|
||||||
// not collide with any other identifiers. The best way to ensure this is to only
|
|
||||||
// append to the old name, which is guaranteed to match these requirements.
|
|
||||||
void RenameNode(const std::string& fixed_name, const std::string& new_name);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// takes a fbx node name and returns the identifier to be used in the assimp output scene.
|
// takes a fbx node name and returns the identifier to be used in the assimp output scene.
|
||||||
// the function is guaranteed to provide consistent results over multiple invocations
|
// the function is guaranteed to provide consistent results over multiple invocations
|
||||||
|
@ -278,7 +274,6 @@ private:
|
||||||
// XXX: better use multi_map ..
|
// XXX: better use multi_map ..
|
||||||
typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
|
typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertAnimationStack(const AnimationStack& st);
|
void ConvertAnimationStack(const AnimationStack& st);
|
||||||
|
|
||||||
|
@ -429,13 +424,7 @@ private:
|
||||||
typedef std::map<std::string, unsigned int> NodeAnimBitMap;
|
typedef std::map<std::string, unsigned int> NodeAnimBitMap;
|
||||||
NodeAnimBitMap node_anim_chain_bits;
|
NodeAnimBitMap node_anim_chain_bits;
|
||||||
|
|
||||||
// name -> has had its prefix_stripped?
|
NodeNameCache mNodeNames;
|
||||||
typedef std::map<std::string, bool> NodeNameMap;
|
|
||||||
NodeNameMap node_names;
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> NameNameMap;
|
|
||||||
NameNameMap renamed_nodes;
|
|
||||||
|
|
||||||
double anim_fps;
|
double anim_fps;
|
||||||
|
|
||||||
aiScene* const out;
|
aiScene* const out;
|
||||||
|
|
|
@ -351,7 +351,9 @@ void Document::ReadGlobalSettings()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true);
|
std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
|
||||||
|
|
||||||
|
//double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 );
|
||||||
|
|
||||||
if(!props) {
|
if(!props) {
|
||||||
DOMError("GlobalSettings dictionary contains no property table");
|
DOMError("GlobalSettings dictionary contains no property table");
|
||||||
|
|
|
@ -1022,8 +1022,8 @@ public:
|
||||||
fbx_simple_property(CoordAxisSign, int, 1)
|
fbx_simple_property(CoordAxisSign, int, 1)
|
||||||
fbx_simple_property(OriginalUpAxis, int, 0)
|
fbx_simple_property(OriginalUpAxis, int, 0)
|
||||||
fbx_simple_property(OriginalUpAxisSign, int, 1)
|
fbx_simple_property(OriginalUpAxisSign, int, 1)
|
||||||
fbx_simple_property(UnitScaleFactor, double, 1)
|
fbx_simple_property(UnitScaleFactor, float, 1)
|
||||||
fbx_simple_property(OriginalUnitScaleFactor, double, 1)
|
fbx_simple_property(OriginalUnitScaleFactor, float, 1)
|
||||||
fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0))
|
fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0))
|
||||||
fbx_simple_property(DefaultCamera, std::string, "")
|
fbx_simple_property(DefaultCamera, std::string, "")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,568 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#include "FBXExportNode.h"
|
||||||
|
#include "FBXCommon.h"
|
||||||
|
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
|
#include <assimp/StringUtils.h> // ai_snprintf
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
#include <sstream> // ostringstream
|
||||||
|
#include <memory> // shared_ptr
|
||||||
|
|
||||||
|
// AddP70<type> helpers... there's no usable pattern here,
|
||||||
|
// so all are defined as separate functions.
|
||||||
|
// Even "animatable" properties are often completely different
|
||||||
|
// from the standard (nonanimated) property definition,
|
||||||
|
// so they are specified with an 'A' suffix.
|
||||||
|
|
||||||
|
void FBX::Node::AddP70int(
|
||||||
|
const std::string& name, int32_t value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "int", "Integer", "", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70bool(
|
||||||
|
const std::string& name, bool value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "bool", "", "", int32_t(value));
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70double(
|
||||||
|
const std::string& name, double value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "double", "Number", "", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70numberA(
|
||||||
|
const std::string& name, double value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "Number", "", "A", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70color(
|
||||||
|
const std::string& name, double r, double g, double b
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "ColorRGB", "Color", "", r, g, b);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70colorA(
|
||||||
|
const std::string& name, double r, double g, double b
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "Color", "", "A", r, g, b);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70vector(
|
||||||
|
const std::string& name, double x, double y, double z
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "Vector3D", "Vector", "", x, y, z);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70vectorA(
|
||||||
|
const std::string& name, double x, double y, double z
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "Vector", "", "A", x, y, z);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70string(
|
||||||
|
const std::string& name, const std::string& value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "KString", "", "", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70enum(
|
||||||
|
const std::string& name, int32_t value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "enum", "", "", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::AddP70time(
|
||||||
|
const std::string& name, int64_t value
|
||||||
|
) {
|
||||||
|
FBX::Node n("P");
|
||||||
|
n.AddProperties(name, "KTime", "Time", "", value);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public member functions for writing nodes to stream
|
||||||
|
|
||||||
|
void FBX::Node::Dump(
|
||||||
|
std::shared_ptr<Assimp::IOStream> outfile,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
Assimp::StreamWriterLE outstream(outfile);
|
||||||
|
DumpBinary(outstream);
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
DumpAscii(ss, indent);
|
||||||
|
std::string s = ss.str();
|
||||||
|
outfile->Write(s.c_str(), s.size(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::Dump(
|
||||||
|
Assimp::StreamWriterLE &outstream,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
DumpBinary(outstream);
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
DumpAscii(ss, indent);
|
||||||
|
outstream.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public member functions for low-level writing
|
||||||
|
|
||||||
|
void FBX::Node::Begin(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
BeginBinary(s);
|
||||||
|
} else {
|
||||||
|
// assume we're at the correct place to start already
|
||||||
|
(void)indent;
|
||||||
|
std::ostringstream ss;
|
||||||
|
BeginAscii(ss, indent);
|
||||||
|
s.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpProperties(
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
DumpPropertiesBinary(s);
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
DumpPropertiesAscii(ss, indent);
|
||||||
|
s.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::EndProperties(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
EndProperties(s, binary, indent, properties.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::EndProperties(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool binary, int indent,
|
||||||
|
size_t num_properties
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
EndPropertiesBinary(s, num_properties);
|
||||||
|
} else {
|
||||||
|
// nothing to do
|
||||||
|
(void)indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::BeginChildren(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
// nothing to do
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
BeginChildrenAscii(ss, indent);
|
||||||
|
s.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpChildren(
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
DumpChildrenBinary(s);
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
DumpChildrenAscii(ss, indent);
|
||||||
|
s.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::End(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool binary, int indent,
|
||||||
|
bool has_children
|
||||||
|
) {
|
||||||
|
if (binary) {
|
||||||
|
EndBinary(s, has_children);
|
||||||
|
} else {
|
||||||
|
std::ostringstream ss;
|
||||||
|
EndAscii(ss, indent, has_children);
|
||||||
|
s.PutString(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public member functions for writing to binary fbx
|
||||||
|
|
||||||
|
void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s)
|
||||||
|
{
|
||||||
|
// write header section (with placeholders for some things)
|
||||||
|
BeginBinary(s);
|
||||||
|
|
||||||
|
// write properties
|
||||||
|
DumpPropertiesBinary(s);
|
||||||
|
|
||||||
|
// go back and fill in property related placeholders
|
||||||
|
EndPropertiesBinary(s, properties.size());
|
||||||
|
|
||||||
|
// write children
|
||||||
|
DumpChildrenBinary(s);
|
||||||
|
|
||||||
|
// finish, filling in end offset placeholder
|
||||||
|
EndBinary(s, force_has_children || !children.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public member functions for writing to ascii fbx
|
||||||
|
|
||||||
|
void FBX::Node::DumpAscii(std::ostream &s, int indent)
|
||||||
|
{
|
||||||
|
// write name
|
||||||
|
BeginAscii(s, indent);
|
||||||
|
|
||||||
|
// write properties
|
||||||
|
DumpPropertiesAscii(s, indent);
|
||||||
|
|
||||||
|
if (force_has_children || !children.empty()) {
|
||||||
|
// begin children (with a '{')
|
||||||
|
BeginChildrenAscii(s, indent + 1);
|
||||||
|
// write children
|
||||||
|
DumpChildrenAscii(s, indent + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish (also closing the children bracket '}')
|
||||||
|
EndAscii(s, indent, force_has_children || !children.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private member functions for low-level writing to fbx
|
||||||
|
|
||||||
|
void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
|
||||||
|
{
|
||||||
|
// remember start pos so we can come back and write the end pos
|
||||||
|
this->start_pos = s.Tell();
|
||||||
|
|
||||||
|
// placeholders for end pos and property section info
|
||||||
|
s.PutU4(0); // end pos
|
||||||
|
s.PutU4(0); // number of properties
|
||||||
|
s.PutU4(0); // total property section length
|
||||||
|
|
||||||
|
// node name
|
||||||
|
s.PutU1(uint8_t(name.size())); // length of node name
|
||||||
|
s.PutString(name); // node name as raw bytes
|
||||||
|
|
||||||
|
// property data comes after here
|
||||||
|
this->property_start = s.Tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s)
|
||||||
|
{
|
||||||
|
for (auto &p : properties) {
|
||||||
|
p.DumpBinary(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::EndPropertiesBinary(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
size_t num_properties
|
||||||
|
) {
|
||||||
|
if (num_properties == 0) { return; }
|
||||||
|
size_t pos = s.Tell();
|
||||||
|
ai_assert(pos > property_start);
|
||||||
|
size_t property_section_size = pos - property_start;
|
||||||
|
s.Seek(start_pos + 4);
|
||||||
|
s.PutU4(uint32_t(num_properties));
|
||||||
|
s.PutU4(uint32_t(property_section_size));
|
||||||
|
s.Seek(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s)
|
||||||
|
{
|
||||||
|
for (FBX::Node& child : children) {
|
||||||
|
child.DumpBinary(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::EndBinary(
|
||||||
|
Assimp::StreamWriterLE &s,
|
||||||
|
bool has_children
|
||||||
|
) {
|
||||||
|
// if there were children, add a null record
|
||||||
|
if (has_children) { s.PutString(FBX::NULL_RECORD); }
|
||||||
|
|
||||||
|
// now go back and write initial pos
|
||||||
|
this->end_pos = s.Tell();
|
||||||
|
s.Seek(start_pos);
|
||||||
|
s.PutU4(uint32_t(end_pos));
|
||||||
|
s.Seek(end_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FBX::Node::BeginAscii(std::ostream& s, int indent)
|
||||||
|
{
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << name << ": ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < properties.size(); ++i) {
|
||||||
|
if (i > 0) { s << ", "; }
|
||||||
|
properties[i].DumpAscii(s, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent)
|
||||||
|
{
|
||||||
|
// only call this if there are actually children
|
||||||
|
s << " {";
|
||||||
|
(void)indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent)
|
||||||
|
{
|
||||||
|
// children will need a lot of padding and corralling
|
||||||
|
if (children.size() || force_has_children) {
|
||||||
|
for (size_t i = 0; i < children.size(); ++i) {
|
||||||
|
// no compression in ascii files, so skip this node if it exists
|
||||||
|
if (children[i].name == "EncryptionType") { continue; }
|
||||||
|
// the child can dump itself
|
||||||
|
children[i].DumpAscii(s, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
|
||||||
|
{
|
||||||
|
if (!has_children) { return; } // nothing to do
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// private helpers for static member functions
|
||||||
|
|
||||||
|
// ascii property node from vector of doubles
|
||||||
|
void FBX::Node::WritePropertyNodeAscii(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
int indent
|
||||||
|
){
|
||||||
|
char buffer[32];
|
||||||
|
FBX::Node node(name);
|
||||||
|
node.Begin(s, false, indent);
|
||||||
|
std::string vsize = std::to_string(v.size());
|
||||||
|
// *<size> {
|
||||||
|
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
|
||||||
|
// indent + 1
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
|
||||||
|
// a: value,value,value,...
|
||||||
|
s.PutString("a: ");
|
||||||
|
int count = 0;
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
|
if (i > 0) { s.PutChar(','); }
|
||||||
|
int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]);
|
||||||
|
count += len;
|
||||||
|
if (count > 2048) { s.PutChar('\n'); count = 0; }
|
||||||
|
if (len < 0 || len > 31) {
|
||||||
|
// this should never happen
|
||||||
|
throw DeadlyExportError("failed to convert double to string");
|
||||||
|
}
|
||||||
|
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
s.PutChar('\n');
|
||||||
|
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
|
||||||
|
s.PutChar('}'); s.PutChar(' ');
|
||||||
|
node.End(s, false, indent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ascii property node from vector of int32_t
|
||||||
|
void FBX::Node::WritePropertyNodeAscii(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
int indent
|
||||||
|
){
|
||||||
|
char buffer[32];
|
||||||
|
FBX::Node node(name);
|
||||||
|
node.Begin(s, false, indent);
|
||||||
|
std::string vsize = std::to_string(v.size());
|
||||||
|
// *<size> {
|
||||||
|
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
|
||||||
|
// indent + 1
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
|
||||||
|
// a: value,value,value,...
|
||||||
|
s.PutString("a: ");
|
||||||
|
int count = 0;
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
|
if (i > 0) { s.PutChar(','); }
|
||||||
|
int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]);
|
||||||
|
count += len;
|
||||||
|
if (count > 2048) { s.PutChar('\n'); count = 0; }
|
||||||
|
if (len < 0 || len > 31) {
|
||||||
|
// this should never happen
|
||||||
|
throw DeadlyExportError("failed to convert double to string");
|
||||||
|
}
|
||||||
|
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
s.PutChar('\n');
|
||||||
|
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
|
||||||
|
s.PutChar('}'); s.PutChar(' ');
|
||||||
|
node.End(s, false, indent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary property node from vector of doubles
|
||||||
|
// TODO: optional zip compression!
|
||||||
|
void FBX::Node::WritePropertyNodeBinary(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s
|
||||||
|
){
|
||||||
|
FBX::Node node(name);
|
||||||
|
node.BeginBinary(s);
|
||||||
|
s.PutU1('d');
|
||||||
|
s.PutU4(uint32_t(v.size())); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
s.PutU4(uint32_t(v.size()) * 8); // data size
|
||||||
|
for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
|
||||||
|
node.EndPropertiesBinary(s, 1);
|
||||||
|
node.EndBinary(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary property node from vector of int32_t
|
||||||
|
// TODO: optional zip compression!
|
||||||
|
void FBX::Node::WritePropertyNodeBinary(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s
|
||||||
|
){
|
||||||
|
FBX::Node node(name);
|
||||||
|
node.BeginBinary(s);
|
||||||
|
s.PutU1('i');
|
||||||
|
s.PutU4(uint32_t(v.size())); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
s.PutU4(uint32_t(v.size()) * 4); // data size
|
||||||
|
for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
|
||||||
|
node.EndPropertiesBinary(s, 1);
|
||||||
|
node.EndBinary(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static member functions
|
||||||
|
|
||||||
|
// convenience function to create and write a property node,
|
||||||
|
// holding a single property which is an array of values.
|
||||||
|
// does not copy the data, so is efficient for large arrays.
|
||||||
|
void FBX::Node::WritePropertyNode(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
){
|
||||||
|
if (binary) {
|
||||||
|
FBX::Node::WritePropertyNodeBinary(name, v, s);
|
||||||
|
} else {
|
||||||
|
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience function to create and write a property node,
|
||||||
|
// holding a single property which is an array of values.
|
||||||
|
// does not copy the data, so is efficient for large arrays.
|
||||||
|
void FBX::Node::WritePropertyNode(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
){
|
||||||
|
if (binary) {
|
||||||
|
FBX::Node::WritePropertyNodeBinary(name, v, s);
|
||||||
|
} else {
|
||||||
|
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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 FBXExportNode.h
|
||||||
|
* Declares the FBX::Node helper class for fbx export.
|
||||||
|
*/
|
||||||
|
#ifndef AI_FBXEXPORTNODE_H_INC
|
||||||
|
#define AI_FBXEXPORTNODE_H_INC
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#include "FBXExportProperty.h"
|
||||||
|
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace FBX {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FBX::Node
|
||||||
|
{
|
||||||
|
public: // public data members
|
||||||
|
// TODO: accessors
|
||||||
|
std::string name; // node name
|
||||||
|
std::vector<FBX::Property> properties; // node properties
|
||||||
|
std::vector<FBX::Node> children; // child nodes
|
||||||
|
|
||||||
|
// some nodes always pretend they have children...
|
||||||
|
bool force_has_children = false;
|
||||||
|
|
||||||
|
public: // constructors
|
||||||
|
Node() = default;
|
||||||
|
Node(const std::string& n) : name(n) {}
|
||||||
|
|
||||||
|
// convenience template to construct with properties directly
|
||||||
|
template <typename... More>
|
||||||
|
Node(const std::string& n, const More... more)
|
||||||
|
: name(n)
|
||||||
|
{ AddProperties(more...); }
|
||||||
|
|
||||||
|
public: // functions to add properties or children
|
||||||
|
// add a single property to the node
|
||||||
|
template <typename T>
|
||||||
|
void AddProperty(T value) {
|
||||||
|
properties.emplace_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience function to add multiple properties at once
|
||||||
|
template <typename T, typename... More>
|
||||||
|
void AddProperties(T value, More... more) {
|
||||||
|
properties.emplace_back(value);
|
||||||
|
AddProperties(more...);
|
||||||
|
}
|
||||||
|
void AddProperties() {}
|
||||||
|
|
||||||
|
// add a child node directly
|
||||||
|
void AddChild(const Node& node) { children.push_back(node); }
|
||||||
|
|
||||||
|
// convenience function to add a child node with a single property
|
||||||
|
template <typename... More>
|
||||||
|
void AddChild(
|
||||||
|
const std::string& name,
|
||||||
|
More... more
|
||||||
|
) {
|
||||||
|
FBX::Node c(name);
|
||||||
|
c.AddProperties(more...);
|
||||||
|
children.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // support specifically for dealing with Properties70 nodes
|
||||||
|
|
||||||
|
// it really is simpler to make these all separate functions.
|
||||||
|
// the versions with 'A' suffixes are for animatable properties.
|
||||||
|
// those often follow a completely different format internally in FBX.
|
||||||
|
void AddP70int(const std::string& name, int32_t value);
|
||||||
|
void AddP70bool(const std::string& name, bool value);
|
||||||
|
void AddP70double(const std::string& name, double value);
|
||||||
|
void AddP70numberA(const std::string& name, double value);
|
||||||
|
void AddP70color(const std::string& name, double r, double g, double b);
|
||||||
|
void AddP70colorA(const std::string& name, double r, double g, double b);
|
||||||
|
void AddP70vector(const std::string& name, double x, double y, double z);
|
||||||
|
void AddP70vectorA(const std::string& name, double x, double y, double z);
|
||||||
|
void AddP70string(const std::string& name, const std::string& value);
|
||||||
|
void AddP70enum(const std::string& name, int32_t value);
|
||||||
|
void AddP70time(const std::string& name, int64_t value);
|
||||||
|
|
||||||
|
// template for custom P70 nodes.
|
||||||
|
// anything that doesn't fit in the above can be created manually.
|
||||||
|
template <typename... More>
|
||||||
|
void AddP70(
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& type2,
|
||||||
|
const std::string& flags,
|
||||||
|
More... more
|
||||||
|
) {
|
||||||
|
Node n("P");
|
||||||
|
n.AddProperties(name, type, type2, flags, more...);
|
||||||
|
AddChild(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // member functions for writing data to a file or stream
|
||||||
|
|
||||||
|
// write the full node to the given file or stream
|
||||||
|
void Dump(
|
||||||
|
std::shared_ptr<Assimp::IOStream> outfile,
|
||||||
|
bool binary, int indent
|
||||||
|
);
|
||||||
|
void Dump(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||||
|
|
||||||
|
// these other functions are for writing data piece by piece.
|
||||||
|
// they must be used carefully.
|
||||||
|
// for usage examples see FBXExporter.cpp.
|
||||||
|
void Begin(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||||
|
void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent);
|
||||||
|
void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||||
|
void EndProperties(
|
||||||
|
Assimp::StreamWriterLE &s, bool binary, int indent,
|
||||||
|
size_t num_properties
|
||||||
|
);
|
||||||
|
void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent);
|
||||||
|
void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent);
|
||||||
|
void End(
|
||||||
|
Assimp::StreamWriterLE &s, bool binary, int indent,
|
||||||
|
bool has_children
|
||||||
|
);
|
||||||
|
|
||||||
|
private: // internal functions used for writing
|
||||||
|
|
||||||
|
void DumpBinary(Assimp::StreamWriterLE &s);
|
||||||
|
void DumpAscii(Assimp::StreamWriterLE &s, int indent);
|
||||||
|
void DumpAscii(std::ostream &s, int indent);
|
||||||
|
|
||||||
|
void BeginBinary(Assimp::StreamWriterLE &s);
|
||||||
|
void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
|
||||||
|
void EndPropertiesBinary(Assimp::StreamWriterLE &s);
|
||||||
|
void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
|
||||||
|
void DumpChildrenBinary(Assimp::StreamWriterLE& s);
|
||||||
|
void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
|
||||||
|
|
||||||
|
void BeginAscii(std::ostream &s, int indent);
|
||||||
|
void DumpPropertiesAscii(std::ostream &s, int indent);
|
||||||
|
void BeginChildrenAscii(std::ostream &s, int indent);
|
||||||
|
void DumpChildrenAscii(std::ostream &s, int indent);
|
||||||
|
void EndAscii(std::ostream &s, int indent, bool has_children);
|
||||||
|
|
||||||
|
private: // data used for binary dumps
|
||||||
|
size_t start_pos; // starting position in stream
|
||||||
|
size_t end_pos; // ending position in stream
|
||||||
|
size_t property_start; // starting position of property section
|
||||||
|
|
||||||
|
public: // static member functions
|
||||||
|
|
||||||
|
// convenience function to create a node with a single property,
|
||||||
|
// and write it to the stream.
|
||||||
|
template <typename T>
|
||||||
|
static void WritePropertyNode(
|
||||||
|
const std::string& name,
|
||||||
|
const T value,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
) {
|
||||||
|
FBX::Property p(value);
|
||||||
|
FBX::Node node(name, p);
|
||||||
|
node.Dump(s, binary, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience function to create and write a property node,
|
||||||
|
// holding a single property which is an array of values.
|
||||||
|
// does not copy the data, so is efficient for large arrays.
|
||||||
|
static void WritePropertyNode(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
);
|
||||||
|
|
||||||
|
// convenience function to create and write a property node,
|
||||||
|
// holding a single property which is an array of values.
|
||||||
|
// does not copy the data, so is efficient for large arrays.
|
||||||
|
static void WritePropertyNode(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
bool binary, int indent
|
||||||
|
);
|
||||||
|
|
||||||
|
private: // static helper functions
|
||||||
|
static void WritePropertyNodeAscii(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
int indent
|
||||||
|
);
|
||||||
|
static void WritePropertyNodeAscii(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
int indent
|
||||||
|
);
|
||||||
|
static void WritePropertyNodeBinary(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<double>& v,
|
||||||
|
Assimp::StreamWriterLE& s
|
||||||
|
);
|
||||||
|
static void WritePropertyNodeBinary(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<int32_t>& v,
|
||||||
|
Assimp::StreamWriterLE& s
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#endif // AI_FBXEXPORTNODE_H_INC
|
|
@ -0,0 +1,364 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#include "FBXExportProperty.h"
|
||||||
|
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream> // ostringstream
|
||||||
|
|
||||||
|
|
||||||
|
// constructors for single element properties
|
||||||
|
|
||||||
|
FBX::Property::Property(bool v)
|
||||||
|
: type('C'), data(1)
|
||||||
|
{
|
||||||
|
data = {uint8_t(v)};
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(int16_t v) : type('Y'), data(2)
|
||||||
|
{
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
(reinterpret_cast<int16_t*>(d))[0] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(int32_t v) : type('I'), data(4)
|
||||||
|
{
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
(reinterpret_cast<int32_t*>(d))[0] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(float v) : type('F'), data(4)
|
||||||
|
{
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
(reinterpret_cast<float*>(d))[0] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(double v) : type('D'), data(8)
|
||||||
|
{
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
(reinterpret_cast<double*>(d))[0] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(int64_t v) : type('L'), data(8)
|
||||||
|
{
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
(reinterpret_cast<int64_t*>(d))[0] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// constructors for array-type properties
|
||||||
|
|
||||||
|
FBX::Property::Property(const char* c, bool raw)
|
||||||
|
: Property(std::string(c), raw)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// strings can either be saved as "raw" (R) data, or "string" (S) data
|
||||||
|
FBX::Property::Property(const std::string& s, bool raw)
|
||||||
|
: type(raw ? 'R' : 'S'), data(s.size())
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < s.size(); ++i) {
|
||||||
|
data[i] = uint8_t(s[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(const std::vector<uint8_t>& r)
|
||||||
|
: type('R'), data(r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
FBX::Property::Property(const std::vector<int32_t>& va)
|
||||||
|
: type('i'), data(4*va.size())
|
||||||
|
{
|
||||||
|
int32_t* d = reinterpret_cast<int32_t*>(data.data());
|
||||||
|
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(const std::vector<int64_t>& va)
|
||||||
|
: type('l'), data(8*va.size())
|
||||||
|
{
|
||||||
|
int64_t* d = reinterpret_cast<int64_t*>(data.data());
|
||||||
|
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(const std::vector<float>& va)
|
||||||
|
: type('f'), data(4*va.size())
|
||||||
|
{
|
||||||
|
float* d = reinterpret_cast<float*>(data.data());
|
||||||
|
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(const std::vector<double>& va)
|
||||||
|
: type('d'), data(8*va.size())
|
||||||
|
{
|
||||||
|
double* d = reinterpret_cast<double*>(data.data());
|
||||||
|
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
FBX::Property::Property(const aiMatrix4x4& vm)
|
||||||
|
: type('d'), data(8*16)
|
||||||
|
{
|
||||||
|
double* d = reinterpret_cast<double*>(data.data());
|
||||||
|
for (unsigned int c = 0; c < 4; ++c) {
|
||||||
|
for (unsigned int r = 0; r < 4; ++r) {
|
||||||
|
d[4*c+r] = vm[r][c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public member functions
|
||||||
|
|
||||||
|
size_t FBX::Property::size()
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case 'C': case 'Y': case 'I': case 'F': case 'D': case 'L':
|
||||||
|
return data.size() + 1;
|
||||||
|
case 'S': case 'R':
|
||||||
|
return data.size() + 5;
|
||||||
|
case 'i': case 'd':
|
||||||
|
return data.size() + 13;
|
||||||
|
default:
|
||||||
|
throw DeadlyExportError("Requested size on property of unknown type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s)
|
||||||
|
{
|
||||||
|
s.PutU1(type);
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
size_t N;
|
||||||
|
switch (type) {
|
||||||
|
case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
|
||||||
|
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
|
||||||
|
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
|
||||||
|
case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
|
||||||
|
case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
|
||||||
|
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
|
||||||
|
case 'S':
|
||||||
|
case 'R':
|
||||||
|
s.PutU4(uint32_t(data.size()));
|
||||||
|
for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
|
||||||
|
return;
|
||||||
|
case 'i':
|
||||||
|
N = data.size() / 4;
|
||||||
|
s.PutU4(uint32_t(N)); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
// TODO: compress if large?
|
||||||
|
s.PutU4(uint32_t(data.size())); // data size
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 'l':
|
||||||
|
N = data.size() / 8;
|
||||||
|
s.PutU4(uint32_t(N)); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
// TODO: compress if large?
|
||||||
|
s.PutU4(uint32_t(data.size())); // data size
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 'f':
|
||||||
|
N = data.size() / 4;
|
||||||
|
s.PutU4(uint32_t(N)); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
// TODO: compress if large?
|
||||||
|
s.PutU4(uint32_t(data.size())); // data size
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
s.PutF4((reinterpret_cast<float*>(d))[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 'd':
|
||||||
|
N = data.size() / 8;
|
||||||
|
s.PutU4(uint32_t(N)); // number of elements
|
||||||
|
s.PutU4(0); // no encoding (1 would be zip-compressed)
|
||||||
|
// TODO: compress if large?
|
||||||
|
s.PutU4(uint32_t(data.size())); // data size
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
s.PutF8((reinterpret_cast<double*>(d))[i]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
std::ostringstream err;
|
||||||
|
err << "Tried to dump property with invalid type '";
|
||||||
|
err << type << "'!";
|
||||||
|
throw DeadlyExportError(err.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss.imbue(std::locale::classic());
|
||||||
|
ss.precision(15); // this seems to match official FBX SDK exports
|
||||||
|
DumpAscii(ss, indent);
|
||||||
|
outstream.PutString(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBX::Property::DumpAscii(std::ostream& s, int indent)
|
||||||
|
{
|
||||||
|
// no writing type... or anything. just shove it into the stream.
|
||||||
|
uint8_t* d = data.data();
|
||||||
|
size_t N;
|
||||||
|
size_t swap = data.size();
|
||||||
|
size_t count = 0;
|
||||||
|
switch (type) {
|
||||||
|
case 'C':
|
||||||
|
if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; }
|
||||||
|
else { s << 'F'; }
|
||||||
|
return;
|
||||||
|
case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return;
|
||||||
|
case 'I': s << *(reinterpret_cast<int32_t*>(d)); return;
|
||||||
|
case 'F': s << *(reinterpret_cast<float*>(d)); return;
|
||||||
|
case 'D': s << *(reinterpret_cast<double*>(d)); return;
|
||||||
|
case 'L': s << *(reinterpret_cast<int64_t*>(d)); return;
|
||||||
|
case 'S':
|
||||||
|
// first search to see if it has "\x00\x01" in it -
|
||||||
|
// which separates fields which are reversed in the ascii version.
|
||||||
|
// yeah.
|
||||||
|
// FBX, yeah.
|
||||||
|
for (size_t i = 0; i < data.size(); ++i) {
|
||||||
|
if (data[i] == '\0') {
|
||||||
|
swap = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'R':
|
||||||
|
s << '"';
|
||||||
|
// we might as well check this now,
|
||||||
|
// probably it will never happen
|
||||||
|
for (size_t i = 0; i < data.size(); ++i) {
|
||||||
|
char c = data[i];
|
||||||
|
if (c == '"') {
|
||||||
|
throw runtime_error("can't handle quotes in property string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// first write the SWAPPED member (if any)
|
||||||
|
for (size_t i = swap + 2; i < data.size(); ++i) {
|
||||||
|
char c = data[i];
|
||||||
|
s << c;
|
||||||
|
}
|
||||||
|
// then a separator
|
||||||
|
if (swap != data.size()) {
|
||||||
|
s << "::";
|
||||||
|
}
|
||||||
|
// then the initial member
|
||||||
|
for (size_t i = 0; i < swap; ++i) {
|
||||||
|
char c = data[i];
|
||||||
|
s << c;
|
||||||
|
}
|
||||||
|
s << '"';
|
||||||
|
return;
|
||||||
|
case 'i':
|
||||||
|
N = data.size() / 4; // number of elements
|
||||||
|
s << '*' << N << " {\n";
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||||
|
s << "a: ";
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
if (i > 0) { s << ','; }
|
||||||
|
if (count++ > 120) { s << '\n'; count = 0; }
|
||||||
|
s << (reinterpret_cast<int32_t*>(d))[i];
|
||||||
|
}
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << "} ";
|
||||||
|
return;
|
||||||
|
case 'l':
|
||||||
|
N = data.size() / 8;
|
||||||
|
s << '*' << N << " {\n";
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||||
|
s << "a: ";
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
if (i > 0) { s << ','; }
|
||||||
|
if (count++ > 120) { s << '\n'; count = 0; }
|
||||||
|
s << (reinterpret_cast<int64_t*>(d))[i];
|
||||||
|
}
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << "} ";
|
||||||
|
return;
|
||||||
|
case 'f':
|
||||||
|
N = data.size() / 4;
|
||||||
|
s << '*' << N << " {\n";
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||||
|
s << "a: ";
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
if (i > 0) { s << ','; }
|
||||||
|
if (count++ > 120) { s << '\n'; count = 0; }
|
||||||
|
s << (reinterpret_cast<float*>(d))[i];
|
||||||
|
}
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << "} ";
|
||||||
|
return;
|
||||||
|
case 'd':
|
||||||
|
N = data.size() / 8;
|
||||||
|
s << '*' << N << " {\n";
|
||||||
|
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
|
||||||
|
s << "a: ";
|
||||||
|
// set precision to something that can handle doubles
|
||||||
|
s.precision(15);
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
if (i > 0) { s << ','; }
|
||||||
|
if (count++ > 120) { s << '\n'; count = 0; }
|
||||||
|
s << (reinterpret_cast<double*>(d))[i];
|
||||||
|
}
|
||||||
|
s << '\n';
|
||||||
|
for (int i = 0; i < indent; ++i) { s << '\t'; }
|
||||||
|
s << "} ";
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
std::ostringstream err;
|
||||||
|
err << "Tried to dump property with invalid type '";
|
||||||
|
err << type << "'!";
|
||||||
|
throw runtime_error(err.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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 FBXExportProperty.h
|
||||||
|
* Declares the FBX::Property helper class for fbx export.
|
||||||
|
*/
|
||||||
|
#ifndef AI_FBXEXPORTPROPERTY_H_INC
|
||||||
|
#define AI_FBXEXPORTPROPERTY_H_INC
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
|
||||||
|
#include <assimp/types.h> // aiMatrix4x4
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
#include <type_traits> // is_void
|
||||||
|
|
||||||
|
namespace FBX {
|
||||||
|
class Property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FBX::Property
|
||||||
|
*
|
||||||
|
* Holds a value of any of FBX's recognized types,
|
||||||
|
* each represented by a particular one-character code.
|
||||||
|
* C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true
|
||||||
|
* Y : 2-byte int16
|
||||||
|
* I : 4-byte int32
|
||||||
|
* F : 4-byte float
|
||||||
|
* D : 8-byte double
|
||||||
|
* L : 8-byte int64
|
||||||
|
* i : array of int32
|
||||||
|
* f : array of float
|
||||||
|
* d : array of double
|
||||||
|
* l : array of int64
|
||||||
|
* b : array of 1-byte booleans (0x00 or 0x01)
|
||||||
|
* S : string (array of 1-byte char)
|
||||||
|
* R : raw data (array of bytes)
|
||||||
|
*/
|
||||||
|
class FBX::Property
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors for basic types.
|
||||||
|
// all explicit to avoid accidental typecasting
|
||||||
|
explicit Property(bool v);
|
||||||
|
// TODO: determine if there is actually a byte type,
|
||||||
|
// or if this always means <bool>. 'C' seems to imply <char>,
|
||||||
|
// so possibly the above was intended to represent both.
|
||||||
|
explicit Property(int16_t v);
|
||||||
|
explicit Property(int32_t v);
|
||||||
|
explicit Property(float v);
|
||||||
|
explicit Property(double v);
|
||||||
|
explicit Property(int64_t v);
|
||||||
|
// strings can either be stored as 'R' (raw) or 'S' (string) type
|
||||||
|
explicit Property(const char* c, bool raw=false);
|
||||||
|
explicit Property(const std::string& s, bool raw=false);
|
||||||
|
explicit Property(const std::vector<uint8_t>& r);
|
||||||
|
explicit Property(const std::vector<int32_t>& va);
|
||||||
|
explicit Property(const std::vector<int64_t>& va);
|
||||||
|
explicit Property(const std::vector<double>& va);
|
||||||
|
explicit Property(const std::vector<float>& va);
|
||||||
|
explicit Property(const aiMatrix4x4& vm);
|
||||||
|
|
||||||
|
// this will catch any type not defined above,
|
||||||
|
// so that we don't accidentally convert something we don't want.
|
||||||
|
// for example (const char*) --> (bool)... seriously wtf C++
|
||||||
|
template <class T>
|
||||||
|
explicit Property(T v) : type('X') {
|
||||||
|
static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
|
||||||
|
} // note: no line wrap so it appears verbatim on the compiler error
|
||||||
|
|
||||||
|
// the size of this property node in a binary file, in bytes
|
||||||
|
size_t size();
|
||||||
|
|
||||||
|
// write this property node as binary data to the given stream
|
||||||
|
void DumpBinary(Assimp::StreamWriterLE &s);
|
||||||
|
void DumpAscii(Assimp::StreamWriterLE &s, int indent=0);
|
||||||
|
void DumpAscii(std::ostream &s, int indent=0);
|
||||||
|
// note: make sure the ostream is in classic "C" locale
|
||||||
|
|
||||||
|
private:
|
||||||
|
char type;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#endif // AI_FBXEXPORTPROPERTY_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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 FBXExporter.h
|
||||||
|
* Declares the exporter class to write a scene to an fbx file
|
||||||
|
*/
|
||||||
|
#ifndef AI_FBXEXPORTER_H_INC
|
||||||
|
#define AI_FBXEXPORTER_H_INC
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#include "FBXExportNode.h" // FBX::Node
|
||||||
|
#include "FBXCommon.h" // FBX::TransformInheritance
|
||||||
|
|
||||||
|
#include <assimp/types.h>
|
||||||
|
//#include <assimp/material.h>
|
||||||
|
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||||
|
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <memory> // shared_ptr
|
||||||
|
#include <sstream> // stringstream
|
||||||
|
|
||||||
|
struct aiScene;
|
||||||
|
struct aiNode;
|
||||||
|
//struct aiMaterial;
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
class IOSystem;
|
||||||
|
class IOStream;
|
||||||
|
class ExportProperties;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/** Helper class to export a given scene to an FBX file. */
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
class FBXExporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Constructor for a specific scene to export
|
||||||
|
FBXExporter(const aiScene* pScene, const ExportProperties* pProperties);
|
||||||
|
|
||||||
|
// call one of these methods to export
|
||||||
|
void ExportBinary(const char* pFile, IOSystem* pIOSystem);
|
||||||
|
void ExportAscii(const char* pFile, IOSystem* pIOSystem);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool binary; // whether current export is in binary or ascii format
|
||||||
|
const aiScene* mScene; // the scene to export
|
||||||
|
const ExportProperties* mProperties; // currently unused
|
||||||
|
std::shared_ptr<IOStream> outfile; // file to write to
|
||||||
|
|
||||||
|
std::vector<FBX::Node> connections; // conection storage
|
||||||
|
|
||||||
|
std::vector<int64_t> mesh_uids;
|
||||||
|
std::vector<int64_t> material_uids;
|
||||||
|
std::map<const aiNode*,int64_t> node_uids;
|
||||||
|
|
||||||
|
// this crude unique-ID system is actually fine
|
||||||
|
int64_t last_uid = 999999;
|
||||||
|
int64_t generate_uid() { return ++last_uid; }
|
||||||
|
|
||||||
|
// binary files have a specific header and footer,
|
||||||
|
// in addition to the actual data
|
||||||
|
void WriteBinaryHeader();
|
||||||
|
void WriteBinaryFooter();
|
||||||
|
|
||||||
|
// ascii files have a comment at the top
|
||||||
|
void WriteAsciiHeader();
|
||||||
|
|
||||||
|
// WriteAllNodes does the actual export.
|
||||||
|
// It just calls all the Write<Section> methods below in order.
|
||||||
|
void WriteAllNodes();
|
||||||
|
|
||||||
|
// Methods to write individual sections.
|
||||||
|
// The order here matches the order inside an FBX file.
|
||||||
|
// Each method corresponds to a top-level FBX section,
|
||||||
|
// except WriteHeader which also includes some binary-only sections
|
||||||
|
// and WriteFooter which is binary data only.
|
||||||
|
void WriteHeaderExtension();
|
||||||
|
// WriteFileId(); // binary-only, included in WriteHeader
|
||||||
|
// WriteCreationTime(); // binary-only, included in WriteHeader
|
||||||
|
// WriteCreator(); // binary-only, included in WriteHeader
|
||||||
|
void WriteGlobalSettings();
|
||||||
|
void WriteDocuments();
|
||||||
|
void WriteReferences();
|
||||||
|
void WriteDefinitions();
|
||||||
|
void WriteObjects();
|
||||||
|
void WriteConnections();
|
||||||
|
// WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
void WriteAsciiSectionHeader(const std::string& title);
|
||||||
|
void WriteModelNodes(
|
||||||
|
Assimp::StreamWriterLE& s,
|
||||||
|
const aiNode* node,
|
||||||
|
int64_t parent_uid,
|
||||||
|
const std::unordered_set<const aiNode*>& limbnodes
|
||||||
|
);
|
||||||
|
void WriteModelNodes( // usually don't call this directly
|
||||||
|
StreamWriterLE& s,
|
||||||
|
const aiNode* node,
|
||||||
|
int64_t parent_uid,
|
||||||
|
const std::unordered_set<const aiNode*>& limbnodes,
|
||||||
|
std::vector<std::pair<std::string,aiVector3D>>& transform_chain
|
||||||
|
);
|
||||||
|
void WriteModelNode( // nor this
|
||||||
|
StreamWriterLE& s,
|
||||||
|
bool binary,
|
||||||
|
const aiNode* node,
|
||||||
|
int64_t node_uid,
|
||||||
|
const std::string& type,
|
||||||
|
const std::vector<std::pair<std::string,aiVector3D>>& xfm_chain,
|
||||||
|
FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs
|
||||||
|
);
|
||||||
|
void WriteAnimationCurveNode(
|
||||||
|
StreamWriterLE& outstream,
|
||||||
|
int64_t uid,
|
||||||
|
std::string name, // "T", "R", or "S"
|
||||||
|
aiVector3D default_value,
|
||||||
|
std::string property_name, // "Lcl Translation" etc
|
||||||
|
int64_t animation_layer_uid,
|
||||||
|
int64_t node_uid
|
||||||
|
);
|
||||||
|
void WriteAnimationCurve(
|
||||||
|
StreamWriterLE& outstream,
|
||||||
|
double default_value,
|
||||||
|
const std::vector<int64_t>& times,
|
||||||
|
const std::vector<float>& values,
|
||||||
|
int64_t curvenode_id,
|
||||||
|
const std::string& property_link // "d|X", "d|Y", etc
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||||
|
|
||||||
|
#endif // AI_FBXEXPORTER_H_INC
|
|
@ -54,6 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "FBXProperties.h"
|
#include "FBXProperties.h"
|
||||||
#include <assimp/ByteSwapper.h>
|
#include <assimp/ByteSwapper.h>
|
||||||
|
|
||||||
|
#include <algorithm> // std::transform
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
|
||||||
|
@ -82,11 +84,12 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
|
||||||
|
|
||||||
std::string templateName;
|
std::string templateName;
|
||||||
|
|
||||||
const char* const sh = shading.c_str();
|
// lower-case shading because Blender (for example) writes "Phong"
|
||||||
if(!strcmp(sh,"phong")) {
|
std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower);
|
||||||
|
if(shading == "phong") {
|
||||||
templateName = "Material.FbxSurfacePhong";
|
templateName = "Material.FbxSurfacePhong";
|
||||||
}
|
}
|
||||||
else if(!strcmp(sh,"lambert")) {
|
else if(shading == "lambert") {
|
||||||
templateName = "Material.FbxSurfaceLambert";
|
templateName = "Material.FbxSurfaceLambert";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -79,14 +79,13 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Geometry::~Geometry()
|
Geometry::~Geometry()
|
||||||
{
|
{
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
const Skin* Geometry::DeformerSkin() const {
|
const Skin* Geometry::DeformerSkin() const {
|
||||||
return skin;
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||||
: Geometry(id, element,name, doc)
|
: Geometry(id, element,name, doc)
|
||||||
|
@ -186,9 +185,8 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
MeshGeometry::~MeshGeometry()
|
MeshGeometry::~MeshGeometry() {
|
||||||
{
|
// empty
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -308,7 +306,6 @@ void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
||||||
<< type << ", index: " << typedIndex);
|
<< type << ", index: " << typedIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
|
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
|
||||||
{
|
{
|
||||||
|
@ -412,7 +409,6 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Lengthy utility function to read and resolve a FBX vertex data array - that is, the
|
// Lengthy utility function to read and resolve a FBX vertex data array - that is, the
|
||||||
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
|
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
|
||||||
|
@ -428,16 +424,19 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
const std::vector<unsigned int>& mapping_offsets,
|
const std::vector<unsigned int>& mapping_offsets,
|
||||||
const std::vector<unsigned int>& mappings)
|
const std::vector<unsigned int>& mappings)
|
||||||
{
|
{
|
||||||
|
bool isDirect = ReferenceInformationType == "Direct";
|
||||||
|
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
|
||||||
|
|
||||||
|
// fall-back to direct data if there is no index data element
|
||||||
|
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
|
||||||
|
isDirect = true;
|
||||||
|
isIndexToDirect = false;
|
||||||
|
}
|
||||||
|
|
||||||
// handle permutations of Mapping and Reference type - it would be nice to
|
// handle permutations of Mapping and Reference type - it would be nice to
|
||||||
// deal with this more elegantly and with less redundancy, but right
|
// deal with this more elegantly and with less redundancy, but right
|
||||||
// now it seems unavoidable.
|
// now it seems unavoidable.
|
||||||
if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
|
if (MappingInformationType == "ByVertice" && isDirect) {
|
||||||
if ( !HasElement( source, indexDataElementName ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
|
@ -450,14 +449,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
|
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
data_out.resize(vertex_count);
|
data_out.resize(vertex_count);
|
||||||
if ( !HasElement( source, indexDataElementName ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> uvIndices;
|
std::vector<int> uvIndices;
|
||||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||||
|
@ -472,7 +468,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
|
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
|
@ -485,7 +481,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
|
|
||||||
data_out.swap(tempData);
|
data_out.swap(tempData);
|
||||||
}
|
}
|
||||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
|
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
|
@ -499,9 +495,14 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const T empty;
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
for(int i : uvIndices) {
|
for(int i : uvIndices) {
|
||||||
if (static_cast<size_t>(i) >= tempData.size()) {
|
if ( -1 == i ) {
|
||||||
|
data_out[ next++ ] = empty;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (static_cast<size_t>(i) >= tempData.size()) {
|
||||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,7 +529,6 @@ void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, c
|
||||||
m_mappings);
|
m_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
|
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
|
||||||
const std::string& MappingInformationType,
|
const std::string& MappingInformationType,
|
||||||
|
@ -543,7 +543,6 @@ void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope
|
||||||
m_mappings);
|
m_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
|
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
|
||||||
const std::string& MappingInformationType,
|
const std::string& MappingInformationType,
|
||||||
|
|
|
@ -68,7 +68,6 @@ private:
|
||||||
const Skin* skin;
|
const Skin* skin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::vector<int> MatIndexArray;
|
typedef std::vector<int> MatIndexArray;
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,8 +94,8 @@ public:
|
||||||
* if no tangents are specified */
|
* if no tangents are specified */
|
||||||
const std::vector<aiVector3D>& GetTangents() const;
|
const std::vector<aiVector3D>& GetTangents() const;
|
||||||
|
|
||||||
/** Get a list of all vertex binormals or an empty array
|
/** Get a list of all vertex bi-normals or an empty array
|
||||||
* if no binormals are specified */
|
* if no bi-normals are specified */
|
||||||
const std::vector<aiVector3D>& GetBinormals() const;
|
const std::vector<aiVector3D>& GetBinormals() const;
|
||||||
|
|
||||||
/** Return list of faces - each entry denotes a face and specifies
|
/** Return list of faces - each entry denotes a face and specifies
|
||||||
|
|
|
@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* Implements a filter system to filter calls to Exists() and Open()
|
* Implements a filter system to filter calls to Exists() and Open()
|
||||||
* in order to improve the success rate of file opening ...
|
* in order to improve the success rate of file opening ...
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_FILESYSTEMFILTER_H_INC
|
#ifndef AI_FILESYSTEMFILTER_H_INC
|
||||||
#define AI_FILESYSTEMFILTER_H_INC
|
#define AI_FILESYSTEMFILTER_H_INC
|
||||||
|
|
||||||
#include "../include/assimp/IOSystem.hpp"
|
#include <assimp/IOSystem.hpp>
|
||||||
#include "../include/assimp/DefaultLogger.hpp"
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include "../include/assimp/fast_atof.h"
|
#include <assimp/fast_atof.h>
|
||||||
#include "../include/assimp/ParsingUtils.h"
|
#include <assimp/ParsingUtils.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -64,90 +65,89 @@ class FileSystemFilter : public IOSystem
|
||||||
public:
|
public:
|
||||||
/** Constructor. */
|
/** Constructor. */
|
||||||
FileSystemFilter(const std::string& file, IOSystem* old)
|
FileSystemFilter(const std::string& file, IOSystem* old)
|
||||||
: wrapped (old)
|
: mWrapped (old)
|
||||||
, src_file (file)
|
, mSrc_file(file)
|
||||||
, sep(wrapped->getOsSeparator())
|
, sep(mWrapped->getOsSeparator()) {
|
||||||
{
|
ai_assert(nullptr != mWrapped);
|
||||||
ai_assert(NULL != wrapped);
|
|
||||||
|
|
||||||
// Determine base directory
|
// Determine base directory
|
||||||
base = src_file;
|
mBase = mSrc_file;
|
||||||
std::string::size_type ss2;
|
std::string::size_type ss2;
|
||||||
if (std::string::npos != (ss2 = base.find_last_of("\\/"))) {
|
if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) {
|
||||||
base.erase(ss2,base.length()-ss2);
|
mBase.erase(ss2,mBase.length()-ss2);
|
||||||
}
|
} else {
|
||||||
else {
|
mBase = "";
|
||||||
base = "";
|
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the directory is terminated properly
|
// make sure the directory is terminated properly
|
||||||
char s;
|
char s;
|
||||||
|
|
||||||
if (base.length() == 0) {
|
if ( mBase.empty() ) {
|
||||||
base = ".";
|
mBase = ".";
|
||||||
base += getOsSeparator();
|
mBase += getOsSeparator();
|
||||||
}
|
} else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
|
||||||
else if ((s = *(base.end()-1)) != '\\' && s != '/') {
|
mBase += getOsSeparator();
|
||||||
base += getOsSeparator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultLogger::get()->info("Import root directory is \'" + base + "\'");
|
DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Destructor. */
|
/** Destructor. */
|
||||||
~FileSystemFilter()
|
~FileSystemFilter() {
|
||||||
{
|
// empty
|
||||||
// haha
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Tests for the existence of a file at the given path. */
|
/** Tests for the existence of a file at the given path. */
|
||||||
bool Exists( const char* pFile) const
|
bool Exists( const char* pFile) const {
|
||||||
{
|
ai_assert( nullptr != mWrapped );
|
||||||
|
|
||||||
std::string tmp = pFile;
|
std::string tmp = pFile;
|
||||||
|
|
||||||
// Currently this IOSystem is also used to open THE ONE FILE.
|
// Currently this IOSystem is also used to open THE ONE FILE.
|
||||||
if (tmp != src_file) {
|
if (tmp != mSrc_file) {
|
||||||
BuildPath(tmp);
|
BuildPath(tmp);
|
||||||
Cleanup(tmp);
|
Cleanup(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapped->Exists(tmp);
|
return mWrapped->Exists(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns the directory separator. */
|
/** Returns the directory separator. */
|
||||||
char getOsSeparator() const
|
char getOsSeparator() const {
|
||||||
{
|
|
||||||
return sep;
|
return sep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Open a new file with a given path. */
|
/** Open a new file with a given path. */
|
||||||
IOStream* Open( const char* pFile, const char* pMode = "rb")
|
IOStream* Open( const char* pFile, const char* pMode = "rb") {
|
||||||
{
|
ai_assert( nullptr != mWrapped );
|
||||||
ai_assert(pFile);
|
if ( nullptr == pFile || nullptr == pMode ) {
|
||||||
ai_assert(pMode);
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert( nullptr != pFile );
|
||||||
|
ai_assert( nullptr != pMode );
|
||||||
|
|
||||||
// First try the unchanged path
|
// First try the unchanged path
|
||||||
IOStream* s = wrapped->Open(pFile,pMode);
|
IOStream* s = mWrapped->Open(pFile,pMode);
|
||||||
|
|
||||||
if (!s) {
|
if (nullptr == s) {
|
||||||
std::string tmp = pFile;
|
std::string tmp = pFile;
|
||||||
|
|
||||||
// Try to convert between absolute and relative paths
|
// Try to convert between absolute and relative paths
|
||||||
BuildPath(tmp);
|
BuildPath(tmp);
|
||||||
s = wrapped->Open(tmp,pMode);
|
s = mWrapped->Open(tmp,pMode);
|
||||||
|
|
||||||
if (!s) {
|
if (nullptr == s) {
|
||||||
// Finally, look for typical issues with paths
|
// Finally, look for typical issues with paths
|
||||||
// and try to correct them. This is our last
|
// and try to correct them. This is our last
|
||||||
// resort.
|
// resort.
|
||||||
tmp = pFile;
|
tmp = pFile;
|
||||||
Cleanup(tmp);
|
Cleanup(tmp);
|
||||||
BuildPath(tmp);
|
BuildPath(tmp);
|
||||||
s = wrapped->Open(tmp,pMode);
|
s = mWrapped->Open(tmp,pMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,27 +156,75 @@ public:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Closes the given file and releases all resources associated with it. */
|
/** Closes the given file and releases all resources associated with it. */
|
||||||
void Close( IOStream* pFile)
|
void Close( IOStream* pFile) {
|
||||||
{
|
ai_assert( nullptr != mWrapped );
|
||||||
return wrapped->Close(pFile);
|
return mWrapped->Close(pFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Compare two paths */
|
/** Compare two paths */
|
||||||
bool ComparePaths (const char* one, const char* second) const
|
bool ComparePaths (const char* one, const char* second) const {
|
||||||
{
|
ai_assert( nullptr != mWrapped );
|
||||||
return wrapped->ComparePaths (one,second);
|
return mWrapped->ComparePaths (one,second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Pushes a new directory onto the directory stack. */
|
||||||
|
bool PushDirectory(const std::string &path ) {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->PushDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Returns the top directory from the stack. */
|
||||||
|
const std::string &CurrentDirectory() const {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->CurrentDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Returns the number of directories stored on the stack. */
|
||||||
|
size_t StackSize() const {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->StackSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Pops the top directory from the stack. */
|
||||||
|
bool PopDirectory() {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->PopDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Creates an new directory at the given path. */
|
||||||
|
bool CreateDirectory(const std::string &path) {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->CreateDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Will change the current directory to the given path. */
|
||||||
|
bool ChangeDirectory(const std::string &path) {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->ChangeDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Delete file. */
|
||||||
|
bool DeleteFile(const std::string &file) {
|
||||||
|
ai_assert( nullptr != mWrapped );
|
||||||
|
return mWrapped->DeleteFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Build a valid path from a given relative or absolute path.
|
/** Build a valid path from a given relative or absolute path.
|
||||||
*/
|
*/
|
||||||
void BuildPath (std::string& in) const
|
void BuildPath (std::string& in) const {
|
||||||
{
|
ai_assert( nullptr != mWrapped );
|
||||||
// if we can already access the file, great.
|
// if we can already access the file, great.
|
||||||
if (in.length() < 3 || wrapped->Exists(in)) {
|
if (in.length() < 3 || mWrapped->Exists(in)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +232,8 @@ private:
|
||||||
if (in[1] != ':') {
|
if (in[1] != ':') {
|
||||||
|
|
||||||
// append base path and try
|
// append base path and try
|
||||||
const std::string tmp = base + in;
|
const std::string tmp = mBase + in;
|
||||||
if (wrapped->Exists(tmp)) {
|
if (mWrapped->Exists(tmp)) {
|
||||||
in = tmp;
|
in = tmp;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +255,7 @@ private:
|
||||||
std::string::size_type last_dirsep = std::string::npos;
|
std::string::size_type last_dirsep = std::string::npos;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
tmp = base;
|
tmp = mBase;
|
||||||
tmp += sep;
|
tmp += sep;
|
||||||
|
|
||||||
std::string::size_type dirsep = in.rfind('/', last_dirsep);
|
std::string::size_type dirsep = in.rfind('/', last_dirsep);
|
||||||
|
@ -223,7 +271,7 @@ private:
|
||||||
last_dirsep = dirsep-1;
|
last_dirsep = dirsep-1;
|
||||||
|
|
||||||
tmp += in.substr(dirsep+1, in.length()-pos);
|
tmp += in.substr(dirsep+1, in.length()-pos);
|
||||||
if (wrapped->Exists(tmp)) {
|
if (mWrapped->Exists(tmp)) {
|
||||||
in = tmp;
|
in = tmp;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -236,15 +284,14 @@ private:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Cleanup the given path
|
/** Cleanup the given path
|
||||||
*/
|
*/
|
||||||
void Cleanup (std::string& in) const
|
void Cleanup (std::string& in) const {
|
||||||
{
|
|
||||||
char last = 0;
|
|
||||||
if(in.empty()) {
|
if(in.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a very common issue when we're parsing file names: spaces at the
|
// Remove a very common issue when we're parsing file names: spaces at the
|
||||||
// beginning of the path.
|
// beginning of the path.
|
||||||
|
char last = 0;
|
||||||
std::string::iterator it = in.begin();
|
std::string::iterator it = in.begin();
|
||||||
while (IsSpaceOrNewLine( *it ))++it;
|
while (IsSpaceOrNewLine( *it ))++it;
|
||||||
if (it != in.begin()) {
|
if (it != in.begin()) {
|
||||||
|
@ -274,9 +321,7 @@ private:
|
||||||
it = in.erase(it);
|
it = in.erase(it);
|
||||||
--it;
|
--it;
|
||||||
}
|
}
|
||||||
}
|
} else if (*it == '%' && in.end() - it > 2) {
|
||||||
else if (*it == '%' && in.end() - it > 2) {
|
|
||||||
|
|
||||||
// Hex sequence in URIs
|
// Hex sequence in URIs
|
||||||
if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
|
if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
|
||||||
*it = HexOctetToDecimal(&*it);
|
*it = HexOctetToDecimal(&*it);
|
||||||
|
@ -290,8 +335,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IOSystem* wrapped;
|
IOSystem *mWrapped;
|
||||||
std::string src_file, base;
|
std::string mSrc_file, mBase;
|
||||||
char sep;
|
char sep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,9 +60,9 @@ namespace Assimp {
|
||||||
* @param in Input mesh
|
* @param in Input mesh
|
||||||
* @return Hash.
|
* @return Hash.
|
||||||
*/
|
*/
|
||||||
inline uint64_t GetMeshHash(aiMesh* in)
|
inline
|
||||||
{
|
uint64_t GetMeshHash(aiMesh* in) {
|
||||||
ai_assert(NULL != in);
|
ai_assert(nullptr != in);
|
||||||
|
|
||||||
// ... get an unique value representing the vertex format of the mesh
|
// ... get an unique value representing the vertex format of the mesh
|
||||||
const unsigned int fhash = GetMeshVFormatUnique(in);
|
const unsigned int fhash = GetMeshVFormatUnique(in);
|
||||||
|
@ -78,14 +78,14 @@ inline uint64_t GetMeshHash(aiMesh* in)
|
||||||
/** @brief Perform a component-wise comparison of two arrays
|
/** @brief Perform a component-wise comparison of two arrays
|
||||||
*
|
*
|
||||||
* @param first First array
|
* @param first First array
|
||||||
* @param second Second aray
|
* @param second Second array
|
||||||
* @param size Size of both arrays
|
* @param size Size of both arrays
|
||||||
* @param e Epsilon
|
* @param e Epsilon
|
||||||
* @return true if the arrays are identical
|
* @return true if the arrays are identical
|
||||||
*/
|
*/
|
||||||
inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
|
inline
|
||||||
unsigned int size, float e)
|
bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
|
||||||
{
|
unsigned int size, float e) {
|
||||||
for (const aiVector3D* end = first+size; first != end; ++first,++second) {
|
for (const aiVector3D* end = first+size; first != end; ++first,++second) {
|
||||||
if ( (*first - *second).SquareLength() >= e)
|
if ( (*first - *second).SquareLength() >= e)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -100,26 +100,22 @@ IRRImporter::~IRRImporter()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||||
{
|
|
||||||
/* NOTE: A simple check for the file extension is not enough
|
|
||||||
* here. Irrmesh and irr are easy, but xml is too generic
|
|
||||||
* and could be collada, too. So we need to open the file and
|
|
||||||
* search for typical tokens.
|
|
||||||
*/
|
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
|
if ( extension == "irr" ) {
|
||||||
if (extension == "irr")return true;
|
return true;
|
||||||
else if (extension == "xml" || checkSig)
|
} else if (extension == "xml" || checkSig) {
|
||||||
{
|
|
||||||
/* If CanRead() is called in order to check whether we
|
/* If CanRead() is called in order to check whether we
|
||||||
* support a specific file extension in general pIOHandler
|
* support a specific file extension in general pIOHandler
|
||||||
* might be NULL and it's our duty to return true here.
|
* might be NULL and it's our duty to return true here.
|
||||||
*/
|
*/
|
||||||
if (!pIOHandler)return true;
|
if ( nullptr == pIOHandler ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const char* tokens[] = {"irr_scene"};
|
const char* tokens[] = {"irr_scene"};
|
||||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,7 @@ Importer::~Importer()
|
||||||
delete pimpl->mIOHandler;
|
delete pimpl->mIOHandler;
|
||||||
delete pimpl->mProgressHandler;
|
delete pimpl->mProgressHandler;
|
||||||
|
|
||||||
// Kill imported scene. Destructors should do that recursivly
|
// Kill imported scene. Destructor's should do that recursively
|
||||||
delete pimpl->mScene;
|
delete pimpl->mScene;
|
||||||
|
|
||||||
// Delete shared post-processing data
|
// Delete shared post-processing data
|
||||||
|
@ -200,18 +200,6 @@ Importer::~Importer()
|
||||||
delete pimpl;
|
delete pimpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Copy constructor - copies the config of another Importer, not the scene
|
|
||||||
Importer::Importer(const Importer &other)
|
|
||||||
: pimpl(NULL) {
|
|
||||||
new(this) Importer();
|
|
||||||
|
|
||||||
pimpl->mIntProperties = other.pimpl->mIntProperties;
|
|
||||||
pimpl->mFloatProperties = other.pimpl->mFloatProperties;
|
|
||||||
pimpl->mStringProperties = other.pimpl->mStringProperties;
|
|
||||||
pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Register a custom post-processing step
|
// Register a custom post-processing step
|
||||||
aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
|
aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
|
||||||
|
@ -634,7 +622,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
if (s != std::string::npos) {
|
if (s != std::string::npos) {
|
||||||
DefaultLogger::get()->info("File extension not known, trying signature-based detection");
|
DefaultLogger::get()->info("File extension not known, trying signature-based detection");
|
||||||
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
||||||
|
|
||||||
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
|
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
|
||||||
imp = pimpl->mImporter[a];
|
imp = pimpl->mImporter[a];
|
||||||
break;
|
break;
|
||||||
|
@ -959,6 +946,7 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const
|
||||||
size_t Importer::GetImporterIndex (const char* szExtension) const
|
size_t Importer::GetImporterIndex (const char* szExtension) const
|
||||||
{
|
{
|
||||||
ai_assert(szExtension);
|
ai_assert(szExtension);
|
||||||
|
|
||||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||||
|
|
||||||
// skip over wildcard and dot characters at string head --
|
// skip over wildcard and dot characters at string head --
|
||||||
|
|
|
@ -141,7 +141,8 @@ bool IFCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
||||||
// it is only unambiguous as long as we don't support any further
|
// it is only unambiguous as long as we don't support any further
|
||||||
// file formats with STEP as their encoding.
|
// file formats with STEP as their encoding.
|
||||||
const char* tokens[] = {"ISO-10303-21"};
|
const char* tokens[] = {"ISO-10303-21"};
|
||||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
const bool found( SearchFileHeaderForToken( pIOHandler, pFile, tokens, 1 ) );
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -582,9 +583,8 @@ typedef std::map<std::string, std::string> Metadata;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
|
void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
|
||||||
const std::string& prefix = "",
|
const std::string& prefix = "",
|
||||||
unsigned int nest = 0)
|
unsigned int nest = 0) {
|
||||||
{
|
|
||||||
for(const Schema_2x3::IfcProperty& property : set) {
|
for(const Schema_2x3::IfcProperty& property : set) {
|
||||||
const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
|
const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
|
||||||
if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {
|
if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {
|
||||||
|
|
|
@ -40,13 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */
|
/** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */
|
||||||
|
|
||||||
#include "AssimpPCH.h"
|
|
||||||
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
||||||
|
|
||||||
#include "IFCReaderGen.h"
|
#include "AssimpPCH.h"
|
||||||
|
#include "IFCReaderGen4.h"
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
using namespace IFC;
|
using namespace IFC;
|
||||||
|
using namespace ::Assimp::IFC::Schema_4;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -432,7 +432,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||||
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
|
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
|
||||||
if (layer.mName != "<LWODefault>" || num > 0) {
|
if (layer.mName != "<LWODefault>" || num > 0) {
|
||||||
aiNode* pcNode = new aiNode();
|
aiNode* pcNode = new aiNode();
|
||||||
apcNodes[layer.mIndex] = pcNode;
|
|
||||||
pcNode->mName.Set(layer.mName);
|
pcNode->mName.Set(layer.mName);
|
||||||
pcNode->mParent = (aiNode*)&layer;
|
pcNode->mParent = (aiNode*)&layer;
|
||||||
pcNode->mNumMeshes = num;
|
pcNode->mNumMeshes = num;
|
||||||
|
@ -442,6 +441,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||||
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
||||||
pcNode->mMeshes[p] = p + meshStart;
|
pcNode->mMeshes[p] = p + meshStart;
|
||||||
}
|
}
|
||||||
|
apcNodes[layer.mIndex] = pcNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,7 +584,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
||||||
//Set parent of all children, inserting pivots
|
//Set parent of all children, inserting pivots
|
||||||
//std::cout << "Set parent of all children" << std::endl;
|
//std::cout << "Set parent of all children" << std::endl;
|
||||||
std::map<uint16_t, aiNode*> mapPivot;
|
std::map<uint16_t, aiNode*> mapPivot;
|
||||||
for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||||
|
|
||||||
//Get the parent index
|
//Get the parent index
|
||||||
LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
|
LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
|
||||||
|
@ -593,7 +593,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
||||||
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
||||||
aiNode* pivotNode = new aiNode();
|
aiNode* pivotNode = new aiNode();
|
||||||
pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
|
pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
|
||||||
mapPivot[-(itapcNodes->first+2)] = pivotNode;
|
|
||||||
itapcNodes->second->mParent = pivotNode;
|
itapcNodes->second->mParent = pivotNode;
|
||||||
|
|
||||||
//Look for the parent node to attach the pivot to
|
//Look for the parent node to attach the pivot to
|
||||||
|
@ -611,18 +610,19 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
||||||
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
||||||
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
||||||
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
||||||
|
mapPivot[-(itapcNodes->first+2)] = pivotNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Merge pivot map into node map
|
//Merge pivot map into node map
|
||||||
//std::cout << "Merge pivot map into node map" << std::endl;
|
//std::cout << "Merge pivot map into node map" << std::endl;
|
||||||
for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
||||||
apcNodes[itMapPivot->first] = itMapPivot->second;
|
apcNodes[itMapPivot->first] = itMapPivot->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set children of all parents
|
//Set children of all parents
|
||||||
apcNodes[-1] = root;
|
apcNodes[-1] = root;
|
||||||
for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
|
for (auto itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
|
||||||
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
||||||
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
||||||
++(itMapParentNodes->second->mNumChildren);
|
++(itMapParentNodes->second->mNumChildren);
|
||||||
}
|
}
|
||||||
|
@ -630,7 +630,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
||||||
if (itMapParentNodes->second->mNumChildren) {
|
if (itMapParentNodes->second->mNumChildren) {
|
||||||
itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
|
itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
|
||||||
uint16_t p = 0;
|
uint16_t p = 0;
|
||||||
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
||||||
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
||||||
itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
|
itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,11 @@ public:
|
||||||
{
|
{
|
||||||
unsigned int mBone; ///< Index of the bone
|
unsigned int mBone; ///< Index of the bone
|
||||||
float mWeight; ///< Weight of that bone on this vertex
|
float mWeight; ///< Weight of that bone on this vertex
|
||||||
Weight() { }
|
Weight()
|
||||||
|
: mBone(0)
|
||||||
|
, mWeight(0.0f)
|
||||||
|
{ }
|
||||||
|
|
||||||
Weight( unsigned int pBone, float pWeight)
|
Weight( unsigned int pBone, float pWeight)
|
||||||
{
|
{
|
||||||
mBone = pBone;
|
mBone = pBone;
|
||||||
|
|
|
@ -844,11 +844,11 @@ struct IntGroupInfo_MDL7
|
||||||
struct IntGroupData_MDL7
|
struct IntGroupData_MDL7
|
||||||
{
|
{
|
||||||
IntGroupData_MDL7()
|
IntGroupData_MDL7()
|
||||||
: pcFaces(NULL), bNeed2UV(false)
|
: bNeed2UV(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//! Array of faces that belong to the group
|
//! Array of faces that belong to the group
|
||||||
MDL::IntFace_MDL7* pcFaces;
|
std::vector<MDL::IntFace_MDL7> pcFaces;
|
||||||
|
|
||||||
//! Array of vertex positions
|
//! Array of vertex positions
|
||||||
std::vector<aiVector3D> vPositions;
|
std::vector<aiVector3D> vPositions;
|
||||||
|
|
|
@ -1502,7 +1502,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
||||||
groupData.bNeed2UV = true;
|
groupData.bNeed2UV = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris];
|
groupData.pcFaces.resize(groupInfo.pcGroup->numtris);
|
||||||
|
|
||||||
// read all faces into the preallocated arrays
|
// read all faces into the preallocated arrays
|
||||||
ReadFaces_3DGS_MDL7(groupInfo, groupData);
|
ReadFaces_3DGS_MDL7(groupInfo, groupData);
|
||||||
|
|
|
@ -132,18 +132,18 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt
|
||||||
mOutputMat.precision(16);
|
mOutputMat.precision(16);
|
||||||
|
|
||||||
WriteGeometryFile(noMtl);
|
WriteGeometryFile(noMtl);
|
||||||
if (!noMtl)
|
if ( !noMtl ) {
|
||||||
WriteMaterialFile();
|
WriteMaterialFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
ObjExporter::~ObjExporter() {
|
ObjExporter::~ObjExporter() {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string ObjExporter :: GetMaterialLibName()
|
std::string ObjExporter::GetMaterialLibName() {
|
||||||
{
|
|
||||||
// within the Obj file, we use just the relative file name with the path stripped
|
// within the Obj file, we use just the relative file name with the path stripped
|
||||||
const std::string& s = GetMaterialLibFileName();
|
const std::string& s = GetMaterialLibFileName();
|
||||||
std::string::size_type il = s.find_last_of("/\\");
|
std::string::size_type il = s.find_last_of("/\\");
|
||||||
|
@ -158,8 +158,9 @@ std::string ObjExporter :: GetMaterialLibName()
|
||||||
std::string ObjExporter::GetMaterialLibFileName() {
|
std::string ObjExporter::GetMaterialLibFileName() {
|
||||||
// Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
|
// Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
|
||||||
size_t lastdot = filename.find_last_of('.');
|
size_t lastdot = filename.find_last_of('.');
|
||||||
if (lastdot != std::string::npos)
|
if ( lastdot != std::string::npos ) {
|
||||||
return filename.substr(0, lastdot) + MaterialExt;
|
return filename.substr( 0, lastdot ) + MaterialExt;
|
||||||
|
}
|
||||||
|
|
||||||
return filename + MaterialExt;
|
return filename + MaterialExt;
|
||||||
}
|
}
|
||||||
|
@ -172,8 +173,7 @@ void ObjExporter::WriteHeader(std::ostringstream& out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string ObjExporter::GetMaterialName(unsigned int index)
|
std::string ObjExporter::GetMaterialName(unsigned int index) {
|
||||||
{
|
|
||||||
const aiMaterial* const mat = pScene->mMaterials[index];
|
const aiMaterial* const mat = pScene->mMaterials[index];
|
||||||
if ( nullptr == mat ) {
|
if ( nullptr == mat ) {
|
||||||
static const std::string EmptyStr;
|
static const std::string EmptyStr;
|
||||||
|
@ -191,8 +191,7 @@ std::string ObjExporter::GetMaterialName(unsigned int index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter::WriteMaterialFile()
|
void ObjExporter::WriteMaterialFile() {
|
||||||
{
|
|
||||||
WriteHeader(mOutputMat);
|
WriteHeader(mOutputMat);
|
||||||
|
|
||||||
for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||||
|
@ -310,8 +309,9 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
|
||||||
if (!m.name.empty()) {
|
if (!m.name.empty()) {
|
||||||
mOutput << "g " << m.name << endl;
|
mOutput << "g " << m.name << endl;
|
||||||
}
|
}
|
||||||
if (!noMtl)
|
if ( !noMtl ) {
|
||||||
mOutput << "usemtl " << m.matname << endl;
|
mOutput << "usemtl " << m.matname << endl;
|
||||||
|
}
|
||||||
|
|
||||||
for(const Face& f : m.faces) {
|
for(const Face& f : m.faces) {
|
||||||
mOutput << f.kind << ' ';
|
mOutput << f.kind << ' ';
|
||||||
|
@ -382,7 +382,7 @@ void ObjExporter::colIndexMap::getColors( std::vector<aiColor4D> &colors ) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
|
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
|
||||||
mMeshes.push_back(MeshInstance());
|
mMeshes.push_back(MeshInstance() );
|
||||||
MeshInstance& mesh = mMeshes.back();
|
MeshInstance& mesh = mMeshes.back();
|
||||||
|
|
||||||
mesh.name = std::string( name.data, name.length );
|
mesh.name = std::string( name.data, name.length );
|
||||||
|
@ -436,8 +436,7 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
|
void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) {
|
||||||
{
|
|
||||||
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
|
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
|
||||||
|
|
||||||
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||||
|
|
|
@ -207,30 +207,24 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
|
||||||
|
|
||||||
// Create the root node of the scene
|
// Create the root node of the scene
|
||||||
pScene->mRootNode = new aiNode;
|
pScene->mRootNode = new aiNode;
|
||||||
if ( !pModel->m_ModelName.empty() )
|
if ( !pModel->m_ModelName.empty() ) {
|
||||||
{
|
|
||||||
// Set the name of the scene
|
// Set the name of the scene
|
||||||
pScene->mRootNode->mName.Set(pModel->m_ModelName);
|
pScene->mRootNode->mName.Set(pModel->m_ModelName);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// This is a fatal error, so break down the application
|
// This is a fatal error, so break down the application
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create nodes for the whole scene
|
// Create nodes for the whole scene
|
||||||
std::vector<aiMesh*> MeshArray;
|
std::vector<aiMesh*> MeshArray;
|
||||||
for (size_t index = 0; index < pModel->m_Objects.size(); index++)
|
for (size_t index = 0; index < pModel->m_Objects.size(); ++index ) {
|
||||||
{
|
|
||||||
createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
|
createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create mesh pointer buffer for this scene
|
// Create mesh pointer buffer for this scene
|
||||||
if (pScene->mNumMeshes > 0)
|
if (pScene->mNumMeshes > 0) {
|
||||||
{
|
|
||||||
pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
|
pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
|
||||||
for (size_t index =0; index < MeshArray.size(); index++)
|
for (size_t index =0; index < MeshArray.size(); ++index ) {
|
||||||
{
|
|
||||||
pScene->mMeshes[ index ] = MeshArray[ index ];
|
pScene->mMeshes[ index ] = MeshArray[ index ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +255,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
|
||||||
appendChildToParentNode( pParent, pNode );
|
appendChildToParentNode( pParent, pNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( size_t i=0; i< pObject->m_Meshes.size(); i++ )
|
for ( size_t i=0; i< pObject->m_Meshes.size(); ++i ) {
|
||||||
{
|
|
||||||
unsigned int meshId = pObject->m_Meshes[ i ];
|
unsigned int meshId = pObject->m_Meshes[ i ];
|
||||||
aiMesh *pMesh = createTopology( pModel, pObject, meshId );
|
aiMesh *pMesh = createTopology( pModel, pObject, meshId );
|
||||||
if( pMesh ) {
|
if( pMesh ) {
|
||||||
|
@ -275,8 +268,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create all nodes from the sub-objects stored in the current object
|
// Create all nodes from the sub-objects stored in the current object
|
||||||
if ( !pObject->m_SubObjects.empty() )
|
if ( !pObject->m_SubObjects.empty() ) {
|
||||||
{
|
|
||||||
size_t numChilds = pObject->m_SubObjects.size();
|
size_t numChilds = pObject->m_SubObjects.size();
|
||||||
pNode->mNumChildren = static_cast<unsigned int>( numChilds );
|
pNode->mNumChildren = static_cast<unsigned int>( numChilds );
|
||||||
pNode->mChildren = new aiNode*[ numChilds ];
|
pNode->mChildren = new aiNode*[ numChilds ];
|
||||||
|
@ -286,16 +278,14 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
|
||||||
|
|
||||||
// Set mesh instances into scene- and node-instances
|
// Set mesh instances into scene- and node-instances
|
||||||
const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
|
const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
|
||||||
if ( meshSizeDiff > 0 )
|
if ( meshSizeDiff > 0 ) {
|
||||||
{
|
|
||||||
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
||||||
pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
|
pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
|
for (size_t i = oldMeshSize; i < MeshArray.size(); ++i ) {
|
||||||
{
|
|
||||||
pNode->mMeshes[ index ] = pScene->mNumMeshes;
|
pNode->mMeshes[ index ] = pScene->mNumMeshes;
|
||||||
pScene->mNumMeshes++;
|
pScene->mNumMeshes++;
|
||||||
index++;
|
++index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,11 +303,12 @@ void ObjFileMtlImporter::createMaterial()
|
||||||
// New Material created
|
// New Material created
|
||||||
m_pModel->m_pCurrentMaterial = new ObjFile::Material();
|
m_pModel->m_pCurrentMaterial = new ObjFile::Material();
|
||||||
m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
|
m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
|
||||||
|
m_pModel->m_MaterialLib.push_back( name );
|
||||||
|
m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
|
||||||
|
|
||||||
if (m_pModel->m_pCurrentMesh) {
|
if (m_pModel->m_pCurrentMesh) {
|
||||||
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
|
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
|
||||||
}
|
}
|
||||||
m_pModel->m_MaterialLib.push_back( name );
|
|
||||||
m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
|
|
||||||
} else {
|
} else {
|
||||||
// Use older material
|
// Use older material
|
||||||
m_pModel->m_pCurrentMaterial = (*it).second;
|
m_pModel->m_pCurrentMaterial = (*it).second;
|
||||||
|
|
|
@ -612,13 +612,14 @@ void ObjFileParser::getMaterialLib() {
|
||||||
if ( '/' != *path.rbegin() ) {
|
if ( '/' != *path.rbegin() ) {
|
||||||
path += '/';
|
path += '/';
|
||||||
}
|
}
|
||||||
absName = path + strMatName;
|
absName += path;
|
||||||
|
absName += strMatName;
|
||||||
} else {
|
} else {
|
||||||
absName = strMatName;
|
absName = strMatName;
|
||||||
}
|
}
|
||||||
IOStream *pFile = m_pIO->Open( absName );
|
|
||||||
|
|
||||||
if (!pFile ) {
|
IOStream *pFile = m_pIO->Open( absName );
|
||||||
|
if ( nullptr == pFile ) {
|
||||||
DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
|
DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
|
||||||
std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
|
std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
|
||||||
DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName);
|
DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName);
|
||||||
|
|
|
@ -52,27 +52,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
namespace Ogre {
|
||||||
namespace Ogre
|
|
||||||
{
|
|
||||||
|
|
||||||
/// Returns a lower cased copy of @s.
|
/// Returns a lower cased copy of @s.
|
||||||
static inline std::string ToLower(std::string s)
|
static AI_FORCE_INLINE
|
||||||
|
std::string ToLower(std::string s)
|
||||||
{
|
{
|
||||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
|
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
|
||||||
static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true)
|
static AI_FORCE_INLINE
|
||||||
{
|
bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
|
||||||
if (s.empty() || suffix.empty())
|
if (s.empty() || suffix.empty()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (s.length() < suffix.length()) {
|
||||||
else if (s.length() < suffix.length())
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,48 +78,43 @@ static inline bool EndsWith(const std::string &s, const std::string &suffix, boo
|
||||||
|
|
||||||
size_t len = suffix.length();
|
size_t len = suffix.length();
|
||||||
std::string sSuffix = s.substr(s.length()-len, len);
|
std::string sSuffix = s.substr(s.length()-len, len);
|
||||||
|
|
||||||
return (ASSIMP_stricmp(sSuffix, suffix) == 0);
|
return (ASSIMP_stricmp(sSuffix, suffix) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
||||||
|
|
||||||
/// Trim from start
|
/// Trim from start
|
||||||
static inline std::string &TrimLeft(std::string &s, bool newlines = true)
|
static AI_FORCE_INLINE
|
||||||
{
|
std::string &TrimLeft(std::string &s, bool newlines = true) {
|
||||||
if (!newlines)
|
if (!newlines) {
|
||||||
{
|
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trim from end
|
/// Trim from end
|
||||||
static inline std::string &TrimRight(std::string &s, bool newlines = true)
|
static AI_FORCE_INLINE
|
||||||
{
|
std::string &TrimRight(std::string &s, bool newlines = true) {
|
||||||
if (!newlines)
|
if (!newlines) {
|
||||||
{
|
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trim from both ends
|
/// Trim from both ends
|
||||||
static inline std::string &Trim(std::string &s, bool newlines = true)
|
static AI_FORCE_INLINE
|
||||||
{
|
std::string &Trim(std::string &s, bool newlines = true) {
|
||||||
return TrimLeft(TrimRight(s, newlines), newlines);
|
return TrimLeft(TrimRight(s, newlines), newlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
/// Skips a line from current @ss position until a newline. Returns the skipped part.
|
||||||
static inline std::string SkipLine(std::stringstream &ss)
|
static AI_FORCE_INLINE
|
||||||
{
|
std::string SkipLine(std::stringstream &ss) {
|
||||||
std::string skipped;
|
std::string skipped;
|
||||||
getline(ss, skipped);
|
getline(ss, skipped);
|
||||||
return skipped;
|
return skipped;
|
||||||
|
@ -131,8 +122,8 @@ static inline std::string SkipLine(std::stringstream &ss)
|
||||||
|
|
||||||
/// Skips a line and reads next element from @c ss to @c nextElement.
|
/// Skips a line and reads next element from @c ss to @c nextElement.
|
||||||
/** @return Skipped line content until newline. */
|
/** @return Skipped line content until newline. */
|
||||||
static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement)
|
static AI_FORCE_INLINE
|
||||||
{
|
std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
|
||||||
std::string skipped = SkipLine(ss);
|
std::string skipped = SkipLine(ss);
|
||||||
ss >> nextElement;
|
ss >> nextElement;
|
||||||
return skipped;
|
return skipped;
|
||||||
|
|
|
@ -213,18 +213,18 @@ std::string &OgreXmlSerializer::SkipCurrentNode()
|
||||||
DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
|
DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(;;)
|
for(;;) {
|
||||||
{
|
if (!m_reader->read()) {
|
||||||
if (!m_reader->read())
|
|
||||||
{
|
|
||||||
m_currentNodeName = "";
|
m_currentNodeName = "";
|
||||||
return m_currentNodeName;
|
return m_currentNodeName;
|
||||||
}
|
}
|
||||||
if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END)
|
if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
|
||||||
continue;
|
continue;
|
||||||
else if (std::string(m_reader->getNodeName()) == m_currentNodeName)
|
} else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextNode();
|
return NextNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,17 +303,16 @@ static const char *anZ = "z";
|
||||||
|
|
||||||
// Mesh
|
// Mesh
|
||||||
|
|
||||||
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader)
|
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
|
||||||
{
|
|
||||||
OgreXmlSerializer serializer(reader);
|
OgreXmlSerializer serializer(reader);
|
||||||
|
|
||||||
MeshXml *mesh = new MeshXml();
|
MeshXml *mesh = new MeshXml();
|
||||||
serializer.ReadMesh(mesh);
|
serializer.ReadMesh(mesh);
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadMesh(MeshXml *mesh)
|
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
|
||||||
{
|
|
||||||
if (NextNode() != nnMesh) {
|
if (NextNode() != nnMesh) {
|
||||||
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
|
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
|
||||||
}
|
}
|
||||||
|
@ -835,7 +834,7 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
|
||||||
|
|
||||||
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
|
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
|
||||||
{
|
{
|
||||||
static const aiVector3D zeroVec(0.f, 0.f, 0.f);
|
const aiVector3D zeroVec(0.f, 0.f, 0.f);
|
||||||
|
|
||||||
NextNode();
|
NextNode();
|
||||||
while(m_currentNodeName == nnKeyFrame)
|
while(m_currentNodeName == nnKeyFrame)
|
||||||
|
|
|
@ -221,12 +221,8 @@ static void propId2StdString( Property *prop, std::string &name, std::string &ke
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
OpenGEXImporter::VertexContainer::VertexContainer()
|
OpenGEXImporter::VertexContainer::VertexContainer()
|
||||||
: m_numVerts( 0 )
|
: m_numColors( 0 )
|
||||||
, m_vertices( nullptr )
|
|
||||||
, m_numColors( 0 )
|
|
||||||
, m_colors( nullptr )
|
, m_colors( nullptr )
|
||||||
, m_numNormals( 0 )
|
|
||||||
, m_normals( nullptr )
|
|
||||||
, m_numUVComps()
|
, m_numUVComps()
|
||||||
, m_textureCoords() {
|
, m_textureCoords() {
|
||||||
// empty
|
// empty
|
||||||
|
@ -234,9 +230,7 @@ OpenGEXImporter::VertexContainer::VertexContainer()
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
OpenGEXImporter::VertexContainer::~VertexContainer() {
|
OpenGEXImporter::VertexContainer::~VertexContainer() {
|
||||||
delete[] m_vertices;
|
|
||||||
delete[] m_colors;
|
delete[] m_colors;
|
||||||
delete[] m_normals;
|
|
||||||
|
|
||||||
for(auto &texcoords : m_textureCoords) {
|
for(auto &texcoords : m_textureCoords) {
|
||||||
delete [] texcoords;
|
delete [] texcoords;
|
||||||
|
@ -697,7 +691,8 @@ void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *
|
||||||
void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
|
void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
|
||||||
m_currentMesh = new aiMesh;
|
m_currentMesh = new aiMesh;
|
||||||
const size_t meshidx( m_meshCache.size() );
|
const size_t meshidx( m_meshCache.size() );
|
||||||
m_meshCache.push_back( m_currentMesh );
|
// ownership is transfered but a reference remains in m_currentMesh
|
||||||
|
m_meshCache.emplace_back( m_currentMesh );
|
||||||
|
|
||||||
Property *prop = node->getProperties();
|
Property *prop = node->getProperties();
|
||||||
if( nullptr != prop ) {
|
if( nullptr != prop ) {
|
||||||
|
@ -736,17 +731,22 @@ enum MeshAttribute {
|
||||||
TexCoord
|
TexCoord
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const std::string PosToken = "position";
|
||||||
|
static const std::string ColToken = "color";
|
||||||
|
static const std::string NormalToken = "normal";
|
||||||
|
static const std::string TexCoordToken = "texcoord";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
static MeshAttribute getAttributeByName( const char *attribName ) {
|
static MeshAttribute getAttributeByName( const char *attribName ) {
|
||||||
ai_assert( nullptr != attribName );
|
ai_assert( nullptr != attribName );
|
||||||
|
|
||||||
if ( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) {
|
if ( 0 == strncmp( PosToken.c_str(), attribName, PosToken.size() ) ) {
|
||||||
return Position;
|
return Position;
|
||||||
} else if ( 0 == strncmp( "color", attribName, strlen( "color" ) ) ) {
|
} else if ( 0 == strncmp( ColToken.c_str(), attribName, ColToken.size() ) ) {
|
||||||
return Color;
|
return Color;
|
||||||
} else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) {
|
} else if( 0 == strncmp( NormalToken.c_str(), attribName, NormalToken.size() ) ) {
|
||||||
return Normal;
|
return Normal;
|
||||||
} else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) {
|
} else if( 0 == strncmp( TexCoordToken.c_str(), attribName, TexCoordToken.size() ) ) {
|
||||||
return TexCoord;
|
return TexCoord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,17 +857,15 @@ void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene
|
||||||
const size_t numItems( countDataArrayListItems( vaList ) );
|
const size_t numItems( countDataArrayListItems( vaList ) );
|
||||||
|
|
||||||
if( Position == attribType ) {
|
if( Position == attribType ) {
|
||||||
m_currentVertices.m_numVerts = numItems;
|
m_currentVertices.m_vertices.resize( numItems );
|
||||||
m_currentVertices.m_vertices = new aiVector3D[ numItems ];
|
copyVectorArray( numItems, vaList, m_currentVertices.m_vertices.data() );
|
||||||
copyVectorArray( numItems, vaList, m_currentVertices.m_vertices );
|
|
||||||
} else if ( Color == attribType ) {
|
} else if ( Color == attribType ) {
|
||||||
m_currentVertices.m_numColors = numItems;
|
m_currentVertices.m_numColors = numItems;
|
||||||
m_currentVertices.m_colors = new aiColor4D[ numItems ];
|
m_currentVertices.m_colors = new aiColor4D[ numItems ];
|
||||||
copyColor4DArray( numItems, vaList, m_currentVertices.m_colors );
|
copyColor4DArray( numItems, vaList, m_currentVertices.m_colors );
|
||||||
} else if( Normal == attribType ) {
|
} else if( Normal == attribType ) {
|
||||||
m_currentVertices.m_numNormals = numItems;
|
m_currentVertices.m_normals.resize( numItems );
|
||||||
m_currentVertices.m_normals = new aiVector3D[ numItems ];
|
copyVectorArray( numItems, vaList, m_currentVertices.m_normals.data() );
|
||||||
copyVectorArray( numItems, vaList, m_currentVertices.m_normals );
|
|
||||||
} else if( TexCoord == attribType ) {
|
} else if( TexCoord == attribType ) {
|
||||||
m_currentVertices.m_numUVComps[ 0 ] = numItems;
|
m_currentVertices.m_numUVComps[ 0 ] = numItems;
|
||||||
m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ];
|
m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ];
|
||||||
|
@ -904,7 +902,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
|
||||||
hasColors = true;
|
hasColors = true;
|
||||||
}
|
}
|
||||||
bool hasNormalCoords( false );
|
bool hasNormalCoords( false );
|
||||||
if ( m_currentVertices.m_numNormals > 0 ) {
|
if ( !m_currentVertices.m_normals.empty() ) {
|
||||||
m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ];
|
m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ];
|
||||||
hasNormalCoords = true;
|
hasNormalCoords = true;
|
||||||
}
|
}
|
||||||
|
@ -922,7 +920,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
|
||||||
Value *next( vaList->m_dataList );
|
Value *next( vaList->m_dataList );
|
||||||
for( size_t indices = 0; indices < current.mNumIndices; indices++ ) {
|
for( size_t indices = 0; indices < current.mNumIndices; indices++ ) {
|
||||||
const int idx( next->getUnsignedInt32() );
|
const int idx( next->getUnsignedInt32() );
|
||||||
ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_numVerts );
|
ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_vertices.size() );
|
||||||
ai_assert( index < m_currentMesh->mNumVertices );
|
ai_assert( index < m_currentMesh->mNumVertices );
|
||||||
aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] );
|
aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] );
|
||||||
m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z );
|
m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z );
|
||||||
|
@ -1105,14 +1103,12 @@ void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene * /*pS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const float floatVal( val->getFloat() );
|
const float floatVal( val->getFloat() );
|
||||||
if ( prop->m_value != nullptr ) {
|
if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
|
||||||
if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
|
m_currentCamera->mHorizontalFOV = floatVal;
|
||||||
m_currentCamera->mHorizontalFOV = floatVal;
|
} else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 4 ) ) {
|
||||||
} else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 3 ) ) {
|
m_currentCamera->mClipPlaneNear = floatVal;
|
||||||
m_currentCamera->mClipPlaneNear = floatVal;
|
} else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
|
||||||
} else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
|
m_currentCamera->mClipPlaneFar = floatVal;
|
||||||
m_currentCamera->mClipPlaneFar = floatVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1145,7 +1141,9 @@ void OpenGEXImporter::copyMeshes( aiScene *pScene ) {
|
||||||
|
|
||||||
pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
|
pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
|
||||||
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
|
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
|
||||||
std::copy( m_meshCache.begin(), m_meshCache.end(), pScene->mMeshes );
|
for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
|
||||||
|
pScene->mMeshes[i] = m_meshCache[i].release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -144,12 +144,10 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct VertexContainer {
|
struct VertexContainer {
|
||||||
size_t m_numVerts;
|
std::vector<aiVector3D> m_vertices;
|
||||||
aiVector3D *m_vertices;
|
|
||||||
size_t m_numColors;
|
size_t m_numColors;
|
||||||
aiColor4D *m_colors;
|
aiColor4D *m_colors;
|
||||||
size_t m_numNormals;
|
std::vector<aiVector3D> m_normals;
|
||||||
aiVector3D *m_normals;
|
|
||||||
size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
||||||
aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
|
||||||
|
|
||||||
|
@ -185,7 +183,7 @@ private:
|
||||||
typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap;
|
typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap;
|
||||||
NodeChildMap m_nodeChildMap;
|
NodeChildMap m_nodeChildMap;
|
||||||
|
|
||||||
std::vector<aiMesh*> m_meshCache;
|
std::vector<std::unique_ptr<aiMesh> > m_meshCache;
|
||||||
typedef std::map<std::string, size_t> ReferenceMap;
|
typedef std::map<std::string, size_t> ReferenceMap;
|
||||||
std::map<std::string, size_t> m_mesh2refMap;
|
std::map<std::string, size_t> m_mesh2refMap;
|
||||||
std::map<std::string, size_t> m_material2refMap;
|
std::map<std::string, size_t> m_material2refMap;
|
||||||
|
@ -194,7 +192,7 @@ private:
|
||||||
MetricInfo m_metrics[ MetricInfo::Max ];
|
MetricInfo m_metrics[ MetricInfo::Max ];
|
||||||
aiNode *m_currentNode;
|
aiNode *m_currentNode;
|
||||||
VertexContainer m_currentVertices;
|
VertexContainer m_currentVertices;
|
||||||
aiMesh *m_currentMesh;
|
aiMesh *m_currentMesh; // not owned, target is owned by m_meshCache
|
||||||
aiMaterial *m_currentMaterial;
|
aiMaterial *m_currentMaterial;
|
||||||
aiLight *m_currentLight;
|
aiLight *m_currentLight;
|
||||||
aiCamera *m_currentCamera;
|
aiCamera *m_currentCamera;
|
||||||
|
|
|
@ -148,6 +148,17 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina
|
||||||
<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
|
<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
|
||||||
<< aiGetVersionRevision() << ")" << endl;
|
<< aiGetVersionRevision() << ")" << endl;
|
||||||
|
|
||||||
|
// Look through materials for a diffuse texture, and add it if found
|
||||||
|
for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i )
|
||||||
|
{
|
||||||
|
const aiMaterial* const mat = pScene->mMaterials[i];
|
||||||
|
aiString s;
|
||||||
|
if ( AI_SUCCESS == mat->Get( AI_MATKEY_TEXTURE_DIFFUSE( 0 ), s ) )
|
||||||
|
{
|
||||||
|
mOutput << "comment TextureFile " << s.data << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: probably want to check here rather than just assume something
|
// TODO: probably want to check here rather than just assume something
|
||||||
// definitely not good to always write float even if we might have double precision
|
// definitely not good to always write float even if we might have double precision
|
||||||
|
|
||||||
|
|
|
@ -58,16 +58,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static const aiImporterDesc desc = {
|
||||||
"Stanford Polygon Library (PLY) Importer",
|
"Stanford Polygon Library (PLY) Importer",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
|
aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
"ply"
|
"ply"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,229 +92,188 @@ namespace
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
PLYImporter::PLYImporter()
|
PLYImporter::PLYImporter()
|
||||||
: mBuffer(nullptr)
|
: mBuffer(nullptr)
|
||||||
, pcDOM(nullptr)
|
, pcDOM(nullptr)
|
||||||
, mGeneratedMesh(nullptr){
|
, mGeneratedMesh(nullptr) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
PLYImporter::~PLYImporter() {
|
PLYImporter::~PLYImporter() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||||
{
|
const std::string extension = GetExtension(pFile);
|
||||||
const std::string extension = GetExtension(pFile);
|
|
||||||
|
|
||||||
if (extension == "ply")
|
if ( extension == "ply" ) {
|
||||||
return true;
|
return true;
|
||||||
else if (!extension.length() || checkSig)
|
} else if (!extension.length() || checkSig) {
|
||||||
{
|
if ( !pIOHandler ) {
|
||||||
if (!pIOHandler)return true;
|
return true;
|
||||||
const char* tokens[] = { "ply" };
|
}
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
static const char* tokens[] = { "ply" };
|
||||||
}
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const aiImporterDesc* PLYImporter::GetInfo() const
|
const aiImporterDesc* PLYImporter::GetInfo() const {
|
||||||
{
|
return &desc;
|
||||||
return &desc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static bool isBigEndian(const char* szMe) {
|
static bool isBigEndian(const char* szMe) {
|
||||||
ai_assert(NULL != szMe);
|
ai_assert(NULL != szMe);
|
||||||
|
|
||||||
// binary_little_endian
|
// binary_little_endian
|
||||||
// binary_big_endian
|
// binary_big_endian
|
||||||
bool isBigEndian(false);
|
bool isBigEndian(false);
|
||||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||||
if ( 'l' == *szMe || 'L' == *szMe ) {
|
if ( 'l' == *szMe || 'L' == *szMe ) {
|
||||||
isBigEndian = true;
|
isBigEndian = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if ('b' == *szMe || 'B' == *szMe) {
|
if ('b' == *szMe || 'B' == *szMe) {
|
||||||
isBigEndian = true;
|
isBigEndian = true;
|
||||||
}
|
}
|
||||||
#endif // ! AI_BUILD_BIG_ENDIAN
|
#endif // ! AI_BUILD_BIG_ENDIAN
|
||||||
|
|
||||||
return isBigEndian;
|
return isBigEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void PLYImporter::InternReadFile(const std::string& pFile,
|
void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
||||||
aiScene* pScene, IOSystem* pIOHandler)
|
static const std::string mode = "rb";
|
||||||
{
|
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
|
||||||
static const std::string mode = "rb";
|
if (!fileStream.get()) {
|
||||||
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
|
throw DeadlyImportError("Failed to open file " + pFile + ".");
|
||||||
if (!fileStream.get()) {
|
}
|
||||||
throw DeadlyImportError("Failed to open file " + pFile + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the file-size
|
// Get the file-size
|
||||||
size_t fileSize = fileStream->FileSize();
|
const size_t fileSize( fileStream->FileSize() );
|
||||||
if ( 0 == fileSize ) {
|
if ( 0 == fileSize ) {
|
||||||
throw DeadlyImportError("File " + pFile + " is empty.");
|
throw DeadlyImportError("File " + pFile + " is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
IOStreamBuffer<char> streamedBuffer(1024 * 1024);
|
IOStreamBuffer<char> streamedBuffer(1024 * 1024);
|
||||||
streamedBuffer.open(fileStream.get());
|
streamedBuffer.open(fileStream.get());
|
||||||
|
|
||||||
// the beginning of the file must be PLY - magic, magic
|
// the beginning of the file must be PLY - magic, magic
|
||||||
std::vector<char> headerCheck;
|
std::vector<char> headerCheck;
|
||||||
streamedBuffer.getNextLine(headerCheck);
|
streamedBuffer.getNextLine(headerCheck);
|
||||||
|
|
||||||
if ((headerCheck.size() < 3) ||
|
if ((headerCheck.size() < 3) ||
|
||||||
(headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
|
(headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
|
||||||
(headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
|
(headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
|
||||||
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') )
|
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) {
|
||||||
{
|
streamedBuffer.close();
|
||||||
streamedBuffer.close();
|
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
|
||||||
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char> mBuffer2;
|
std::vector<char> mBuffer2;
|
||||||
streamedBuffer.getNextLine(mBuffer2);
|
streamedBuffer.getNextLine(mBuffer2);
|
||||||
mBuffer = (unsigned char*)&mBuffer2[0];
|
mBuffer = (unsigned char*)&mBuffer2[0];
|
||||||
|
|
||||||
char* szMe = (char*)&this->mBuffer[0];
|
char* szMe = (char*)&this->mBuffer[0];
|
||||||
SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
|
SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
|
||||||
|
|
||||||
// determine the format of the file data and construct the aimesh
|
// determine the format of the file data and construct the aimesh
|
||||||
PLY::DOM sPlyDom;
|
PLY::DOM sPlyDom;
|
||||||
this->pcDOM = &sPlyDom;
|
this->pcDOM = &sPlyDom;
|
||||||
|
|
||||||
if (TokenMatch(szMe, "format", 6)) {
|
if (TokenMatch(szMe, "format", 6)) {
|
||||||
if (TokenMatch(szMe, "ascii", 5)) {
|
if (TokenMatch(szMe, "ascii", 5)) {
|
||||||
SkipLine(szMe, (const char**)&szMe);
|
SkipLine(szMe, (const char**)&szMe);
|
||||||
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this))
|
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
|
||||||
{
|
if (mGeneratedMesh != NULL) {
|
||||||
if (mGeneratedMesh != NULL)
|
delete(mGeneratedMesh);
|
||||||
{
|
mGeneratedMesh = nullptr;
|
||||||
delete(mGeneratedMesh);
|
}
|
||||||
mGeneratedMesh = nullptr;
|
|
||||||
|
streamedBuffer.close();
|
||||||
|
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
|
||||||
|
}
|
||||||
|
} else if (!::strncmp(szMe, "binary_", 7)) {
|
||||||
|
szMe += 7;
|
||||||
|
const bool bIsBE(isBigEndian(szMe));
|
||||||
|
|
||||||
|
// skip the line, parse the rest of the header and build the DOM
|
||||||
|
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
|
||||||
|
if (mGeneratedMesh != NULL) {
|
||||||
|
delete(mGeneratedMesh);
|
||||||
|
mGeneratedMesh = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamedBuffer.close();
|
||||||
|
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mGeneratedMesh != NULL) {
|
||||||
|
delete(mGeneratedMesh);
|
||||||
|
mGeneratedMesh = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamedBuffer.close();
|
||||||
|
throw DeadlyImportError("Invalid .ply file: Unknown file format");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||||
|
if (mGeneratedMesh != NULL) {
|
||||||
|
delete(mGeneratedMesh);
|
||||||
|
mGeneratedMesh = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamedBuffer.close();
|
streamedBuffer.close();
|
||||||
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
|
throw DeadlyImportError("Invalid .ply file: Missing format specification");
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!::strncmp(szMe, "binary_", 7))
|
|
||||||
{
|
|
||||||
szMe += 7;
|
|
||||||
const bool bIsBE(isBigEndian(szMe));
|
|
||||||
|
|
||||||
// skip the line, parse the rest of the header and build the DOM
|
|
||||||
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE))
|
|
||||||
{
|
|
||||||
if (mGeneratedMesh != NULL)
|
|
||||||
{
|
|
||||||
delete(mGeneratedMesh);
|
|
||||||
mGeneratedMesh = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
streamedBuffer.close();
|
|
||||||
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mGeneratedMesh != NULL)
|
|
||||||
{
|
|
||||||
delete(mGeneratedMesh);
|
|
||||||
mGeneratedMesh = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
streamedBuffer.close();
|
|
||||||
throw DeadlyImportError("Invalid .ply file: Unknown file format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
|
||||||
if (mGeneratedMesh != NULL)
|
|
||||||
{
|
|
||||||
delete(mGeneratedMesh);
|
|
||||||
mGeneratedMesh = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//free the file buffer
|
||||||
streamedBuffer.close();
|
streamedBuffer.close();
|
||||||
throw DeadlyImportError("Invalid .ply file: Missing format specification");
|
|
||||||
}
|
|
||||||
|
|
||||||
//free the file buffer
|
if (mGeneratedMesh == NULL) {
|
||||||
streamedBuffer.close();
|
throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
|
||||||
|
|
||||||
if (mGeneratedMesh == NULL)
|
|
||||||
{
|
|
||||||
throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no face list is existing we assume that the vertex
|
|
||||||
// list is containing a list of points
|
|
||||||
bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
|
|
||||||
if (pointsOnly)
|
|
||||||
{
|
|
||||||
if (mGeneratedMesh->mNumVertices < 3)
|
|
||||||
{
|
|
||||||
if (mGeneratedMesh != NULL)
|
|
||||||
{
|
|
||||||
delete(mGeneratedMesh);
|
|
||||||
mGeneratedMesh = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
streamedBuffer.close();
|
|
||||||
throw DeadlyImportError("Invalid .ply file: Not enough "
|
|
||||||
"vertices to build a proper face list. ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
|
// if no face list is existing we assume that the vertex
|
||||||
mGeneratedMesh->mNumFaces = iNum;
|
// list is containing a list of points
|
||||||
mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
|
bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
|
||||||
|
if (pointsOnly) {
|
||||||
for (unsigned int i = 0; i < iNum; ++i)
|
mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
|
||||||
{
|
|
||||||
mGeneratedMesh->mFaces[i].mNumIndices = 3;
|
|
||||||
mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
|
|
||||||
mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
|
|
||||||
mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1;
|
|
||||||
mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// now load a list of all materials
|
// now load a list of all materials
|
||||||
std::vector<aiMaterial*> avMaterials;
|
std::vector<aiMaterial*> avMaterials;
|
||||||
std::string defaultTexture;
|
std::string defaultTexture;
|
||||||
LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
|
LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
|
||||||
|
|
||||||
// now generate the output scene object. Fill the material list
|
// now generate the output scene object. Fill the material list
|
||||||
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||||
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||||
pScene->mMaterials[i] = avMaterials[i];
|
pScene->mMaterials[i] = avMaterials[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the mesh list
|
// fill the mesh list
|
||||||
pScene->mNumMeshes = 1;
|
pScene->mNumMeshes = 1;
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||||
pScene->mMeshes[0] = mGeneratedMesh;
|
pScene->mMeshes[0] = mGeneratedMesh;
|
||||||
mGeneratedMesh = nullptr;
|
mGeneratedMesh = nullptr;
|
||||||
|
|
||||||
// generate a simple node structure
|
// generate a simple node structure
|
||||||
pScene->mRootNode = new aiNode();
|
pScene->mRootNode = new aiNode();
|
||||||
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
||||||
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) {
|
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) {
|
||||||
pScene->mRootNode->mMeshes[i] = i;
|
pScene->mRootNode->mMeshes[i] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) {
|
void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) {
|
||||||
|
@ -521,9 +480,7 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Convert a color component to [0...1]
|
// Convert a color component to [0...1]
|
||||||
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val,
|
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
|
||||||
PLY::EDataType eType)
|
|
||||||
{
|
|
||||||
switch (eType)
|
switch (eType)
|
||||||
{
|
{
|
||||||
case EDT_Float:
|
case EDT_Float:
|
||||||
|
|
|
@ -57,7 +57,6 @@ struct aiMesh;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
|
||||||
using namespace PLY;
|
using namespace PLY;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -1043,71 +1043,91 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
|
||||||
switch (eType)
|
switch (eType)
|
||||||
{
|
{
|
||||||
case EDT_UInt:
|
case EDT_UInt:
|
||||||
out->iUInt = (uint32_t)*((uint32_t*)pCur);
|
{
|
||||||
pCur += 4;
|
uint32_t t;
|
||||||
|
memcpy(&t, pCur, sizeof(uint32_t));
|
||||||
|
pCur += sizeof(uint32_t);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
|
out->iUInt = t;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case EDT_UShort:
|
case EDT_UShort:
|
||||||
{
|
{
|
||||||
uint16_t i = *((uint16_t*)pCur);
|
uint16_t t;
|
||||||
|
memcpy(&t, pCur, sizeof(uint16_t));
|
||||||
|
pCur += sizeof(uint16_t);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap(&i);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
out->iUInt = (uint32_t)i;
|
out->iUInt = t;
|
||||||
pCur += 2;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EDT_UChar:
|
case EDT_UChar:
|
||||||
{
|
{
|
||||||
out->iUInt = (uint32_t)(*((uint8_t*)pCur));
|
uint8_t t;
|
||||||
pCur++;
|
memcpy(&t, pCur, sizeof(uint8_t));
|
||||||
|
pCur += sizeof(uint8_t);
|
||||||
|
out->iUInt = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EDT_Int:
|
case EDT_Int:
|
||||||
out->iInt = *((int32_t*)pCur);
|
{
|
||||||
pCur += 4;
|
int32_t t;
|
||||||
|
memcpy(&t, pCur, sizeof(int32_t));
|
||||||
|
pCur += sizeof(int32_t);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap(&out->iInt);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
|
out->iInt = t;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case EDT_Short:
|
case EDT_Short:
|
||||||
{
|
{
|
||||||
int16_t i = *((int16_t*)pCur);
|
int16_t t;
|
||||||
|
memcpy(&t, pCur, sizeof(int16_t));
|
||||||
|
pCur += sizeof(int16_t);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap(&i);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
out->iInt = (int32_t)i;
|
out->iInt = t;
|
||||||
pCur += 2;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EDT_Char:
|
case EDT_Char:
|
||||||
out->iInt = (int32_t)*((int8_t*)pCur);
|
{
|
||||||
pCur++;
|
int8_t t;
|
||||||
|
memcpy(&t, pCur, sizeof(int8_t));
|
||||||
|
pCur += sizeof(int8_t);
|
||||||
|
out->iInt = t;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case EDT_Float:
|
case EDT_Float:
|
||||||
{
|
{
|
||||||
out->fFloat = *((float*)pCur);
|
float t;
|
||||||
|
memcpy(&t, pCur, sizeof(float));
|
||||||
|
pCur += sizeof(float);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
pCur += 4;
|
out->fFloat = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EDT_Double:
|
case EDT_Double:
|
||||||
{
|
{
|
||||||
out->fDouble = *((double*)pCur);
|
double t;
|
||||||
|
memcpy(&t, pCur, sizeof(double));
|
||||||
|
pCur += sizeof(double);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
|
if (p_bBE)ByteSwap::Swap(&t);
|
||||||
pCur += 8;
|
out->fDouble = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -39,12 +39,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/** @file Defines the helper data structures for importing PLY files */
|
/** @file Defines the helper data structures for importing PLY files */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_PLYFILEHELPER_H_INC
|
#ifndef AI_PLYFILEHELPER_H_INC
|
||||||
#define AI_PLYFILEHELPER_H_INC
|
#define AI_PLYFILEHELPER_H_INC
|
||||||
|
|
||||||
|
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
#include <assimp/IOStreamBuffer.h>
|
#include <assimp/IOStreamBuffer.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -58,8 +57,7 @@ class PLYImporter;
|
||||||
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
|
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
|
||||||
// http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
|
// http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
|
||||||
// http://www.okino.com/conv/exp_ply.htm
|
// http://www.okino.com/conv/exp_ply.htm
|
||||||
namespace PLY
|
namespace PLY {
|
||||||
{
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
|
@ -78,8 +76,7 @@ int8
|
||||||
int16
|
int16
|
||||||
uint8 ... forms are also used
|
uint8 ... forms are also used
|
||||||
*/
|
*/
|
||||||
enum EDataType
|
enum EDataType {
|
||||||
{
|
|
||||||
EDT_Char = 0x0u,
|
EDT_Char = 0x0u,
|
||||||
EDT_UChar,
|
EDT_UChar,
|
||||||
EDT_Short,
|
EDT_Short,
|
||||||
|
@ -98,8 +95,7 @@ enum EDataType
|
||||||
*
|
*
|
||||||
* Semantics define the usage of a property, e.g. x coordinate
|
* Semantics define the usage of a property, e.g. x coordinate
|
||||||
*/
|
*/
|
||||||
enum ESemantic
|
enum ESemantic {
|
||||||
{
|
|
||||||
//! vertex position x coordinate
|
//! vertex position x coordinate
|
||||||
EST_XCoord = 0x0u,
|
EST_XCoord = 0x0u,
|
||||||
//! vertex position x coordinate
|
//! vertex position x coordinate
|
||||||
|
@ -182,15 +178,14 @@ enum ESemantic
|
||||||
*
|
*
|
||||||
* Semantics define the usage of an element, e.g. vertex or material
|
* Semantics define the usage of an element, e.g. vertex or material
|
||||||
*/
|
*/
|
||||||
enum EElementSemantic
|
enum EElementSemantic {
|
||||||
{
|
|
||||||
//! The element is a vertex
|
//! The element is a vertex
|
||||||
EEST_Vertex = 0x0u,
|
EEST_Vertex = 0x0u,
|
||||||
|
|
||||||
//! The element is a face description (index table)
|
//! The element is a face description (index table)
|
||||||
EEST_Face,
|
EEST_Face,
|
||||||
|
|
||||||
//! The element is a tristrip description (index table)
|
//! The element is a triangle-strip description (index table)
|
||||||
EEST_TriStrip,
|
EEST_TriStrip,
|
||||||
|
|
||||||
//! The element is an edge description (ignored)
|
//! The element is an edge description (ignored)
|
||||||
|
@ -211,17 +206,16 @@ enum EElementSemantic
|
||||||
*
|
*
|
||||||
* This can e.g. be a part of the vertex declaration
|
* This can e.g. be a part of the vertex declaration
|
||||||
*/
|
*/
|
||||||
class Property
|
class Property {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
Property()
|
Property()
|
||||||
: eType (EDT_Int),
|
: eType (EDT_Int)
|
||||||
Semantic(),
|
, Semantic()
|
||||||
bIsList(false),
|
, bIsList(false)
|
||||||
eFirstType(EDT_UChar)
|
, eFirstType(EDT_UChar) {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
//! Data type of the property
|
//! Data type of the property
|
||||||
EDataType eType;
|
EDataType eType;
|
||||||
|
@ -260,15 +254,14 @@ public:
|
||||||
* This can e.g. be the vertex declaration. Elements contain a
|
* This can e.g. be the vertex declaration. Elements contain a
|
||||||
* well-defined number of properties.
|
* well-defined number of properties.
|
||||||
*/
|
*/
|
||||||
class Element
|
class Element {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
Element()
|
Element()
|
||||||
: eSemantic (EEST_INVALID)
|
: eSemantic (EEST_INVALID)
|
||||||
, NumOccur(0)
|
, NumOccur(0) {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
//! List of properties assigned to the element
|
//! List of properties assigned to the element
|
||||||
//! std::vector to support operator[]
|
//! std::vector to support operator[]
|
||||||
|
|
|
@ -125,6 +125,9 @@ corresponding preprocessor flag to selectively disable steps.
|
||||||
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
|
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
|
||||||
# include "DeboneProcess.h"
|
# include "DeboneProcess.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||||
|
# include "ScaleProcess.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -136,7 +139,7 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
||||||
// of sequence it is executed. Steps that are added here are not
|
// of sequence it is executed. Steps that are added here are not
|
||||||
// validated - as RegisterPPStep() does - all dependencies must be given.
|
// validated - as RegisterPPStep() does - all dependencies must be given.
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
out.reserve(30);
|
out.reserve(31);
|
||||||
#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
|
#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
|
||||||
out.push_back( new MakeLeftHandedProcess());
|
out.push_back( new MakeLeftHandedProcess());
|
||||||
#endif
|
#endif
|
||||||
|
@ -197,7 +200,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
||||||
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
|
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
|
||||||
out.push_back( new GenFaceNormalsProcess());
|
out.push_back( new GenFaceNormalsProcess());
|
||||||
#endif
|
#endif
|
||||||
|
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||||
|
out.push_back( new ScaleProcess());
|
||||||
|
#endif
|
||||||
// .........................................................................
|
// .........................................................................
|
||||||
// DON'T change the order of these five ..
|
// DON'T change the order of these five ..
|
||||||
// XXX this is actually a design weakness that dates back to the time
|
// XXX this is actually a design weakness that dates back to the time
|
||||||
|
|
|
@ -651,7 +651,8 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
// generate mesh nodes
|
// generate mesh nodes
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
|
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
|
||||||
{
|
{
|
||||||
aiNode* pcNode = *nodes = new aiNode();
|
aiNode* pcNode = new aiNode();
|
||||||
|
*nodes = pcNode;
|
||||||
pcNode->mParent = pScene->mRootNode;
|
pcNode->mParent = pScene->mRootNode;
|
||||||
pcNode->mName = pScene->mMeshes[i]->mName;
|
pcNode->mName = pScene->mMeshes[i]->mName;
|
||||||
|
|
||||||
|
@ -663,7 +664,8 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
// generate light nodes
|
// generate light nodes
|
||||||
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
|
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
|
||||||
{
|
{
|
||||||
aiNode* pcNode = *nodes = new aiNode();
|
aiNode* pcNode = new aiNode();
|
||||||
|
*nodes = pcNode;
|
||||||
pcNode->mParent = pScene->mRootNode;
|
pcNode->mParent = pScene->mRootNode;
|
||||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i);
|
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i);
|
||||||
pScene->mLights[i]->mName = pcNode->mName;
|
pScene->mLights[i]->mName = pcNode->mName;
|
||||||
|
@ -671,7 +673,8 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
// generate camera nodes
|
// generate camera nodes
|
||||||
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
|
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
|
||||||
{
|
{
|
||||||
aiNode* pcNode = *nodes = new aiNode();
|
aiNode* pcNode = new aiNode();
|
||||||
|
*nodes = pcNode;
|
||||||
pcNode->mParent = pScene->mRootNode;
|
pcNode->mParent = pScene->mRootNode;
|
||||||
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i);
|
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i);
|
||||||
pScene->mCameras[i]->mName = pcNode->mName;
|
pScene->mCameras[i]->mName = pcNode->mName;
|
||||||
|
|
|
@ -172,12 +172,16 @@ void STLExporter :: WriteMeshBinary(const aiMesh* m)
|
||||||
}
|
}
|
||||||
nor.Normalize();
|
nor.Normalize();
|
||||||
}
|
}
|
||||||
ai_real nx = nor.x, ny = nor.y, nz = nor.z;
|
// STL binary files use 4-byte floats. This may possibly cause loss of precision
|
||||||
|
// for clients using 8-byte doubles
|
||||||
|
float nx = (float) nor.x;
|
||||||
|
float ny = (float) nor.y;
|
||||||
|
float nz = (float) nor.z;
|
||||||
AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz);
|
AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz);
|
||||||
mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4);
|
mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4);
|
||||||
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||||
const aiVector3D& v = m->mVertices[f.mIndices[a]];
|
const aiVector3D& v = m->mVertices[f.mIndices[a]];
|
||||||
ai_real vx = v.x, vy = v.y, vz = v.z;
|
float vx = (float) v.x, vy = (float) v.y, vz = (float) v.z;
|
||||||
AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz);
|
AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz);
|
||||||
mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4);
|
mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,26 +449,43 @@ bool STLImporter::LoadBinaryFile()
|
||||||
aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||||
aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||||
|
|
||||||
|
typedef aiVector3t<float> aiVector3F;
|
||||||
|
aiVector3F* theVec;
|
||||||
|
aiVector3F theVec3F;
|
||||||
|
|
||||||
for ( unsigned int i = 0; i < pMesh->mNumFaces; ++i ) {
|
for ( unsigned int i = 0; i < pMesh->mNumFaces; ++i ) {
|
||||||
// NOTE: Blender sometimes writes empty normals ... this is not
|
// NOTE: Blender sometimes writes empty normals ... this is not
|
||||||
// our fault ... the RemoveInvalidData helper step should fix that
|
// our fault ... the RemoveInvalidData helper step should fix that
|
||||||
::memcpy( vn, sz, sizeof( aiVector3D ) );
|
|
||||||
sz += sizeof(aiVector3D);
|
// There's one normal for the face in the STL; use it three times
|
||||||
|
// for vertex normals
|
||||||
|
theVec = (aiVector3F*) sz;
|
||||||
|
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
|
||||||
|
vn->x = theVec3F.x; vn->y = theVec3F.y; vn->z = theVec3F.z;
|
||||||
*(vn+1) = *vn;
|
*(vn+1) = *vn;
|
||||||
*(vn+2) = *vn;
|
*(vn+2) = *vn;
|
||||||
|
++theVec;
|
||||||
vn += 3;
|
vn += 3;
|
||||||
|
|
||||||
::memcpy( vp, sz, sizeof( aiVector3D ) );
|
// vertex 1
|
||||||
|
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
|
||||||
|
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
|
||||||
|
++theVec;
|
||||||
++vp;
|
++vp;
|
||||||
sz += sizeof(aiVector3D);
|
|
||||||
|
|
||||||
::memcpy( vp, sz, sizeof( aiVector3D ) );
|
// vertex 2
|
||||||
|
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
|
||||||
|
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
|
||||||
|
++theVec;
|
||||||
++vp;
|
++vp;
|
||||||
sz += sizeof(aiVector3D);
|
|
||||||
|
|
||||||
::memcpy( vp, sz, sizeof( aiVector3D ) );
|
// vertex 3
|
||||||
|
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
|
||||||
|
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
|
||||||
|
++theVec;
|
||||||
++vp;
|
++vp;
|
||||||
sz += sizeof(aiVector3D);
|
|
||||||
|
sz = (const unsigned char*) theVec;
|
||||||
|
|
||||||
uint16_t color = *((uint16_t*)sz);
|
uint16_t color = *((uint16_t*)sz);
|
||||||
sz += 2;
|
sz += 2;
|
||||||
|
|
|
@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
#ifndef ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
|
||||||
|
|
||||||
#include "ScaleProcess.h"
|
#include "ScaleProcess.h"
|
||||||
|
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
@ -86,13 +88,6 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
||||||
|
|
||||||
void ScaleProcess::traverseNodes( aiNode *node ) {
|
void ScaleProcess::traverseNodes( aiNode *node ) {
|
||||||
applyScaling( node );
|
applyScaling( node );
|
||||||
|
|
||||||
/*for ( unsigned int i = 0; i < node->mNumChildren; ++i ) {
|
|
||||||
aiNode *currentNode = currentNode->mChildren[ i ];
|
|
||||||
if ( nullptr != currentNode ) {
|
|
||||||
traverseNodes( currentNode );
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScaleProcess::applyScaling( aiNode *currentNode ) {
|
void ScaleProcess::applyScaling( aiNode *currentNode ) {
|
||||||
|
@ -104,3 +99,5 @@ void ScaleProcess::applyScaling( aiNode *currentNode ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace Assimp
|
} // Namespace Assimp
|
||||||
|
|
||||||
|
#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
|
||||||
|
|
|
@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/SceneCombiner.h>
|
#include <assimp/SceneCombiner.h>
|
||||||
#include <assimp/StringUtils.h>
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
|
#include <assimp/metadata.h>
|
||||||
#include <assimp/Hash.h>
|
#include <assimp/Hash.h>
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
@ -806,8 +807,9 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
|
||||||
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
||||||
if ((*it)->mNormals) {
|
if ((*it)->mNormals) {
|
||||||
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
|
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
|
||||||
|
} else {
|
||||||
|
DefaultLogger::get()->warn( "JoinMeshes: Normals expected but input mesh contains no normals" );
|
||||||
}
|
}
|
||||||
else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
|
|
||||||
pv2 += (*it)->mNumVertices;
|
pv2 += (*it)->mNumVertices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -817,28 +819,29 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
|
||||||
pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
|
pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
|
||||||
aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
|
aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
|
||||||
|
|
||||||
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
||||||
if ((*it)->mTangents) {
|
if ((*it)->mTangents) {
|
||||||
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
|
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
|
||||||
::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
|
::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
|
||||||
|
} else {
|
||||||
|
DefaultLogger::get()->warn( "JoinMeshes: Tangents expected but input mesh contains no tangents" );
|
||||||
}
|
}
|
||||||
else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
|
|
||||||
pv2 += (*it)->mNumVertices;
|
pv2 += (*it)->mNumVertices;
|
||||||
pv2b += (*it)->mNumVertices;
|
pv2b += (*it)->mNumVertices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// copy texture coordinates
|
// copy texture coordinates
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
while ((**begin).HasTextureCoords(n)) {
|
while ((**begin).HasTextureCoords(n)) {
|
||||||
out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
|
out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
|
||||||
|
|
||||||
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
|
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
|
||||||
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
||||||
|
|
||||||
if ((*it)->mTextureCoords[n]) {
|
if ((*it)->mTextureCoords[n]) {
|
||||||
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
|
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
|
||||||
|
} else {
|
||||||
|
DefaultLogger::get()->warn( "JoinMeshes: UVs expected but input mesh contains no UVs" );
|
||||||
}
|
}
|
||||||
else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
|
|
||||||
pv2 += (*it)->mNumVertices;
|
pv2 += (*it)->mNumVertices;
|
||||||
}
|
}
|
||||||
++n;
|
++n;
|
||||||
|
@ -848,11 +851,11 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
|
||||||
while ((**begin).HasVertexColors(n)) {
|
while ((**begin).HasVertexColors(n)) {
|
||||||
aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
|
aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
|
||||||
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
|
||||||
|
|
||||||
if ((*it)->mColors[n]) {
|
if ((*it)->mColors[n]) {
|
||||||
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
|
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
|
||||||
|
} else {
|
||||||
|
DefaultLogger::get()->warn( "JoinMeshes: VCs expected but input mesh contains no VCs" );
|
||||||
}
|
}
|
||||||
else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
|
|
||||||
pv2 += (*it)->mNumVertices;
|
pv2 += (*it)->mNumVertices;
|
||||||
}
|
}
|
||||||
++n;
|
++n;
|
||||||
|
@ -1001,7 +1004,12 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
|
||||||
*_dest = new aiScene();
|
*_dest = new aiScene();
|
||||||
}
|
}
|
||||||
aiScene* dest = *_dest;
|
aiScene* dest = *_dest;
|
||||||
ai_assert(dest);
|
ai_assert(nullptr != dest);
|
||||||
|
|
||||||
|
// copy metadata
|
||||||
|
if ( nullptr != src->mMetaData ) {
|
||||||
|
dest->mMetaData = new aiMetadata( *src->mMetaData );
|
||||||
|
}
|
||||||
|
|
||||||
// copy animations
|
// copy animations
|
||||||
dest->mNumAnimations = src->mNumAnimations;
|
dest->mNumAnimations = src->mNumAnimations;
|
||||||
|
@ -1256,29 +1264,30 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
|
||||||
aiMetadataEntry& out = dest->mValues[i];
|
aiMetadataEntry& out = dest->mValues[i];
|
||||||
out.mType = in.mType;
|
out.mType = in.mType;
|
||||||
switch (dest->mValues[i].mType) {
|
switch (dest->mValues[i].mType) {
|
||||||
case AI_BOOL:
|
case AI_BOOL:
|
||||||
out.mData = new bool(*static_cast<bool*>(in.mData));
|
out.mData = new bool(*static_cast<bool*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_INT32:
|
case AI_INT32:
|
||||||
out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
|
out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_UINT64:
|
case AI_UINT64:
|
||||||
out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
|
out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_FLOAT:
|
case AI_FLOAT:
|
||||||
out.mData = new float(*static_cast<float*>(in.mData));
|
out.mData = new float(*static_cast<float*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_DOUBLE:
|
case AI_DOUBLE:
|
||||||
out.mData = new double(*static_cast<double*>(in.mData));
|
out.mData = new double(*static_cast<double*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_AISTRING:
|
case AI_AISTRING:
|
||||||
out.mData = new aiString(*static_cast<aiString*>(in.mData));
|
out.mData = new aiString(*static_cast<aiString*>(in.mData));
|
||||||
break;
|
break;
|
||||||
case AI_AIVECTOR3D:
|
case AI_AIVECTOR3D:
|
||||||
out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
|
out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,22 +42,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** @file Stuff to deal with aiScene::mPrivate
|
/** @file Stuff to deal with aiScene::mPrivate
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SCENEPRIVATE_H_INCLUDED
|
#ifndef AI_SCENEPRIVATE_H_INCLUDED
|
||||||
#define AI_SCENEPRIVATE_H_INCLUDED
|
#define AI_SCENEPRIVATE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
class Importer;
|
class Importer;
|
||||||
|
|
||||||
struct ScenePrivateData {
|
struct ScenePrivateData {
|
||||||
|
|
||||||
ScenePrivateData()
|
ScenePrivateData()
|
||||||
: mOrigImporter()
|
: mOrigImporter( nullptr )
|
||||||
, mPPStepsApplied()
|
, mPPStepsApplied( 0 )
|
||||||
, mIsCopy()
|
, mIsCopy( false ) {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// Importer that originally loaded the scene though the C-API
|
// Importer that originally loaded the scene though the C-API
|
||||||
// If set, this object is owned by this private data instance.
|
// If set, this object is owned by this private data instance.
|
||||||
|
@ -75,14 +78,24 @@ struct ScenePrivateData {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Access private data stored in the scene
|
// Access private data stored in the scene
|
||||||
inline ScenePrivateData* ScenePriv(aiScene* in) {
|
inline
|
||||||
|
ScenePrivateData* ScenePriv(aiScene* in) {
|
||||||
|
ai_assert( nullptr != in );
|
||||||
|
if ( nullptr == in ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return static_cast<ScenePrivateData*>(in->mPrivate);
|
return static_cast<ScenePrivateData*>(in->mPrivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const ScenePrivateData* ScenePriv(const aiScene* in) {
|
inline
|
||||||
|
const ScenePrivateData* ScenePriv(const aiScene* in) {
|
||||||
|
ai_assert( nullptr != in );
|
||||||
|
if ( nullptr == in ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return static_cast<const ScenePrivateData*>(in->mPrivate);
|
return static_cast<const ScenePrivateData*>(in->mPrivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // Namespace Assimp
|
||||||
|
|
||||||
#endif
|
#endif // AI_SCENEPRIVATE_H_INCLUDED
|
||||||
|
|
|
@ -294,7 +294,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition,
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
// Now start iterating from there until the first position lays outside of the distance range.
|
// Now start iterating from there until the first position lays outside of the distance range.
|
||||||
// Add all positions inside the distance range within the tolerance to the result aray
|
// Add all positions inside the distance range within the tolerance to the result array
|
||||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||||
while( ToBinary(it->mDistance) < maxDistBinary)
|
while( ToBinary(it->mDistance) < maxDistBinary)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "VertexTriangleAdjacency.h"
|
#include "VertexTriangleAdjacency.h"
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -60,8 +59,8 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
||||||
// compute the number of referenced vertices if it wasn't specified by the caller
|
// compute the number of referenced vertices if it wasn't specified by the caller
|
||||||
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
|
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
|
||||||
if (!iNumVertices) {
|
if (!iNumVertices) {
|
||||||
|
|
||||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||||
|
ai_assert( nullptr != pcFace );
|
||||||
ai_assert(3 == pcFace->mNumIndices);
|
ai_assert(3 == pcFace->mNumIndices);
|
||||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
|
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
|
||||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
|
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
|
||||||
|
@ -69,19 +68,18 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->iNumVertices = iNumVertices;
|
mNumVertices = iNumVertices;
|
||||||
|
|
||||||
unsigned int* pi;
|
unsigned int* pi;
|
||||||
|
|
||||||
// allocate storage
|
// allocate storage
|
||||||
if (bComputeNumTriangles) {
|
if (bComputeNumTriangles) {
|
||||||
pi = mLiveTriangles = new unsigned int[iNumVertices+1];
|
pi = mLiveTriangles = new unsigned int[iNumVertices+1];
|
||||||
memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
|
::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||||
mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||||
memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
|
::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||||
mLiveTriangles = NULL; // important, otherwise the d'tor would crash
|
mLiveTriangles = NULL; // important, otherwise the d'tor would crash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +88,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
||||||
*piEnd++ = 0u;
|
*piEnd++ = 0u;
|
||||||
|
|
||||||
// first pass: compute the number of faces referencing each vertex
|
// first pass: compute the number of faces referencing each vertex
|
||||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
|
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||||
{
|
|
||||||
pi[pcFace->mIndices[0]]++;
|
pi[pcFace->mIndices[0]]++;
|
||||||
pi[pcFace->mIndices[1]]++;
|
pi[pcFace->mIndices[1]]++;
|
||||||
pi[pcFace->mIndices[2]]++;
|
pi[pcFace->mIndices[2]]++;
|
||||||
|
|
|
@ -60,10 +60,8 @@ namespace Assimp {
|
||||||
* @note Although it is called #VertexTriangleAdjacency, the current version does also
|
* @note Although it is called #VertexTriangleAdjacency, the current version does also
|
||||||
* support arbitrary polygons. */
|
* support arbitrary polygons. */
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
class ASSIMP_API VertexTriangleAdjacency
|
class ASSIMP_API VertexTriangleAdjacency {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** @brief Construction from an existing index buffer
|
/** @brief Construction from an existing index buffer
|
||||||
* @param pcFaces Index buffer
|
* @param pcFaces Index buffer
|
||||||
|
@ -77,39 +75,30 @@ public:
|
||||||
unsigned int iNumVertices = 0,
|
unsigned int iNumVertices = 0,
|
||||||
bool bComputeNumTriangles = true);
|
bool bComputeNumTriangles = true);
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** @brief Destructor */
|
/** @brief Destructor */
|
||||||
~VertexTriangleAdjacency();
|
~VertexTriangleAdjacency();
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** @brief Get all triangles adjacent to a vertex
|
/** @brief Get all triangles adjacent to a vertex
|
||||||
* @param iVertIndex Index of the vertex
|
* @param iVertIndex Index of the vertex
|
||||||
* @return A pointer to the adjacency list. */
|
* @return A pointer to the adjacency list. */
|
||||||
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const
|
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
|
||||||
{
|
ai_assert(iVertIndex < mNumVertices);
|
||||||
ai_assert(iVertIndex < iNumVertices);
|
|
||||||
return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
|
return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** @brief Get the number of triangles that are referenced by
|
/** @brief Get the number of triangles that are referenced by
|
||||||
* a vertex. This function returns a reference that can be modified
|
* a vertex. This function returns a reference that can be modified
|
||||||
* @param iVertIndex Index of the vertex
|
* @param iVertIndex Index of the vertex
|
||||||
* @return Number of referenced triangles */
|
* @return Number of referenced triangles */
|
||||||
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex)
|
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) {
|
||||||
{
|
ai_assert( iVertIndex < mNumVertices );
|
||||||
ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles);
|
ai_assert( nullptr != mLiveTriangles );
|
||||||
return mLiveTriangles[iVertIndex];
|
return mLiveTriangles[iVertIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
//! Offset table
|
//! Offset table
|
||||||
unsigned int* mOffsetTable;
|
unsigned int* mOffsetTable;
|
||||||
|
|
||||||
|
@ -120,9 +109,9 @@ public:
|
||||||
unsigned int* mLiveTriangles;
|
unsigned int* mLiveTriangles;
|
||||||
|
|
||||||
//! Debug: Number of referenced vertices
|
//! Debug: Number of referenced vertices
|
||||||
unsigned int iNumVertices;
|
unsigned int mNumVertices;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} //! ns Assimp
|
||||||
|
|
||||||
#endif // !! AI_VTADJACENCY_H_INC
|
#endif // !! AI_VTADJACENCY_H_INC
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2018, assimp team
|
Copyright (c) 2006-2018, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -44,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the XFile importer class
|
* @brief Implementation of the XFile importer class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
||||||
|
|
||||||
#include "XFileImporter.h"
|
#include "XFileImporter.h"
|
||||||
|
@ -79,17 +76,19 @@ static const aiImporterDesc desc = {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
XFileImporter::XFileImporter()
|
XFileImporter::XFileImporter()
|
||||||
{}
|
: mBuffer() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
XFileImporter::~XFileImporter()
|
XFileImporter::~XFileImporter() {
|
||||||
{}
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||||
{
|
|
||||||
std::string extension = GetExtension(pFile);
|
std::string extension = GetExtension(pFile);
|
||||||
if(extension == "x") {
|
if(extension == "x") {
|
||||||
return true;
|
return true;
|
||||||
|
@ -104,23 +103,24 @@ bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get file extension list
|
// Get file extension list
|
||||||
const aiImporterDesc* XFileImporter::GetInfo () const
|
const aiImporterDesc* XFileImporter::GetInfo () const {
|
||||||
{
|
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
||||||
{
|
|
||||||
// read file into memory
|
// read file into memory
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||||
if( file.get() == NULL)
|
if ( file.get() == NULL ) {
|
||||||
throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
throw DeadlyImportError( "Failed to open file " + pFile + "." );
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t MinSize = 16;
|
||||||
size_t fileSize = file->FileSize();
|
size_t fileSize = file->FileSize();
|
||||||
if( fileSize < 16)
|
if ( fileSize < MinSize ) {
|
||||||
throw DeadlyImportError( "XFile is too small.");
|
throw DeadlyImportError( "XFile is too small." );
|
||||||
|
}
|
||||||
|
|
||||||
// in the hope that binary files will never start with a BOM ...
|
// in the hope that binary files will never start with a BOM ...
|
||||||
mBuffer.resize( fileSize + 1);
|
mBuffer.resize( fileSize + 1);
|
||||||
|
@ -134,8 +134,9 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
||||||
CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
|
CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
|
||||||
|
|
||||||
// if nothing came from it, report it as error
|
// if nothing came from it, report it as error
|
||||||
if( !pScene->mRootNode)
|
if ( !pScene->mRootNode ) {
|
||||||
throw DeadlyImportError( "XFile is ill-formatted - no content imported.");
|
throw DeadlyImportError( "XFile is ill-formatted - no content imported." );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -146,17 +147,15 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
|
||||||
ConvertMaterials( pScene, pData->mGlobalMaterials);
|
ConvertMaterials( pScene, pData->mGlobalMaterials);
|
||||||
|
|
||||||
// copy nodes, extracting meshes and materials on the way
|
// copy nodes, extracting meshes and materials on the way
|
||||||
pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode);
|
pScene->mRootNode = CreateNodes( pScene, nullptr, pData->mRootNode);
|
||||||
|
|
||||||
// extract animations
|
// extract animations
|
||||||
CreateAnimations( pScene, pData);
|
CreateAnimations( pScene, pData);
|
||||||
|
|
||||||
// read the global meshes that were stored outside of any node
|
// read the global meshes that were stored outside of any node
|
||||||
if( pData->mGlobalMeshes.size() > 0)
|
if( !pData->mGlobalMeshes.empty() ) {
|
||||||
{
|
|
||||||
// create a root node to hold them if there isn't any, yet
|
// create a root node to hold them if there isn't any, yet
|
||||||
if( pScene->mRootNode == NULL)
|
if( pScene->mRootNode == nullptr ) {
|
||||||
{
|
|
||||||
pScene->mRootNode = new aiNode;
|
pScene->mRootNode = new aiNode;
|
||||||
pScene->mRootNode->mName.Set( "$dummy_node");
|
pScene->mRootNode->mName.Set( "$dummy_node");
|
||||||
}
|
}
|
||||||
|
@ -180,8 +179,7 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
|
||||||
flipper.Execute(pScene);
|
flipper.Execute(pScene);
|
||||||
|
|
||||||
// finally: create a dummy material if not material was imported
|
// finally: create a dummy material if not material was imported
|
||||||
if( pScene->mNumMaterials == 0)
|
if( pScene->mNumMaterials == 0) {
|
||||||
{
|
|
||||||
pScene->mNumMaterials = 1;
|
pScene->mNumMaterials = 1;
|
||||||
// create the Material
|
// create the Material
|
||||||
aiMaterial* mat = new aiMaterial;
|
aiMaterial* mat = new aiMaterial;
|
||||||
|
@ -205,10 +203,10 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursively creates scene nodes from the imported hierarchy.
|
// Recursively creates scene nodes from the imported hierarchy.
|
||||||
aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode)
|
aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) {
|
||||||
{
|
if ( !pNode ) {
|
||||||
if( !pNode)
|
return nullptr;
|
||||||
return NULL;
|
}
|
||||||
|
|
||||||
// create node
|
// create node
|
||||||
aiNode* node = new aiNode;
|
aiNode* node = new aiNode;
|
||||||
|
@ -222,13 +220,13 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
|
||||||
CreateMeshes( pScene, node, pNode->mMeshes);
|
CreateMeshes( pScene, node, pNode->mMeshes);
|
||||||
|
|
||||||
// handle childs
|
// handle childs
|
||||||
if( pNode->mChildren.size() > 0)
|
if( !pNode->mChildren.empty() ) {
|
||||||
{
|
|
||||||
node->mNumChildren = (unsigned int)pNode->mChildren.size();
|
node->mNumChildren = (unsigned int)pNode->mChildren.size();
|
||||||
node->mChildren = new aiNode* [node->mNumChildren];
|
node->mChildren = new aiNode* [node->mNumChildren];
|
||||||
|
|
||||||
for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
|
for ( unsigned int a = 0; a < pNode->mChildren.size(); ++a ) {
|
||||||
node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]);
|
node->mChildren[ a ] = CreateNodes( pScene, node, pNode->mChildren[ a ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
@ -236,16 +234,14 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Creates the meshes for the given node.
|
// Creates the meshes for the given node.
|
||||||
void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes)
|
void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) {
|
||||||
{
|
|
||||||
if (pMeshes.empty()) {
|
if (pMeshes.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a mesh for each mesh-material combination in the source node
|
// create a mesh for each mesh-material combination in the source node
|
||||||
std::vector<aiMesh*> meshes;
|
std::vector<aiMesh*> meshes;
|
||||||
for( unsigned int a = 0; a < pMeshes.size(); a++)
|
for( unsigned int a = 0; a < pMeshes.size(); ++a ) {
|
||||||
{
|
|
||||||
XFile::Mesh* sourceMesh = pMeshes[a];
|
XFile::Mesh* sourceMesh = pMeshes[a];
|
||||||
if ( nullptr == sourceMesh ) {
|
if ( nullptr == sourceMesh ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -255,35 +251,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
ConvertMaterials( pScene, sourceMesh->mMaterials);
|
ConvertMaterials( pScene, sourceMesh->mMaterials);
|
||||||
|
|
||||||
unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
|
unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
|
||||||
for( unsigned int b = 0; b < numMaterials; b++)
|
for( unsigned int b = 0; b < numMaterials; ++b ) {
|
||||||
{
|
|
||||||
// collect the faces belonging to this material
|
// collect the faces belonging to this material
|
||||||
std::vector<unsigned int> faces;
|
std::vector<unsigned int> faces;
|
||||||
unsigned int numVertices = 0;
|
unsigned int numVertices = 0;
|
||||||
if( sourceMesh->mFaceMaterials.size() > 0)
|
if( !sourceMesh->mFaceMaterials.empty() ) {
|
||||||
{
|
|
||||||
// if there is a per-face material defined, select the faces with the corresponding material
|
// if there is a per-face material defined, select the faces with the corresponding material
|
||||||
for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++)
|
for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c ) {
|
||||||
{
|
if( sourceMesh->mFaceMaterials[c] == b) {
|
||||||
if( sourceMesh->mFaceMaterials[c] == b)
|
|
||||||
{
|
|
||||||
faces.push_back( c);
|
faces.push_back( c);
|
||||||
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// if there is no per-face material, place everything into one mesh
|
// if there is no per-face material, place everything into one mesh
|
||||||
for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++)
|
for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c ) {
|
||||||
{
|
|
||||||
faces.push_back( c);
|
faces.push_back( c);
|
||||||
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no faces/vertices using this material? strange...
|
// no faces/vertices using this material? strange...
|
||||||
if( numVertices == 0)
|
if ( numVertices == 0 ) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// create a submesh using this material
|
// create a submesh using this material
|
||||||
aiMesh* mesh = new aiMesh;
|
aiMesh* mesh = new aiMesh;
|
||||||
|
@ -291,11 +282,9 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
|
|
||||||
// find the material in the scene's material list. Either own material
|
// find the material in the scene's material list. Either own material
|
||||||
// or referenced material, it should already have a valid index
|
// or referenced material, it should already have a valid index
|
||||||
if( sourceMesh->mFaceMaterials.size() > 0)
|
if( !sourceMesh->mFaceMaterials.empty() ) {
|
||||||
{
|
|
||||||
mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
|
mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
mesh->mMaterialIndex = 0;
|
mesh->mMaterialIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,28 +299,28 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
mesh->mName.Set(sourceMesh->mName);
|
mesh->mName.Set(sourceMesh->mName);
|
||||||
|
|
||||||
// normals?
|
// normals?
|
||||||
if( sourceMesh->mNormals.size() > 0)
|
if ( sourceMesh->mNormals.size() > 0 ) {
|
||||||
mesh->mNormals = new aiVector3D[numVertices];
|
mesh->mNormals = new aiVector3D[ numVertices ];
|
||||||
|
}
|
||||||
// texture coords
|
// texture coords
|
||||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++)
|
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
|
||||||
{
|
if ( !sourceMesh->mTexCoords[ c ].empty() ) {
|
||||||
if( sourceMesh->mTexCoords[c].size() > 0)
|
mesh->mTextureCoords[ c ] = new aiVector3D[ numVertices ];
|
||||||
mesh->mTextureCoords[c] = new aiVector3D[numVertices];
|
}
|
||||||
}
|
}
|
||||||
// vertex colors
|
// vertex colors
|
||||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++)
|
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
|
||||||
{
|
if ( !sourceMesh->mColors[ c ].empty() ) {
|
||||||
if( sourceMesh->mColors[c].size() > 0)
|
mesh->mColors[ c ] = new aiColor4D[ numVertices ];
|
||||||
mesh->mColors[c] = new aiColor4D[numVertices];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now collect the vertex data of all data streams present in the imported mesh
|
// now collect the vertex data of all data streams present in the imported mesh
|
||||||
unsigned int newIndex = 0;
|
unsigned int newIndex( 0 );
|
||||||
std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
|
std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
|
||||||
orgPoints.resize( numVertices, 0);
|
orgPoints.resize( numVertices, 0);
|
||||||
|
|
||||||
for( unsigned int c = 0; c < faces.size(); c++)
|
for( unsigned int c = 0; c < faces.size(); ++c ) {
|
||||||
{
|
|
||||||
unsigned int f = faces[c]; // index of the source face
|
unsigned int f = faces[c]; // index of the source face
|
||||||
const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
|
const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
|
||||||
|
|
||||||
|
@ -341,30 +330,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
df.mIndices = new unsigned int[ df.mNumIndices];
|
df.mIndices = new unsigned int[ df.mNumIndices];
|
||||||
|
|
||||||
// collect vertex data for indices of this face
|
// collect vertex data for indices of this face
|
||||||
for( unsigned int d = 0; d < df.mNumIndices; d++)
|
for( unsigned int d = 0; d < df.mNumIndices; ++d ) {
|
||||||
{
|
|
||||||
df.mIndices[d] = newIndex;
|
df.mIndices[d] = newIndex;
|
||||||
orgPoints[newIndex] = pf.mIndices[d];
|
orgPoints[newIndex] = pf.mIndices[d];
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
|
mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
|
||||||
// Normal, if present
|
// Normal, if present
|
||||||
if( mesh->HasNormals())
|
if ( mesh->HasNormals() ) {
|
||||||
mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]];
|
mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ sourceMesh->mNormFaces[ f ].mIndices[ d ] ];
|
||||||
|
}
|
||||||
|
|
||||||
// texture coord sets
|
// texture coord sets
|
||||||
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++)
|
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e ) {
|
||||||
{
|
if( mesh->HasTextureCoords( e)) {
|
||||||
if( mesh->HasTextureCoords( e))
|
|
||||||
{
|
|
||||||
aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
|
aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
|
||||||
mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
|
mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// vertex color sets
|
// vertex color sets
|
||||||
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++)
|
for ( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e ) {
|
||||||
if( mesh->HasVertexColors( e))
|
if ( mesh->HasVertexColors( e ) ) {
|
||||||
mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
|
mesh->mColors[ e ][ newIndex ] = sourceMesh->mColors[ e ][ pf.mIndices[ d ] ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newIndex++;
|
newIndex++;
|
||||||
}
|
}
|
||||||
|
@ -376,28 +365,29 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
// convert all bones of the source mesh which influence vertices in this newly created mesh
|
// convert all bones of the source mesh which influence vertices in this newly created mesh
|
||||||
const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
|
const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
|
||||||
std::vector<aiBone*> newBones;
|
std::vector<aiBone*> newBones;
|
||||||
for( unsigned int c = 0; c < bones.size(); c++)
|
for( unsigned int c = 0; c < bones.size(); ++c ) {
|
||||||
{
|
|
||||||
const XFile::Bone& obone = bones[c];
|
const XFile::Bone& obone = bones[c];
|
||||||
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
|
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
|
||||||
std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0);
|
std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0);
|
||||||
for( unsigned int d = 0; d < obone.mWeights.size(); d++)
|
for ( unsigned int d = 0; d < obone.mWeights.size(); ++d ) {
|
||||||
oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
|
oldWeights[ obone.mWeights[ d ].mVertex ] = obone.mWeights[ d ].mWeight;
|
||||||
|
}
|
||||||
|
|
||||||
// collect all vertex weights that influence a vertex in the new mesh
|
// collect all vertex weights that influence a vertex in the new mesh
|
||||||
std::vector<aiVertexWeight> newWeights;
|
std::vector<aiVertexWeight> newWeights;
|
||||||
newWeights.reserve( numVertices);
|
newWeights.reserve( numVertices);
|
||||||
for( unsigned int d = 0; d < orgPoints.size(); d++)
|
for( unsigned int d = 0; d < orgPoints.size(); ++d ) {
|
||||||
{
|
|
||||||
// does the new vertex stem from an old vertex which was influenced by this bone?
|
// does the new vertex stem from an old vertex which was influenced by this bone?
|
||||||
ai_real w = oldWeights[orgPoints[d]];
|
ai_real w = oldWeights[orgPoints[d]];
|
||||||
if( w > 0.0)
|
if ( w > 0.0 ) {
|
||||||
newWeights.push_back( aiVertexWeight( d, w));
|
newWeights.push_back( aiVertexWeight( d, w ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the bone has no weights in the newly created mesh, ignore it
|
// if the bone has no weights in the newly created mesh, ignore it
|
||||||
if( newWeights.size() == 0)
|
if ( newWeights.empty() ) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// create
|
// create
|
||||||
aiBone* nbone = new aiBone;
|
aiBone* nbone = new aiBone;
|
||||||
|
@ -407,14 +397,14 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
nbone->mOffsetMatrix = obone.mOffsetMatrix;
|
nbone->mOffsetMatrix = obone.mOffsetMatrix;
|
||||||
nbone->mNumWeights = (unsigned int)newWeights.size();
|
nbone->mNumWeights = (unsigned int)newWeights.size();
|
||||||
nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
|
nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
|
||||||
for( unsigned int d = 0; d < newWeights.size(); d++)
|
for ( unsigned int d = 0; d < newWeights.size(); ++d ) {
|
||||||
nbone->mWeights[d] = newWeights[d];
|
nbone->mWeights[ d ] = newWeights[ d ];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the bones in the mesh
|
// store the bones in the mesh
|
||||||
mesh->mNumBones = (unsigned int)newBones.size();
|
mesh->mNumBones = (unsigned int)newBones.size();
|
||||||
if( newBones.size() > 0)
|
if( !newBones.empty()) {
|
||||||
{
|
|
||||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||||
std::copy( newBones.begin(), newBones.end(), mesh->mBones);
|
std::copy( newBones.begin(), newBones.end(), mesh->mBones);
|
||||||
}
|
}
|
||||||
|
@ -424,8 +414,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
// reallocate scene mesh array to be large enough
|
// reallocate scene mesh array to be large enough
|
||||||
aiMesh** prevArray = pScene->mMeshes;
|
aiMesh** prevArray = pScene->mMeshes;
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
|
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
|
||||||
if( prevArray)
|
if( prevArray) {
|
||||||
{
|
|
||||||
memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
|
memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
|
||||||
delete [] prevArray;
|
delete [] prevArray;
|
||||||
}
|
}
|
||||||
|
@ -435,8 +424,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||||
|
|
||||||
// store all meshes in the mesh library of the scene and store their indices in the node
|
// store all meshes in the mesh library of the scene and store their indices in the node
|
||||||
for( unsigned int a = 0; a < meshes.size(); a++)
|
for( unsigned int a = 0; a < meshes.size(); a++) {
|
||||||
{
|
|
||||||
pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
|
pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
|
||||||
pNode->mMeshes[a] = pScene->mNumMeshes;
|
pNode->mMeshes[a] = pScene->mNumMeshes;
|
||||||
pScene->mNumMeshes++;
|
pScene->mNumMeshes++;
|
||||||
|
@ -445,16 +433,15 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Converts the animations from the given imported data and creates them in the scene.
|
// Converts the animations from the given imported data and creates them in the scene.
|
||||||
void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData)
|
void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) {
|
||||||
{
|
|
||||||
std::vector<aiAnimation*> newAnims;
|
std::vector<aiAnimation*> newAnims;
|
||||||
|
|
||||||
for( unsigned int a = 0; a < pData->mAnims.size(); a++)
|
for( unsigned int a = 0; a < pData->mAnims.size(); ++a ) {
|
||||||
{
|
|
||||||
const XFile::Animation* anim = pData->mAnims[a];
|
const XFile::Animation* anim = pData->mAnims[a];
|
||||||
// some exporters mock me with empty animation tags.
|
// some exporters mock me with empty animation tags.
|
||||||
if( anim->mAnims.size() == 0)
|
if ( anim->mAnims.empty() ) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// create a new animation to hold the data
|
// create a new animation to hold the data
|
||||||
aiAnimation* nanim = new aiAnimation;
|
aiAnimation* nanim = new aiAnimation;
|
||||||
|
@ -466,15 +453,14 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
|
||||||
nanim->mNumChannels = (unsigned int)anim->mAnims.size();
|
nanim->mNumChannels = (unsigned int)anim->mAnims.size();
|
||||||
nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
|
nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
|
||||||
|
|
||||||
for( unsigned int b = 0; b < anim->mAnims.size(); b++)
|
for( unsigned int b = 0; b < anim->mAnims.size(); ++b ) {
|
||||||
{
|
|
||||||
const XFile::AnimBone* bone = anim->mAnims[b];
|
const XFile::AnimBone* bone = anim->mAnims[b];
|
||||||
aiNodeAnim* nbone = new aiNodeAnim;
|
aiNodeAnim* nbone = new aiNodeAnim;
|
||||||
nbone->mNodeName.Set( bone->mBoneName);
|
nbone->mNodeName.Set( bone->mBoneName);
|
||||||
nanim->mChannels[b] = nbone;
|
nanim->mChannels[b] = nbone;
|
||||||
|
|
||||||
// keyframes are given as combined transformation matrix keys
|
// keyframes are given as combined transformation matrix keys
|
||||||
if( bone->mTrafoKeys.size() > 0)
|
if( !bone->mTrafoKeys.empty() )
|
||||||
{
|
{
|
||||||
nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
|
nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
|
||||||
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
||||||
|
@ -483,8 +469,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
|
||||||
nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
|
nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
|
||||||
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
||||||
|
|
||||||
for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++)
|
for( unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
|
||||||
{
|
|
||||||
// deconstruct each matrix into separate position, rotation and scaling
|
// deconstruct each matrix into separate position, rotation and scaling
|
||||||
double time = bone->mTrafoKeys[c].mTime;
|
double time = bone->mTrafoKeys[c].mTime;
|
||||||
aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
|
aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
|
||||||
|
@ -516,13 +501,11 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
|
||||||
|
|
||||||
// longest lasting key sequence determines duration
|
// longest lasting key sequence determines duration
|
||||||
nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
|
nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// separate key sequences for position, rotation, scaling
|
// separate key sequences for position, rotation, scaling
|
||||||
nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
|
nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
|
||||||
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
||||||
for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++)
|
for( unsigned int c = 0; c < nbone->mNumPositionKeys; ++c ) {
|
||||||
{
|
|
||||||
aiVector3D pos = bone->mPosKeys[c].mValue;
|
aiVector3D pos = bone->mPosKeys[c].mValue;
|
||||||
|
|
||||||
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
|
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
|
||||||
|
@ -532,8 +515,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
|
||||||
// rotation
|
// rotation
|
||||||
nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
|
nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
|
||||||
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
||||||
for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++)
|
for( unsigned int c = 0; c < nbone->mNumRotationKeys; ++c ) {
|
||||||
{
|
|
||||||
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
|
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
|
||||||
|
|
||||||
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
|
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
|
||||||
|
@ -573,56 +555,51 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
|
||||||
void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
|
void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
|
||||||
{
|
{
|
||||||
// count the non-referrer materials in the array
|
// count the non-referrer materials in the array
|
||||||
unsigned int numNewMaterials = 0;
|
unsigned int numNewMaterials( 0 );
|
||||||
for( unsigned int a = 0; a < pMaterials.size(); a++)
|
for ( unsigned int a = 0; a < pMaterials.size(); ++a ) {
|
||||||
if( !pMaterials[a].mIsReference)
|
if ( !pMaterials[ a ].mIsReference ) {
|
||||||
numNewMaterials++;
|
++numNewMaterials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// resize the scene's material list to offer enough space for the new materials
|
// resize the scene's material list to offer enough space for the new materials
|
||||||
if( numNewMaterials > 0 )
|
if( numNewMaterials > 0 ) {
|
||||||
{
|
aiMaterial** prevMats = pScene->mMaterials;
|
||||||
aiMaterial** prevMats = pScene->mMaterials;
|
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
|
if( nullptr != prevMats) {
|
||||||
if( prevMats)
|
::memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
|
||||||
{
|
delete [] prevMats;
|
||||||
memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
|
}
|
||||||
delete [] prevMats;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert all the materials given in the array
|
// convert all the materials given in the array
|
||||||
for( unsigned int a = 0; a < pMaterials.size(); a++)
|
for( unsigned int a = 0; a < pMaterials.size(); ++a ) {
|
||||||
{
|
|
||||||
XFile::Material& oldMat = pMaterials[a];
|
XFile::Material& oldMat = pMaterials[a];
|
||||||
if( oldMat.mIsReference)
|
if( oldMat.mIsReference) {
|
||||||
{
|
// find the material it refers to by name, and store its index
|
||||||
// find the material it refers to by name, and store its index
|
for( size_t a = 0; a < pScene->mNumMaterials; ++a ) {
|
||||||
for( size_t a = 0; a < pScene->mNumMaterials; ++a )
|
aiString name;
|
||||||
{
|
pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
|
||||||
aiString name;
|
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
|
||||||
pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
|
oldMat.sceneIndex = a;
|
||||||
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 )
|
break;
|
||||||
{
|
}
|
||||||
oldMat.sceneIndex = a;
|
}
|
||||||
break;
|
|
||||||
|
if( oldMat.sceneIndex == SIZE_MAX ) {
|
||||||
|
DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" );
|
||||||
|
oldMat.sceneIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if( oldMat.sceneIndex == SIZE_MAX )
|
|
||||||
{
|
|
||||||
DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" );
|
|
||||||
oldMat.sceneIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
aiMaterial* mat = new aiMaterial;
|
aiMaterial* mat = new aiMaterial;
|
||||||
aiString name;
|
aiString name;
|
||||||
name.Set( oldMat.mName);
|
name.Set( oldMat.mName);
|
||||||
mat->AddProperty( &name, AI_MATKEY_NAME);
|
mat->AddProperty( &name, AI_MATKEY_NAME);
|
||||||
|
|
||||||
// Shading model: hardcoded to PHONG, there is no such information in an XFile
|
// Shading model: hard-coded to PHONG, there is no such information in an XFile
|
||||||
// FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
|
// FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
|
||||||
// for some models in the SDK (e.g. good old tiny.x)
|
// for some models in the SDK (e.g. good old tiny.x)
|
||||||
int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
|
int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
|
||||||
|
@ -630,8 +607,8 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
|
||||||
|
|
||||||
mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||||
// material colours
|
// material colours
|
||||||
// Unclear: there's no ambient colour, but emissive. What to put for ambient?
|
// Unclear: there's no ambient colour, but emissive. What to put for ambient?
|
||||||
// Probably nothing at all, let the user select a suitable default.
|
// Probably nothing at all, let the user select a suitable default.
|
||||||
mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||||
mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||||
|
@ -639,36 +616,33 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
|
||||||
|
|
||||||
|
|
||||||
// texture, if there is one
|
// texture, if there is one
|
||||||
if (1 == oldMat.mTextures.size())
|
if (1 == oldMat.mTextures.size() ) {
|
||||||
{
|
|
||||||
const XFile::TexEntry& otex = oldMat.mTextures.back();
|
const XFile::TexEntry& otex = oldMat.mTextures.back();
|
||||||
if (otex.mName.length())
|
if (otex.mName.length()) {
|
||||||
{
|
|
||||||
// if there is only one texture assume it contains the diffuse color
|
// if there is only one texture assume it contains the diffuse color
|
||||||
aiString tex( otex.mName);
|
aiString tex( otex.mName);
|
||||||
if( otex.mIsNormalMap)
|
if ( otex.mIsNormalMap ) {
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(0));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) );
|
||||||
else
|
} else {
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise ... try to search for typical strings in the
|
// Otherwise ... try to search for typical strings in the
|
||||||
// texture's file name like 'bump' or 'diffuse'
|
// texture's file name like 'bump' or 'diffuse'
|
||||||
unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
|
unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
|
||||||
for( unsigned int b = 0; b < oldMat.mTextures.size(); b++)
|
for( unsigned int b = 0; b < oldMat.mTextures.size(); ++b ) {
|
||||||
{
|
|
||||||
const XFile::TexEntry& otex = oldMat.mTextures[b];
|
const XFile::TexEntry& otex = oldMat.mTextures[b];
|
||||||
std::string sz = otex.mName;
|
std::string sz = otex.mName;
|
||||||
if (!sz.length())continue;
|
if ( !sz.length() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// find the file name
|
// find the file name
|
||||||
//const size_t iLen = sz.length();
|
|
||||||
std::string::size_type s = sz.find_last_of("\\/");
|
std::string::size_type s = sz.find_last_of("\\/");
|
||||||
if (std::string::npos == s)
|
if ( std::string::npos == s ) {
|
||||||
s = 0;
|
s = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// cut off the file extension
|
// cut off the file extension
|
||||||
std::string::size_type sExt = sz.find_last_of('.');
|
std::string::size_type sExt = sz.find_last_of('.');
|
||||||
|
@ -677,36 +651,27 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to lower case for easier comparison
|
// convert to lower case for easier comparison
|
||||||
for( unsigned int c = 0; c < sz.length(); c++)
|
for ( unsigned int c = 0; c < sz.length(); ++c ) {
|
||||||
if( isalpha( sz[c]))
|
if ( isalpha( sz[ c ] ) ) {
|
||||||
sz[c] = tolower( sz[c]);
|
sz[ c ] = tolower( sz[ c ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Place texture filename property under the corresponding name
|
// Place texture filename property under the corresponding name
|
||||||
aiString tex( oldMat.mTextures[b].mName);
|
aiString tex( oldMat.mTextures[b].mName);
|
||||||
|
|
||||||
// bump map
|
// bump map
|
||||||
if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s))
|
if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
|
||||||
{
|
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
|
||||||
} else
|
} else if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) {
|
||||||
if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
|
|
||||||
{
|
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
|
||||||
} else
|
} else if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) {
|
||||||
if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
|
|
||||||
{
|
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
|
||||||
} else
|
} else if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) {
|
||||||
if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
|
|
||||||
{
|
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
|
||||||
} else
|
} else if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) {
|
||||||
if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
|
|
||||||
{
|
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// Assume it is a diffuse texture
|
// Assume it is a diffuse texture
|
||||||
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
|
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,59 +87,60 @@ static void dummy_free (void* /*opaque*/, void* address) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor. Creates a data structure out of the XFile given in the memory block.
|
// Constructor. Creates a data structure out of the XFile given in the memory block.
|
||||||
XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
||||||
{
|
: mMajorVersion( 0 )
|
||||||
mMajorVersion = mMinorVersion = 0;
|
, mMinorVersion( 0 )
|
||||||
mIsBinaryFormat = false;
|
, mIsBinaryFormat( false )
|
||||||
mBinaryNumCount = 0;
|
, mBinaryNumCount( 0 )
|
||||||
P = End = NULL;
|
, mP( nullptr )
|
||||||
mLineNumber = 0;
|
, mEnd( nullptr )
|
||||||
mScene = NULL;
|
, mLineNumber( 0 )
|
||||||
|
, mScene( nullptr ) {
|
||||||
// vector to store uncompressed file for INFLATE'd X files
|
// vector to store uncompressed file for INFLATE'd X files
|
||||||
std::vector<char> uncompressed;
|
std::vector<char> uncompressed;
|
||||||
|
|
||||||
// set up memory pointers
|
// set up memory pointers
|
||||||
P = &pBuffer.front();
|
mP = &pBuffer.front();
|
||||||
End = P + pBuffer.size() - 1;
|
mEnd = mP + pBuffer.size() - 1;
|
||||||
|
|
||||||
// check header
|
// check header
|
||||||
if( strncmp( P, "xof ", 4) != 0)
|
if ( 0 != strncmp( mP, "xof ", 4 ) ) {
|
||||||
throw DeadlyImportError( "Header mismatch, file is not an XFile.");
|
throw DeadlyImportError( "Header mismatch, file is not an XFile." );
|
||||||
|
}
|
||||||
|
|
||||||
// read version. It comes in a four byte format such as "0302"
|
// read version. It comes in a four byte format such as "0302"
|
||||||
mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48);
|
mMajorVersion = (unsigned int)(mP[4] - 48) * 10 + (unsigned int)(mP[5] - 48);
|
||||||
mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48);
|
mMinorVersion = (unsigned int)(mP[6] - 48) * 10 + (unsigned int)(mP[7] - 48);
|
||||||
|
|
||||||
bool compressed = false;
|
bool compressed = false;
|
||||||
|
|
||||||
// txt - pure ASCII text format
|
// txt - pure ASCII text format
|
||||||
if( strncmp( P + 8, "txt ", 4) == 0)
|
if( strncmp( mP + 8, "txt ", 4) == 0)
|
||||||
mIsBinaryFormat = false;
|
mIsBinaryFormat = false;
|
||||||
|
|
||||||
// bin - Binary format
|
// bin - Binary format
|
||||||
else if( strncmp( P + 8, "bin ", 4) == 0)
|
else if( strncmp( mP + 8, "bin ", 4) == 0)
|
||||||
mIsBinaryFormat = true;
|
mIsBinaryFormat = true;
|
||||||
|
|
||||||
// tzip - Inflate compressed text format
|
// tzip - Inflate compressed text format
|
||||||
else if( strncmp( P + 8, "tzip", 4) == 0)
|
else if( strncmp( mP + 8, "tzip", 4) == 0)
|
||||||
{
|
{
|
||||||
mIsBinaryFormat = false;
|
mIsBinaryFormat = false;
|
||||||
compressed = true;
|
compressed = true;
|
||||||
}
|
}
|
||||||
// bzip - Inflate compressed binary format
|
// bzip - Inflate compressed binary format
|
||||||
else if( strncmp( P + 8, "bzip", 4) == 0)
|
else if( strncmp( mP + 8, "bzip", 4) == 0)
|
||||||
{
|
{
|
||||||
mIsBinaryFormat = true;
|
mIsBinaryFormat = true;
|
||||||
compressed = true;
|
compressed = true;
|
||||||
}
|
}
|
||||||
else ThrowException( format() << "Unsupported xfile format '" <<
|
else ThrowException( format() << "Unsupported xfile format '" <<
|
||||||
P[8] << P[9] << P[10] << P[11] << "'");
|
mP[8] << mP[9] << mP[10] << mP[11] << "'");
|
||||||
|
|
||||||
// float size
|
// float size
|
||||||
mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000
|
mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000
|
||||||
+ (unsigned int)(P[13] - 48) * 100
|
+ (unsigned int)(mP[13] - 48) * 100
|
||||||
+ (unsigned int)(P[14] - 48) * 10
|
+ (unsigned int)(mP[14] - 48) * 10
|
||||||
+ (unsigned int)(P[15] - 48);
|
+ (unsigned int)(mP[15] - 48);
|
||||||
|
|
||||||
if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
|
if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
|
||||||
ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." );
|
ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." );
|
||||||
|
@ -147,7 +148,7 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
||||||
// The x format specifies size in bits, but we work in bytes
|
// The x format specifies size in bits, but we work in bytes
|
||||||
mBinaryFloatSize /= 8;
|
mBinaryFloatSize /= 8;
|
||||||
|
|
||||||
P += 16;
|
mP += 16;
|
||||||
|
|
||||||
// If this is a compressed X file, apply the inflate algorithm to it
|
// If this is a compressed X file, apply the inflate algorithm to it
|
||||||
if (compressed)
|
if (compressed)
|
||||||
|
@ -186,13 +187,13 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
||||||
::inflateInit2(&stream, -MAX_WBITS);
|
::inflateInit2(&stream, -MAX_WBITS);
|
||||||
|
|
||||||
// skip unknown data (checksum, flags?)
|
// skip unknown data (checksum, flags?)
|
||||||
P += 6;
|
mP += 6;
|
||||||
|
|
||||||
// First find out how much storage we'll need. Count sections.
|
// First find out how much storage we'll need. Count sections.
|
||||||
const char* P1 = P;
|
const char* P1 = mP;
|
||||||
unsigned int est_out = 0;
|
unsigned int est_out = 0;
|
||||||
|
|
||||||
while (P1 + 3 < End)
|
while (P1 + 3 < mEnd)
|
||||||
{
|
{
|
||||||
// read next offset
|
// read next offset
|
||||||
uint16_t ofs = *((uint16_t*)P1);
|
uint16_t ofs = *((uint16_t*)P1);
|
||||||
|
@ -216,18 +217,18 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
||||||
// Allocate storage and terminating zero and do the actual uncompressing
|
// Allocate storage and terminating zero and do the actual uncompressing
|
||||||
uncompressed.resize(est_out + 1);
|
uncompressed.resize(est_out + 1);
|
||||||
char* out = &uncompressed.front();
|
char* out = &uncompressed.front();
|
||||||
while (P + 3 < End)
|
while (mP + 3 < mEnd)
|
||||||
{
|
{
|
||||||
uint16_t ofs = *((uint16_t*)P);
|
uint16_t ofs = *((uint16_t*)mP);
|
||||||
AI_SWAP2(ofs);
|
AI_SWAP2(ofs);
|
||||||
P += 4;
|
mP += 4;
|
||||||
|
|
||||||
if (P + ofs > End + 2) {
|
if (mP + ofs > mEnd + 2) {
|
||||||
throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
|
throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
|
||||||
}
|
}
|
||||||
|
|
||||||
// push data to the stream
|
// push data to the stream
|
||||||
stream.next_in = (Bytef*)P;
|
stream.next_in = (Bytef*)mP;
|
||||||
stream.avail_in = ofs;
|
stream.avail_in = ofs;
|
||||||
stream.next_out = (Bytef*)out;
|
stream.next_out = (Bytef*)out;
|
||||||
stream.avail_out = MSZIP_BLOCK;
|
stream.avail_out = MSZIP_BLOCK;
|
||||||
|
@ -242,15 +243,15 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
||||||
|
|
||||||
// and advance to the next offset
|
// and advance to the next offset
|
||||||
out += MSZIP_BLOCK - stream.avail_out;
|
out += MSZIP_BLOCK - stream.avail_out;
|
||||||
P += ofs;
|
mP += ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// terminate zlib
|
// terminate zlib
|
||||||
::inflateEnd(&stream);
|
::inflateEnd(&stream);
|
||||||
|
|
||||||
// ok, update pointers to point to the uncompressed file data
|
// ok, update pointers to point to the uncompressed file data
|
||||||
P = &uncompressed[0];
|
mP = &uncompressed[0];
|
||||||
End = out;
|
mEnd = out;
|
||||||
|
|
||||||
// FIXME: we don't need the compressed data anymore, could release
|
// FIXME: we don't need the compressed data anymore, could release
|
||||||
// it already for better memory usage. Consider breaking const-co.
|
// it already for better memory usage. Consider breaking const-co.
|
||||||
|
@ -465,12 +466,11 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
|
||||||
// read position faces
|
// read position faces
|
||||||
unsigned int numPosFaces = ReadInt();
|
unsigned int numPosFaces = ReadInt();
|
||||||
pMesh->mPosFaces.resize( numPosFaces);
|
pMesh->mPosFaces.resize( numPosFaces);
|
||||||
for( unsigned int a = 0; a < numPosFaces; a++)
|
for( unsigned int a = 0; a < numPosFaces; ++a) {
|
||||||
{
|
|
||||||
// read indices
|
// read indices
|
||||||
unsigned int numIndices = ReadInt();
|
unsigned int numIndices = ReadInt();
|
||||||
Face& face = pMesh->mPosFaces[a];
|
Face& face = pMesh->mPosFaces[a];
|
||||||
for (unsigned int b = 0; b < numIndices; b++) {
|
for (unsigned int b = 0; b < numIndices; ++b) {
|
||||||
face.mIndices.push_back( ReadInt() );
|
face.mIndices.push_back( ReadInt() );
|
||||||
}
|
}
|
||||||
TestForSeparator();
|
TestForSeparator();
|
||||||
|
@ -478,11 +478,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
|
||||||
|
|
||||||
// here, other data objects may follow
|
// here, other data objects may follow
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while ( running )
|
while ( running ) {
|
||||||
{
|
|
||||||
std::string objectName = GetNextToken();
|
std::string objectName = GetNextToken();
|
||||||
|
|
||||||
if( objectName.size() == 0)
|
if( objectName.empty() )
|
||||||
ThrowException( "Unexpected end of file while parsing mesh structure");
|
ThrowException( "Unexpected end of file while parsing mesh structure");
|
||||||
else
|
else
|
||||||
if( objectName == "}")
|
if( objectName == "}")
|
||||||
|
@ -517,8 +516,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh)
|
void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) {
|
||||||
{
|
if ( nullptr == pMesh ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
readHeadOfDataObject();
|
readHeadOfDataObject();
|
||||||
|
|
||||||
std::string transformNodeName;
|
std::string transformNodeName;
|
||||||
|
@ -647,8 +648,8 @@ void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
|
||||||
if( !mIsBinaryFormat)
|
if( !mIsBinaryFormat)
|
||||||
{
|
{
|
||||||
FindNextNoneWhiteSpace();
|
FindNextNoneWhiteSpace();
|
||||||
if( *P == ';' || *P == ',')
|
if( *mP == ';' || *mP == ',')
|
||||||
P++;
|
mP++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,8 +679,8 @@ void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
|
||||||
// commented out version check, as version 03.03 exported from blender also has 2 semicolons
|
// commented out version check, as version 03.03 exported from blender also has 2 semicolons
|
||||||
if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
|
if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
|
||||||
{
|
{
|
||||||
if(P < End && *P == ';')
|
if(mP < mEnd && *mP == ';')
|
||||||
++P;
|
++mP;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there was only a single material index, replicate it on all faces
|
// if there was only a single material index, replicate it on all faces
|
||||||
|
@ -1029,12 +1030,12 @@ void XFileParser::TestForSeparator()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FindNextNoneWhiteSpace();
|
FindNextNoneWhiteSpace();
|
||||||
if( P >= End)
|
if( mP >= mEnd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// test and skip
|
// test and skip
|
||||||
if( *P == ';' || *P == ',')
|
if( *mP == ';' || *mP == ',')
|
||||||
P++;
|
mP++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1046,62 +1047,73 @@ void XFileParser::readHeadOfDataObject( std::string* poName)
|
||||||
if( poName)
|
if( poName)
|
||||||
*poName = nameOrBrace;
|
*poName = nameOrBrace;
|
||||||
|
|
||||||
if( GetNextToken() != "{")
|
if ( GetNextToken() != "{" ) {
|
||||||
ThrowException( "Opening brace expected.");
|
delete mScene;
|
||||||
|
ThrowException( "Opening brace expected." );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string XFileParser::GetNextToken()
|
std::string XFileParser::GetNextToken() {
|
||||||
{
|
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
||||||
// process binary-formatted file
|
// process binary-formatted file
|
||||||
if( mIsBinaryFormat)
|
if( mIsBinaryFormat) {
|
||||||
{
|
|
||||||
// in binary mode it will only return NAME and STRING token
|
// in binary mode it will only return NAME and STRING token
|
||||||
// and (correctly) skip over other tokens.
|
// and (correctly) skip over other tokens.
|
||||||
|
if ( mEnd - mP < 2 ) {
|
||||||
if( End - P < 2) return s;
|
return s;
|
||||||
|
}
|
||||||
unsigned int tok = ReadBinWord();
|
unsigned int tok = ReadBinWord();
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
||||||
// standalone tokens
|
// standalone tokens
|
||||||
switch( tok)
|
switch( tok ) {
|
||||||
{
|
case 1: {
|
||||||
case 1:
|
|
||||||
// name token
|
// name token
|
||||||
if( End - P < 4) return s;
|
if ( mEnd - mP < 4 ) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
len = ReadBinDWord();
|
len = ReadBinDWord();
|
||||||
if( End - P < int(len)) return s;
|
const int bounds = int( mEnd - mP );
|
||||||
s = std::string(P, len);
|
const int iLen = int( len );
|
||||||
P += len;
|
if ( iLen < 0 ) {
|
||||||
return s;
|
return s;
|
||||||
|
}
|
||||||
|
if ( bounds < iLen ) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
s = std::string( mP, len );
|
||||||
|
mP += len;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// string token
|
// string token
|
||||||
if( End - P < 4) return s;
|
if( mEnd - mP < 4) return s;
|
||||||
len = ReadBinDWord();
|
len = ReadBinDWord();
|
||||||
if( End - P < int(len)) return s;
|
if( mEnd - mP < int(len)) return s;
|
||||||
s = std::string(P, len);
|
s = std::string(mP, len);
|
||||||
P += (len + 2);
|
mP += (len + 2);
|
||||||
return s;
|
return s;
|
||||||
case 3:
|
case 3:
|
||||||
// integer token
|
// integer token
|
||||||
P += 4;
|
mP += 4;
|
||||||
return "<integer>";
|
return "<integer>";
|
||||||
case 5:
|
case 5:
|
||||||
// GUID token
|
// GUID token
|
||||||
P += 16;
|
mP += 16;
|
||||||
return "<guid>";
|
return "<guid>";
|
||||||
case 6:
|
case 6:
|
||||||
if( End - P < 4) return s;
|
if( mEnd - mP < 4) return s;
|
||||||
len = ReadBinDWord();
|
len = ReadBinDWord();
|
||||||
P += (len * 4);
|
mP += (len * 4);
|
||||||
return "<int_list>";
|
return "<int_list>";
|
||||||
case 7:
|
case 7:
|
||||||
if( End - P < 4) return s;
|
if( mEnd - mP < 4) return s;
|
||||||
len = ReadBinDWord();
|
len = ReadBinDWord();
|
||||||
P += (len * mBinaryFloatSize);
|
mP += (len * mBinaryFloatSize);
|
||||||
return "<flt_list>";
|
return "<flt_list>";
|
||||||
case 0x0a:
|
case 0x0a:
|
||||||
return "{";
|
return "{";
|
||||||
|
@ -1159,19 +1171,19 @@ std::string XFileParser::GetNextToken()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FindNextNoneWhiteSpace();
|
FindNextNoneWhiteSpace();
|
||||||
if( P >= End)
|
if( mP >= mEnd)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
while( (P < End) && !isspace( (unsigned char) *P))
|
while( (mP < mEnd) && !isspace( (unsigned char) *mP))
|
||||||
{
|
{
|
||||||
// either keep token delimiters when already holding a token, or return if first valid char
|
// either keep token delimiters when already holding a token, or return if first valid char
|
||||||
if( *P == ';' || *P == '}' || *P == '{' || *P == ',')
|
if( *mP == ';' || *mP == '}' || *mP == '{' || *mP == ',')
|
||||||
{
|
{
|
||||||
if( !s.size())
|
if( !s.size())
|
||||||
s.append( P++, 1);
|
s.append( mP++, 1);
|
||||||
break; // stop for delimiter
|
break; // stop for delimiter
|
||||||
}
|
}
|
||||||
s.append( P++, 1);
|
s.append( mP++, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
@ -1186,18 +1198,18 @@ void XFileParser::FindNextNoneWhiteSpace()
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while( running )
|
while( running )
|
||||||
{
|
{
|
||||||
while( P < End && isspace( (unsigned char) *P))
|
while( mP < mEnd && isspace( (unsigned char) *mP))
|
||||||
{
|
{
|
||||||
if( *P == '\n')
|
if( *mP == '\n')
|
||||||
mLineNumber++;
|
mLineNumber++;
|
||||||
++P;
|
++mP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( P >= End)
|
if( mP >= mEnd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// check if this is a comment
|
// check if this is a comment
|
||||||
if( (P[0] == '/' && P[1] == '/') || P[0] == '#')
|
if( (mP[0] == '/' && mP[1] == '/') || mP[0] == '#')
|
||||||
ReadUntilEndOfLine();
|
ReadUntilEndOfLine();
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -1214,22 +1226,30 @@ void XFileParser::GetNextTokenAsString( std::string& poString)
|
||||||
}
|
}
|
||||||
|
|
||||||
FindNextNoneWhiteSpace();
|
FindNextNoneWhiteSpace();
|
||||||
if( P >= End)
|
if ( mP >= mEnd ) {
|
||||||
ThrowException( "Unexpected end of file while parsing string");
|
delete mScene;
|
||||||
|
ThrowException( "Unexpected end of file while parsing string" );
|
||||||
|
}
|
||||||
|
|
||||||
if( *P != '"')
|
if ( *mP != '"' ) {
|
||||||
ThrowException( "Expected quotation mark.");
|
delete mScene;
|
||||||
++P;
|
ThrowException( "Expected quotation mark." );
|
||||||
|
}
|
||||||
|
++mP;
|
||||||
|
|
||||||
while( P < End && *P != '"')
|
while( mP < mEnd && *mP != '"')
|
||||||
poString.append( P++, 1);
|
poString.append( mP++, 1);
|
||||||
|
|
||||||
if( P >= End-1)
|
if ( mP >= mEnd - 1 ) {
|
||||||
ThrowException( "Unexpected end of file while parsing string");
|
delete mScene;
|
||||||
|
ThrowException( "Unexpected end of file while parsing string" );
|
||||||
|
}
|
||||||
|
|
||||||
if( P[1] != ';' || P[0] != '"')
|
if ( mP[ 1 ] != ';' || mP[ 0 ] != '"' ) {
|
||||||
ThrowException( "Expected quotation mark and semicolon at the end of a string.");
|
delete mScene;
|
||||||
P+=2;
|
ThrowException( "Expected quotation mark and semicolon at the end of a string." );
|
||||||
|
}
|
||||||
|
mP+=2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1238,35 +1258,35 @@ void XFileParser::ReadUntilEndOfLine()
|
||||||
if( mIsBinaryFormat)
|
if( mIsBinaryFormat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while( P < End)
|
while( mP < mEnd)
|
||||||
{
|
{
|
||||||
if( *P == '\n' || *P == '\r')
|
if( *mP == '\n' || *mP == '\r')
|
||||||
{
|
{
|
||||||
++P; mLineNumber++;
|
++mP; mLineNumber++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++P;
|
++mP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
unsigned short XFileParser::ReadBinWord()
|
unsigned short XFileParser::ReadBinWord()
|
||||||
{
|
{
|
||||||
ai_assert(End - P >= 2);
|
ai_assert(mEnd - mP >= 2);
|
||||||
const unsigned char* q = (const unsigned char*) P;
|
const unsigned char* q = (const unsigned char*) mP;
|
||||||
unsigned short tmp = q[0] | (q[1] << 8);
|
unsigned short tmp = q[0] | (q[1] << 8);
|
||||||
P += 2;
|
mP += 2;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
unsigned int XFileParser::ReadBinDWord()
|
unsigned int XFileParser::ReadBinDWord() {
|
||||||
{
|
ai_assert(mEnd - mP >= 4);
|
||||||
ai_assert(End - P >= 4);
|
|
||||||
const unsigned char* q = (const unsigned char*) P;
|
const unsigned char* q = (const unsigned char*) mP;
|
||||||
unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
|
unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
|
||||||
P += 4;
|
mP += 4;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1275,20 +1295,20 @@ unsigned int XFileParser::ReadInt()
|
||||||
{
|
{
|
||||||
if( mIsBinaryFormat)
|
if( mIsBinaryFormat)
|
||||||
{
|
{
|
||||||
if( mBinaryNumCount == 0 && End - P >= 2)
|
if( mBinaryNumCount == 0 && mEnd - mP >= 2)
|
||||||
{
|
{
|
||||||
unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
|
unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
|
||||||
if( tmp == 0x06 && End - P >= 4) // array of ints follows
|
if( tmp == 0x06 && mEnd - mP >= 4) // array of ints follows
|
||||||
mBinaryNumCount = ReadBinDWord();
|
mBinaryNumCount = ReadBinDWord();
|
||||||
else // single int follows
|
else // single int follows
|
||||||
mBinaryNumCount = 1;
|
mBinaryNumCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
--mBinaryNumCount;
|
--mBinaryNumCount;
|
||||||
if ( End - P >= 4) {
|
if ( mEnd - mP >= 4) {
|
||||||
return ReadBinDWord();
|
return ReadBinDWord();
|
||||||
} else {
|
} else {
|
||||||
P = End;
|
mP = mEnd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
@ -1299,24 +1319,24 @@ unsigned int XFileParser::ReadInt()
|
||||||
|
|
||||||
// check preceding minus sign
|
// check preceding minus sign
|
||||||
bool isNegative = false;
|
bool isNegative = false;
|
||||||
if( *P == '-')
|
if( *mP == '-')
|
||||||
{
|
{
|
||||||
isNegative = true;
|
isNegative = true;
|
||||||
P++;
|
mP++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// at least one digit expected
|
// at least one digit expected
|
||||||
if( !isdigit( *P))
|
if( !isdigit( *mP))
|
||||||
ThrowException( "Number expected.");
|
ThrowException( "Number expected.");
|
||||||
|
|
||||||
// read digits
|
// read digits
|
||||||
unsigned int number = 0;
|
unsigned int number = 0;
|
||||||
while( P < End)
|
while( mP < mEnd)
|
||||||
{
|
{
|
||||||
if( !isdigit( *P))
|
if( !isdigit( *mP))
|
||||||
break;
|
break;
|
||||||
number = number * 10 + (*P - 48);
|
number = number * 10 + (*mP - 48);
|
||||||
P++;
|
mP++;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckForSeparator();
|
CheckForSeparator();
|
||||||
|
@ -1329,34 +1349,35 @@ ai_real XFileParser::ReadFloat()
|
||||||
{
|
{
|
||||||
if( mIsBinaryFormat)
|
if( mIsBinaryFormat)
|
||||||
{
|
{
|
||||||
if( mBinaryNumCount == 0 && End - P >= 2)
|
if( mBinaryNumCount == 0 && mEnd - mP >= 2)
|
||||||
{
|
{
|
||||||
unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
|
unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
|
||||||
if( tmp == 0x07 && End - P >= 4) // array of floats following
|
if( tmp == 0x07 && mEnd - mP >= 4) // array of floats following
|
||||||
mBinaryNumCount = ReadBinDWord();
|
mBinaryNumCount = ReadBinDWord();
|
||||||
else // single float following
|
else // single float following
|
||||||
mBinaryNumCount = 1;
|
mBinaryNumCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
--mBinaryNumCount;
|
--mBinaryNumCount;
|
||||||
if( mBinaryFloatSize == 8)
|
if( mBinaryFloatSize == 8) {
|
||||||
{
|
if( mEnd - mP >= 8) {
|
||||||
if( End - P >= 8) {
|
double res;
|
||||||
ai_real result = (ai_real) (*(double*) P);
|
::memcpy( &res, mP, 8 );
|
||||||
P += 8;
|
mP += 8;
|
||||||
|
const ai_real result( static_cast<ai_real>( res ) );
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
P = End;
|
mP = mEnd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
{
|
if( mEnd - mP >= 4) {
|
||||||
if( End - P >= 4) {
|
ai_real result;
|
||||||
ai_real result = *(ai_real*) P;
|
::memcpy( &result, mP, 4 );
|
||||||
P += 4;
|
mP += 4;
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
P = End;
|
mP = mEnd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1367,21 +1388,21 @@ ai_real XFileParser::ReadFloat()
|
||||||
// check for various special strings to allow reading files from faulty exporters
|
// check for various special strings to allow reading files from faulty exporters
|
||||||
// I mean you, Blender!
|
// I mean you, Blender!
|
||||||
// Reading is safe because of the terminating zero
|
// Reading is safe because of the terminating zero
|
||||||
if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0)
|
if( strncmp( mP, "-1.#IND00", 9) == 0 || strncmp( mP, "1.#IND00", 8) == 0)
|
||||||
{
|
{
|
||||||
P += 9;
|
mP += 9;
|
||||||
CheckForSeparator();
|
CheckForSeparator();
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} else
|
} else
|
||||||
if( strncmp( P, "1.#QNAN0", 8) == 0)
|
if( strncmp( mP, "1.#QNAN0", 8) == 0)
|
||||||
{
|
{
|
||||||
P += 8;
|
mP += 8;
|
||||||
CheckForSeparator();
|
CheckForSeparator();
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_real result = 0.0;
|
ai_real result = 0.0;
|
||||||
P = fast_atoreal_move<ai_real>( P, result);
|
mP = fast_atoreal_move<ai_real>( mP, result);
|
||||||
|
|
||||||
CheckForSeparator();
|
CheckForSeparator();
|
||||||
|
|
||||||
|
@ -1438,15 +1459,14 @@ aiColor3D XFileParser::ReadRGB()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Throws an exception with a line number and the given text.
|
// Throws an exception with a line number and the given text.
|
||||||
AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText)
|
AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) {
|
||||||
{
|
if ( mIsBinaryFormat ) {
|
||||||
if( mIsBinaryFormat)
|
throw DeadlyImportError( pText );
|
||||||
throw DeadlyImportError( pText);
|
} else {
|
||||||
else
|
|
||||||
throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText );
|
throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
// Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
||||||
void XFileParser::FilterHierarchy( XFile::Node* pNode)
|
void XFileParser::FilterHierarchy( XFile::Node* pNode)
|
||||||
|
|
|
@ -49,10 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
namespace XFile {
|
||||||
namespace XFile
|
|
||||||
{
|
|
||||||
struct Node;
|
struct Node;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
struct Scene;
|
struct Scene;
|
||||||
|
@ -61,21 +59,20 @@ namespace Assimp
|
||||||
struct AnimBone;
|
struct AnimBone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The XFileParser reads a XFile either in text or binary form and builds a temporary
|
/**
|
||||||
* data structure out of it.
|
* @brief The XFileParser reads a XFile either in text or binary form and builds a temporary
|
||||||
*/
|
* data structure out of it.
|
||||||
class XFileParser
|
*/
|
||||||
{
|
class XFileParser {
|
||||||
public:
|
public:
|
||||||
/** Constructor. Creates a data structure out of the XFile given in the memory block.
|
/// Constructor. Creates a data structure out of the XFile given in the memory block.
|
||||||
* @param pBuffer Null-terminated memory buffer containing the XFile
|
/// @param pBuffer Null-terminated memory buffer containing the XFile
|
||||||
*/
|
|
||||||
explicit XFileParser( const std::vector<char>& pBuffer);
|
explicit XFileParser( const std::vector<char>& pBuffer);
|
||||||
|
|
||||||
/** Destructor. Destroys all imported data along with it */
|
/// Destructor. Destroys all imported data along with it
|
||||||
~XFileParser();
|
~XFileParser();
|
||||||
|
|
||||||
/** Returns the temporary representation of the imported data */
|
/// Returns the temporary representation of the imported data.
|
||||||
XFile::Scene* GetImportedData() const { return mScene; }
|
XFile::Scene* GetImportedData() const { return mScene; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -101,10 +98,10 @@ protected:
|
||||||
//! places pointer to next begin of a token, and ignores comments
|
//! places pointer to next begin of a token, and ignores comments
|
||||||
void FindNextNoneWhiteSpace();
|
void FindNextNoneWhiteSpace();
|
||||||
|
|
||||||
//! returns next parseable token. Returns empty string if no token there
|
//! returns next valid token. Returns empty string if no token there
|
||||||
std::string GetNextToken();
|
std::string GetNextToken();
|
||||||
|
|
||||||
//! reads header of dataobject including the opening brace.
|
//! reads header of data object including the opening brace.
|
||||||
//! returns false if error happened, and writes name of object
|
//! returns false if error happened, and writes name of object
|
||||||
//! if there is one
|
//! if there is one
|
||||||
void readHeadOfDataObject( std::string* poName = NULL);
|
void readHeadOfDataObject( std::string* poName = NULL);
|
||||||
|
@ -118,8 +115,8 @@ protected:
|
||||||
//! checks for a separator char, either a ',' or a ';'
|
//! checks for a separator char, either a ',' or a ';'
|
||||||
void CheckForSeparator();
|
void CheckForSeparator();
|
||||||
|
|
||||||
/// tests and possibly consumes a separator char, but does nothing if there was no separator
|
/// tests and possibly consumes a separator char, but does nothing if there was no separator
|
||||||
void TestForSeparator();
|
void TestForSeparator();
|
||||||
|
|
||||||
//! reads a x file style string
|
//! reads a x file style string
|
||||||
void GetNextTokenAsString( std::string& poString);
|
void GetNextTokenAsString( std::string& poString);
|
||||||
|
@ -138,27 +135,23 @@ protected:
|
||||||
/** Throws an exception with a line number and the given text. */
|
/** Throws an exception with a line number and the given text. */
|
||||||
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
|
||||||
|
|
||||||
/** Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
/**
|
||||||
* @param pData The sub-hierarchy to filter
|
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
||||||
*/
|
* @param pData The sub-hierarchy to filter
|
||||||
|
*/
|
||||||
void FilterHierarchy( XFile::Node* pNode);
|
void FilterHierarchy( XFile::Node* pNode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned int mMajorVersion, mMinorVersion; ///< version numbers
|
unsigned int mMajorVersion, mMinorVersion; ///< version numbers
|
||||||
bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
|
bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
|
||||||
unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
|
unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
|
||||||
// counter for number arrays in binary format
|
unsigned int mBinaryNumCount; /// < counter for number arrays in binary format
|
||||||
unsigned int mBinaryNumCount;
|
const char* mP;
|
||||||
|
const char* mEnd;
|
||||||
const char* P;
|
unsigned int mLineNumber; ///< Line number when reading in text format
|
||||||
const char* End;
|
XFile::Scene* mScene; ///< Imported data
|
||||||
|
|
||||||
/// Line number when reading in text format
|
|
||||||
unsigned int mLineNumber;
|
|
||||||
|
|
||||||
/// Imported data
|
|
||||||
XFile::Scene* mScene;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} //! ns Assimp
|
||||||
|
|
||||||
#endif // AI_XFILEPARSER_H_INC
|
#endif // AI_XFILEPARSER_H_INC
|
||||||
|
|
|
@ -72,17 +72,6 @@ using namespace irr::io;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// scopeguard for a malloc'ed buffer
|
|
||||||
struct free_it
|
|
||||||
{
|
|
||||||
free_it(void* free) : free(free) {}
|
|
||||||
~free_it() {
|
|
||||||
::free(this->free);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* free;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
|
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
|
||||||
template<> const char* LogFunctions<XGLImporter>::Prefix()
|
template<> const char* LogFunctions<XGLImporter>::Prefix()
|
||||||
{
|
{
|
||||||
|
@ -155,8 +144,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
|
||||||
aiScene* pScene, IOSystem* pIOHandler)
|
aiScene* pScene, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
|
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
|
||||||
Bytef* dest = NULL;
|
std::vector<Bytef> uncompressed;
|
||||||
free_it free_it_really(dest);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_scene = pScene;
|
m_scene = pScene;
|
||||||
|
@ -192,6 +180,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
|
||||||
|
|
||||||
size_t total = 0l;
|
size_t total = 0l;
|
||||||
|
|
||||||
|
// TODO: be smarter about this, decompress directly into heap buffer
|
||||||
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
|
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
|
||||||
#define MYBLOCK 1024
|
#define MYBLOCK 1024
|
||||||
Bytef block[MYBLOCK];
|
Bytef block[MYBLOCK];
|
||||||
|
@ -206,8 +195,8 @@ void XGLImporter::InternReadFile( const std::string& pFile,
|
||||||
}
|
}
|
||||||
const size_t have = MYBLOCK - zstream.avail_out;
|
const size_t have = MYBLOCK - zstream.avail_out;
|
||||||
total += have;
|
total += have;
|
||||||
dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
|
uncompressed.resize(total);
|
||||||
memcpy(dest + total - have,block,have);
|
memcpy(uncompressed.data() + total - have,block,have);
|
||||||
}
|
}
|
||||||
while (ret != Z_STREAM_END);
|
while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
|
@ -215,7 +204,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
|
||||||
inflateEnd(&zstream);
|
inflateEnd(&zstream);
|
||||||
|
|
||||||
// replace the input stream with a memory stream
|
// replace the input stream with a memory stream
|
||||||
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
|
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace glTF2
|
||||||
// Vec/matrix types, as raw float arrays
|
// Vec/matrix types, as raw float arrays
|
||||||
typedef float (vec3)[3];
|
typedef float (vec3)[3];
|
||||||
typedef float (vec4)[4];
|
typedef float (vec4)[4];
|
||||||
typedef float (mat4)[16];
|
typedef float (mat4)[16];
|
||||||
|
|
||||||
namespace Util
|
namespace Util
|
||||||
{
|
{
|
||||||
|
@ -166,32 +166,7 @@ namespace glTF2
|
||||||
|
|
||||||
//! Magic number for GLB files
|
//! Magic number for GLB files
|
||||||
#define AI_GLB_MAGIC_NUMBER "glTF"
|
#define AI_GLB_MAGIC_NUMBER "glTF"
|
||||||
|
#include <assimp/pbrmaterial.h>
|
||||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
|
|
||||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
|
|
||||||
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
|
|
||||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
|
|
||||||
|
|
||||||
#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
|
|
||||||
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
|
|
||||||
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
|
|
||||||
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
|
|
||||||
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
|
|
||||||
#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
|
|
||||||
#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
|
|
||||||
|
|
||||||
#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
|
|
||||||
#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
|
|
||||||
|
|
||||||
#ifdef ASSIMP_API
|
#ifdef ASSIMP_API
|
||||||
#include "./../include/assimp/Compiler/pushpack1.h"
|
#include "./../include/assimp/Compiler/pushpack1.h"
|
||||||
|
|
|
@ -669,7 +669,7 @@ inline Image::Image()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Image::Read(Value& obj, Asset& /*r*/)
|
inline void Image::Read(Value& obj, Asset& r)
|
||||||
{
|
{
|
||||||
if (!mDataLength) {
|
if (!mDataLength) {
|
||||||
if (Value* uri = FindString(obj, "uri")) {
|
if (Value* uri = FindString(obj, "uri")) {
|
||||||
|
@ -686,6 +686,19 @@ inline void Image::Read(Value& obj, Asset& /*r*/)
|
||||||
this->uri = uristr;
|
this->uri = uristr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
|
||||||
|
this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
|
||||||
|
Ref<Buffer> buffer = this->bufferView->buffer;
|
||||||
|
|
||||||
|
this->mDataLength = this->bufferView->byteLength;
|
||||||
|
// maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
|
||||||
|
this->mData = new uint8_t [this->mDataLength];
|
||||||
|
memcpy(this->mData, buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
|
||||||
|
|
||||||
|
if (Value* mtype = FindString(obj, "mimeType")) {
|
||||||
|
this->mimeType = mtype->GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,11 +316,9 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
|
||||||
std::string path = tex.C_Str();
|
std::string path = tex.C_Str();
|
||||||
|
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0) {
|
||||||
if (path[0] != '*') {
|
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
|
||||||
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
|
if (it != mTexturesByPath.end()) {
|
||||||
if (it != mTexturesByPath.end()) {
|
texture = mAsset->textures.Get(it->second);
|
||||||
texture = mAsset->textures.Get(it->second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
|
|
|
@ -948,24 +948,24 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
|
||||||
size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
|
size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
|
||||||
|
|
||||||
if(primitives[0].indices->count != size_coordindex)
|
if(primitives[0].indices->count != size_coordindex)
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) +
|
throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + to_string(size_coordindex) +
|
||||||
") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ").");
|
") not equal to uncompressed (" + to_string(primitives[0].indices->count) + ").");
|
||||||
|
|
||||||
size_coordindex *= sizeof(IndicesType);
|
size_coordindex *= sizeof(IndicesType);
|
||||||
// Coordinates
|
// Coordinates
|
||||||
size_t size_coord = ifs.GetNCoord();// See float attributes note.
|
size_t size_coord = ifs.GetNCoord();// See float attributes note.
|
||||||
|
|
||||||
if(primitives[0].attributes.position[0]->count != size_coord)
|
if(primitives[0].attributes.position[0]->count != size_coord)
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) +
|
throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + to_string(size_coord) +
|
||||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ").");
|
") not equal to uncompressed (" + to_string(primitives[0].attributes.position[0]->count) + ").");
|
||||||
|
|
||||||
size_coord *= 3 * sizeof(float);
|
size_coord *= 3 * sizeof(float);
|
||||||
// Normals
|
// Normals
|
||||||
size_t size_normal = ifs.GetNNormal();// See float attributes note.
|
size_t size_normal = ifs.GetNNormal();// See float attributes note.
|
||||||
|
|
||||||
if(primitives[0].attributes.normal[0]->count != size_normal)
|
if(primitives[0].attributes.normal[0]->count != size_normal)
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) +
|
throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + to_string(size_normal) +
|
||||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ").");
|
") not equal to uncompressed (" + to_string(primitives[0].attributes.normal[0]->count) + ").");
|
||||||
|
|
||||||
size_normal *= 3 * sizeof(float);
|
size_normal *= 3 * sizeof(float);
|
||||||
// Additional attributes.
|
// Additional attributes.
|
||||||
|
@ -989,8 +989,8 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
|
||||||
if(idx_texcoord < primitives[0].attributes.texcoord.size())
|
if(idx_texcoord < primitives[0].attributes.texcoord.size())
|
||||||
{
|
{
|
||||||
if(primitives[0].attributes.texcoord[idx]->count != tval)
|
if(primitives[0].attributes.texcoord[idx]->count != tval)
|
||||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + std::to_string(tval) +
|
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + to_string(tval) +
|
||||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
|
") not equal to uncompressed (" + to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
|
||||||
|
|
||||||
idx_texcoord++;
|
idx_texcoord++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,9 +194,16 @@ void glTFImporter::ImportMaterials(glTF::Asset& r)
|
||||||
aimat->AddProperty(&str, AI_MATKEY_NAME);
|
aimat->AddProperty(&str, AI_MATKEY_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT );
|
||||||
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE );
|
||||||
SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
|
||||||
SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.emission, aimat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
|
||||||
|
|
||||||
|
aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
|
||||||
|
|
||||||
|
if (mat.transparent && (mat.transparency != 1.0f)) {
|
||||||
|
aimat->AddProperty(&mat.transparency, 1, AI_MATKEY_OPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
if (mat.shininess > 0.f) {
|
if (mat.shininess > 0.f) {
|
||||||
aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
|
aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "simd.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
bool CPUSupportsSSE2() {
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
|
//* x86_64 always has SSE2 instructions */
|
||||||
|
return true;
|
||||||
|
#elif defined(__GNUC__) && defined(i386)
|
||||||
|
// for GCC x86 we check cpuid
|
||||||
|
unsigned int d;
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"popl %%ebx\n\t"
|
||||||
|
: "=d" ( d )
|
||||||
|
:"a" ( 1 ) );
|
||||||
|
return ( d & 0x04000000 ) != 0;
|
||||||
|
#elif (defined(_MSC_VER) && defined(_M_IX86))
|
||||||
|
// also check cpuid for MSVC x86
|
||||||
|
unsigned int d;
|
||||||
|
__asm {
|
||||||
|
xor eax, eax
|
||||||
|
inc eax
|
||||||
|
push ebx
|
||||||
|
cpuid
|
||||||
|
pop ebx
|
||||||
|
mov d, edx
|
||||||
|
}
|
||||||
|
return ( d & 0x04000000 ) != 0;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Namespace Assimp
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018, 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.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assimp/defs.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
/// @brief Checks if the platform supports SSE2 optimization
|
||||||
|
/// @return true, if SSE2 is supported. false if SSE2 is not supported.
|
||||||
|
bool ASSIMP_API CPUSupportsSSE2();
|
||||||
|
|
||||||
|
} // Namespace Assimp
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue