Merge branch 'master' into umw_dev

pull/1863/head
Kim Kulling 2018-04-08 21:42:10 +02:00 committed by GitHub
commit f096843c45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1374 additions and 547 deletions

View File

@ -138,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
@ -161,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)
@ -179,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" )
@ -192,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 )
@ -212,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" )
@ -229,39 +220,39 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF() ENDIF()
if (IOS) IF (IOS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
endif() ENDIF()
if (ASSIMP_COVERALLS) IF (ASSIMP_COVERALLS)
MESSAGE(STATUS "Coveralls enabled") MESSAGE(STATUS "Coveralls enabled")
INCLUDE(Coveralls) INCLUDE(Coveralls)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") 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") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
endif() ENDIF()
if (ASSIMP_WERROR) 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)
@ -294,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)
@ -371,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")
@ -412,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 )
@ -476,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}" )
@ -507,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)
@ -520,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)
@ -548,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)

View File

@ -35,29 +35,29 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki
__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__:

View File

@ -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

View File

@ -71,7 +71,7 @@ static const aiImporterDesc desc = {
0, 0,
0, 0,
0, 0,
"3ds prj" "3ds prj 3DS PRJ"
}; };
@ -127,7 +127,7 @@ Discreet3DSImporter::~Discreet3DSImporter() {
// 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;
} }

View File

@ -186,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})

View File

@ -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

View File

@ -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;
} }

View File

@ -98,7 +98,7 @@ void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportPrope
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 ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
//void ExportSceneFBXA(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* );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -173,7 +173,7 @@ Exporter::ExportFormatEntry gExporters[] =
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
//Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
#endif #endif
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER

View File

@ -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,9 +135,7 @@ 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;
@ -153,14 +153,14 @@ 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(); post_nodes_chain.clear();
@ -174,7 +174,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
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
@ -189,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
@ -250,11 +258,11 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
ConvertNodes( model->ID(), *last_parent, new_abs_transform ); 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() );
@ -278,34 +286,31 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
} }
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();
@ -378,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();
@ -397,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 )
{ {
@ -738,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
@ -786,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;
@ -2005,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 )

View File

@ -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
@ -117,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 -
@ -258,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
@ -281,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);
@ -432,19 +424,11 @@ 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;
const FBX::Document& doc; const FBX::Document& doc;
std::vector<std::string> mLightNames;
}; };
} }

View File

@ -45,9 +45,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXCommon.h" #include "FBXCommon.h"
#include <assimp/StreamWriter.h> // StreamWriterLE #include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/StringUtils.h> // ai_snprintf
#include <string> #include <string>
#include <ostream>
#include <sstream> // ostringstream
#include <memory> // shared_ptr #include <memory> // shared_ptr
// AddP70<type> helpers... there's no usable pattern here, // AddP70<type> helpers... there's no usable pattern here,
@ -145,33 +149,174 @@ void FBX::Node::AddP70time(
} }
// 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 // public member functions for writing to binary fbx
void FBX::Node::Dump(std::shared_ptr<Assimp::IOStream> outfile) void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s)
{
Assimp::StreamWriterLE outstream(outfile);
Dump(outstream);
}
void FBX::Node::Dump(Assimp::StreamWriterLE &s)
{ {
// write header section (with placeholders for some things) // write header section (with placeholders for some things)
Begin(s); BeginBinary(s);
// write properties // write properties
DumpProperties(s); DumpPropertiesBinary(s);
// go back and fill in property related placeholders // go back and fill in property related placeholders
EndProperties(s, properties.size()); EndPropertiesBinary(s, properties.size());
// write children // write children
DumpChildren(s); DumpChildrenBinary(s);
// finish, filling in end offset placeholder // finish, filling in end offset placeholder
End(s, !children.empty()); EndBinary(s, force_has_children || !children.empty());
} }
void FBX::Node::Begin(Assimp::StreamWriterLE &s)
// 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 // remember start pos so we can come back and write the end pos
this->start_pos = s.Tell(); this->start_pos = s.Tell();
@ -189,26 +334,14 @@ void FBX::Node::Begin(Assimp::StreamWriterLE &s)
this->property_start = s.Tell(); this->property_start = s.Tell();
} }
void FBX::Node::DumpProperties(Assimp::StreamWriterLE& s) void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s)
{ {
for (auto &p : properties) { for (auto &p : properties) {
p.Dump(s); p.DumpBinary(s);
} }
} }
void FBX::Node::DumpChildren(Assimp::StreamWriterLE& s) void FBX::Node::EndPropertiesBinary(
{
for (FBX::Node& child : children) {
child.Dump(s);
}
}
void FBX::Node::EndProperties(Assimp::StreamWriterLE &s)
{
EndProperties(s, properties.size());
}
void FBX::Node::EndProperties(
Assimp::StreamWriterLE &s, Assimp::StreamWriterLE &s,
size_t num_properties size_t num_properties
) { ) {
@ -222,7 +355,14 @@ void FBX::Node::EndProperties(
s.Seek(pos); s.Seek(pos);
} }
void FBX::Node::End( void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s)
{
for (FBX::Node& child : children) {
child.DumpBinary(s);
}
}
void FBX::Node::EndBinary(
Assimp::StreamWriterLE &s, Assimp::StreamWriterLE &s,
bool has_children bool has_children
) { ) {
@ -237,48 +377,192 @@ void FBX::Node::End(
} }
// static member functions void FBX::Node::BeginAscii(std::ostream& s, int indent)
{
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << name << ": ";
}
// convenience function to create and write a property node, void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent)
// holding a single property which is an array of values. {
// does not copy the data, so is efficient for large arrays. 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! // TODO: optional zip compression!
void FBX::Node::WritePropertyNode( void FBX::Node::WritePropertyNodeBinary(
const std::string& name, const std::string& name,
const std::vector<double>& v, const std::vector<double>& v,
Assimp::StreamWriterLE& s Assimp::StreamWriterLE& s
){ ){
Node node(name); FBX::Node node(name);
node.Begin(s); node.BeginBinary(s);
s.PutU1('d'); s.PutU1('d');
s.PutU4(uint32_t(v.size())); // number of elements s.PutU4(uint32_t(v.size())); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(uint32_t(v.size()) * 8); // data size s.PutU4(uint32_t(v.size()) * 8); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); } for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
node.EndProperties(s, 1); node.EndPropertiesBinary(s, 1);
node.End(s, false); node.EndBinary(s, false);
} }
// convenience function to create and write a property node, // binary property node from vector of int32_t
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
// TODO: optional zip compression! // TODO: optional zip compression!
void FBX::Node::WritePropertyNode( void FBX::Node::WritePropertyNodeBinary(
const std::string& name, const std::string& name,
const std::vector<int32_t>& v, const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s Assimp::StreamWriterLE& s
){ ){
Node node(name); FBX::Node node(name);
node.Begin(s); node.BeginBinary(s);
s.PutU1('i'); s.PutU1('i');
s.PutU4(uint32_t(v.size())); // number of elements s.PutU4(uint32_t(v.size())); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(uint32_t(v.size()) * 4); // data size s.PutU4(uint32_t(v.size()) * 4); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); } for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
node.EndProperties(s, 1); node.EndPropertiesBinary(s, 1);
node.End(s, false); 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_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -66,14 +66,18 @@ public: // public data members
std::vector<FBX::Property> properties; // node properties std::vector<FBX::Property> properties; // node properties
std::vector<FBX::Node> children; // child nodes std::vector<FBX::Node> children; // child nodes
// some nodes always pretend they have children...
bool force_has_children = false;
public: // constructors public: // constructors
Node() = default; Node() = default;
Node(const std::string& n) : name(n) {} Node(const std::string& n) : name(n) {}
Node(const std::string& n, const FBX::Property &p)
// convenience template to construct with properties directly
template <typename... More>
Node(const std::string& n, const More... more)
: name(n) : name(n)
{ properties.push_back(p); } { AddProperties(more...); }
Node(const std::string& n, const std::vector<FBX::Property> &pv)
: name(n), properties(pv) {}
public: // functions to add properties or children public: // functions to add properties or children
// add a single property to the node // add a single property to the node
@ -138,19 +142,48 @@ public: // support specifically for dealing with Properties70 nodes
public: // member functions for writing data to a file or stream public: // member functions for writing data to a file or stream
// write the full node as binary data to the given file or stream // write the full node to the given file or stream
void Dump(std::shared_ptr<Assimp::IOStream> outfile); void Dump(
void Dump(Assimp::StreamWriterLE &s); 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. // these other functions are for writing data piece by piece.
// they must be used carefully. // they must be used carefully.
// for usage examples see FBXExporter.cpp. // for usage examples see FBXExporter.cpp.
void Begin(Assimp::StreamWriterLE &s); void Begin(Assimp::StreamWriterLE &s, bool binary, int indent);
void DumpProperties(Assimp::StreamWriterLE& s); void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent);
void EndProperties(Assimp::StreamWriterLE &s); void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent);
void EndProperties(Assimp::StreamWriterLE &s, size_t num_properties); void EndProperties(
void DumpChildren(Assimp::StreamWriterLE& s); Assimp::StreamWriterLE &s, bool binary, int indent,
void End(Assimp::StreamWriterLE &s, bool has_children); 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 private: // data used for binary dumps
size_t start_pos; // starting position in stream size_t start_pos; // starting position in stream
@ -165,11 +198,12 @@ public: // static member functions
static void WritePropertyNode( static void WritePropertyNode(
const std::string& name, const std::string& name,
const T value, const T value,
Assimp::StreamWriterLE& s Assimp::StreamWriterLE& s,
bool binary, int indent
) { ) {
FBX::Property p(value); FBX::Property p(value);
FBX::Node node(name, p); FBX::Node node(name, p);
node.Dump(s); node.Dump(s, binary, indent);
} }
// convenience function to create and write a property node, // convenience function to create and write a property node,
@ -178,7 +212,8 @@ public: // static member functions
static void WritePropertyNode( static void WritePropertyNode(
const std::string& name, const std::string& name,
const std::vector<double>& v, const std::vector<double>& v,
Assimp::StreamWriterLE& s Assimp::StreamWriterLE& s,
bool binary, int indent
); );
// convenience function to create and write a property node, // convenience function to create and write a property node,
@ -187,8 +222,34 @@ public: // static member functions
static void WritePropertyNode( static void WritePropertyNode(
const std::string& name, const std::string& name,
const std::vector<int32_t>& v, 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 Assimp::StreamWriterLE& s
); );
static void WritePropertyNodeBinary(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
);
}; };

View File

@ -48,7 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#include <sstream> // stringstream #include <ostream>
#include <locale>
#include <sstream> // ostringstream
// constructors for single element properties // constructors for single element properties
@ -164,18 +166,18 @@ size_t FBX::Property::size()
} }
} }
void FBX::Property::Dump(Assimp::StreamWriterLE &s) void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s)
{ {
s.PutU1(type); s.PutU1(type);
uint8_t* d; uint8_t* d = data.data();
size_t N; size_t N;
switch (type) { switch (type) {
case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(data.data()))); return; case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(data.data()))); return; case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(data.data()))); return; case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
case 'F': s.PutF4(*(reinterpret_cast<float*>(data.data()))); return; case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
case 'D': s.PutF8(*(reinterpret_cast<double*>(data.data()))); return; case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(data.data()))); return; case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
case 'S': case 'S':
case 'R': case 'R':
s.PutU4(uint32_t(data.size())); s.PutU4(uint32_t(data.size()));
@ -187,7 +189,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large? // TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size s.PutU4(uint32_t(data.size())); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
s.PutI4((reinterpret_cast<int32_t*>(d))[i]); s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
} }
@ -198,7 +199,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large? // TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size s.PutU4(uint32_t(data.size())); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
s.PutI8((reinterpret_cast<int64_t*>(d))[i]); s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
} }
@ -209,7 +209,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large? // TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size s.PutU4(uint32_t(data.size())); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
s.PutF4((reinterpret_cast<float*>(d))[i]); s.PutF4((reinterpret_cast<float*>(d))[i]);
} }
@ -220,18 +219,146 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large? // TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size s.PutU4(uint32_t(data.size())); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
s.PutF8((reinterpret_cast<double*>(d))[i]); s.PutF8((reinterpret_cast<double*>(d))[i]);
} }
return; return;
default: default:
std::stringstream err; std::ostringstream err;
err << "Tried to dump property with invalid type '"; err << "Tried to dump property with invalid type '";
err << type << "'!"; err << type << "'!";
throw DeadlyExportError(err.str()); 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_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#include <ostream>
#include <type_traits> // is_void #include <type_traits> // is_void
namespace FBX { namespace FBX {
@ -113,7 +114,10 @@ public:
size_t size(); size_t size();
// write this property node as binary data to the given stream // write this property node as binary data to the given stream
void Dump(Assimp::StreamWriterLE &s); 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: private:
char type; char type;

View File

@ -66,7 +66,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
#include <array> #include <array>
#include <unordered_set> #include <unordered_set>
#include <iostream> // endl
// RESOURCES: // RESOURCES:
// https://code.blender.org/2013/08/fbx-binary-file-format-specification/ // https://code.blender.org/2013/08/fbx-binary-file-format-specification/
@ -89,6 +88,8 @@ namespace FBX {
"\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e"; "\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e";
const std::string FOOT_MAGIC = const std::string FOOT_MAGIC =
"\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b"; "\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b";
const std::string COMMENT_UNDERLINE =
";------------------------------------------------------------------";
} }
using namespace Assimp; using namespace Assimp;
@ -115,7 +116,7 @@ namespace Assimp {
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Worker function for exporting a scene to ASCII FBX. // Worker function for exporting a scene to ASCII FBX.
// Prototyped and registered in Exporter.cpp // Prototyped and registered in Exporter.cpp
/*void ExportSceneFBXA ( void ExportSceneFBXA (
const char* pFile, const char* pFile,
IOSystem* pIOSystem, IOSystem* pIOSystem,
const aiScene* pScene, const aiScene* pScene,
@ -126,7 +127,7 @@ namespace Assimp {
// perform ascii export // perform ascii export
exporter.ExportAscii(pFile, pIOSystem); exporter.ExportAscii(pFile, pIOSystem);
}*/ // TODO }
} // end of namespace Assimp } // end of namespace Assimp
@ -194,27 +195,43 @@ void FBXExporter::ExportAscii (
); );
} }
// this isn't really necessary, // write the ascii header
// but the Autodesk FBX SDK puts a similar comment at the top of the file. WriteAsciiHeader();
// Theirs declares that the file copyright is owned by Autodesk...
std::stringstream head;
using std::endl;
head << "; FBX " << EXPORT_VERSION_STR << " project file" << endl;
head << "; Created by the Open Asset Import Library (Assimp)" << endl;
head << "; http://assimp.org" << endl;
head << "; -------------------------------------------------" << endl;
head << endl;
const std::string ascii_header = head.str();
outfile->Write(ascii_header.c_str(), ascii_header.size(), 1);
// write all the sections // write all the sections
WriteAllNodes(); WriteAllNodes();
// make sure the file ends with a newline.
// note: if the file is opened in text mode,
// this should do the right cross-platform thing.
outfile->Write("\n", 1, 1);
// explicitly release file pointer, // explicitly release file pointer,
// so we don't have to rely on class destruction. // so we don't have to rely on class destruction.
outfile.reset(); outfile.reset();
} }
void FBXExporter::WriteAsciiHeader()
{
// basically just a comment at the top of the file
std::stringstream head;
head << "; FBX " << EXPORT_VERSION_STR << " project file\n";
head << "; Created by the Open Asset Import Library (Assimp)\n";
head << "; http://assimp.org\n";
head << "; -------------------------------------------------\n";
const std::string ascii_header = head.str();
outfile->Write(ascii_header.c_str(), ascii_header.size(), 1);
}
void FBXExporter::WriteAsciiSectionHeader(const std::string& title)
{
StreamWriterLE outstream(outfile);
std::stringstream s;
s << "\n\n; " << title << '\n';
s << FBX::COMMENT_UNDERLINE << "\n";
outstream.PutString(s.str());
}
void FBXExporter::WriteBinaryHeader() void FBXExporter::WriteBinaryHeader()
{ {
// first a specific sequence of 23 bytes, always the same // first a specific sequence of 23 bytes, always the same
@ -294,28 +311,39 @@ void FBXExporter::WriteAllNodes ()
//FBXHeaderExtension top-level node //FBXHeaderExtension top-level node
void FBXExporter::WriteHeaderExtension () void FBXExporter::WriteHeaderExtension ()
{ {
if (!binary) {
// no title, follows directly from the top comment
}
FBX::Node n("FBXHeaderExtension"); FBX::Node n("FBXHeaderExtension");
StreamWriterLE outstream(outfile); StreamWriterLE outstream(outfile);
int indent = 0;
// begin node // begin node
n.Begin(outstream); n.Begin(outstream, binary, indent);
// write properties // write properties
// (none) // (none)
// finish properties // finish properties
n.EndProperties(outstream, 0); n.EndProperties(outstream, binary, indent, 0);
// begin children
n.BeginChildren(outstream, binary, indent);
indent = 1;
// write child nodes // write child nodes
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"FBXHeaderVersion", int32_t(1003), outstream "FBXHeaderVersion", int32_t(1003), outstream, binary, indent
); );
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"FBXVersion", int32_t(EXPORT_VERSION_INT), outstream "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"EncryptionType", int32_t(0), outstream
); );
if (binary) {
FBX::Node::WritePropertyNode(
"EncryptionType", int32_t(0), outstream, binary, indent
);
}
FBX::Node CreationTimeStamp("CreationTimeStamp"); FBX::Node CreationTimeStamp("CreationTimeStamp");
time_t rawtime; time_t rawtime;
@ -329,36 +357,50 @@ void FBXExporter::WriteHeaderExtension ()
CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min)); CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min));
CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec)); CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec));
CreationTimeStamp.AddChild("Millisecond", int32_t(0)); CreationTimeStamp.AddChild("Millisecond", int32_t(0));
CreationTimeStamp.Dump(outstream); CreationTimeStamp.Dump(outstream, binary, indent);
std::stringstream creator; std::stringstream creator;
creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor() creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor()
<< "." << aiGetVersionMinor() << "." << aiGetVersionRevision(); << "." << aiGetVersionMinor() << "." << aiGetVersionRevision();
FBX::Node::WritePropertyNode("Creator", creator.str(), outstream); FBX::Node::WritePropertyNode(
"Creator", creator.str(), outstream, binary, indent
);
FBX::Node sceneinfo("SceneInfo"); //FBX::Node sceneinfo("SceneInfo");
//sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo"); //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo");
// not sure if any of this is actually needed, // not sure if any of this is actually needed,
// so just write an empty node for now. // so just write an empty node for now.
sceneinfo.Dump(outstream); //sceneinfo.Dump(outstream, binary, indent);
indent = 0;
// finish node // finish node
n.End(outstream, true); n.End(outstream, binary, indent, true);
// that's it for FBXHeaderExtension... // that's it for FBXHeaderExtension...
if (!binary) { return; }
// but binary files also need top-level FileID, CreationTime, Creator: // but binary files also need top-level FileID, CreationTime, Creator:
std::vector<uint8_t> raw(GENERIC_FILEID.size()); std::vector<uint8_t> raw(GENERIC_FILEID.size());
for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) { for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) {
raw[i] = uint8_t(GENERIC_FILEID[i]); raw[i] = uint8_t(GENERIC_FILEID[i]);
} }
FBX::Node::WritePropertyNode("FileId", raw, outstream); FBX::Node::WritePropertyNode(
FBX::Node::WritePropertyNode("CreationTime", GENERIC_CTIME, outstream); "FileId", raw, outstream, binary, indent
FBX::Node::WritePropertyNode("Creator", creator.str(), outstream); );
FBX::Node::WritePropertyNode(
"CreationTime", GENERIC_CTIME, outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"Creator", creator.str(), outstream, binary, indent
);
} }
void FBXExporter::WriteGlobalSettings () void FBXExporter::WriteGlobalSettings ()
{ {
if (!binary) {
// no title, follows directly from the header extension
}
FBX::Node gs("GlobalSettings"); FBX::Node gs("GlobalSettings");
gs.AddChild("Version", int32_t(1000)); gs.AddChild("Version", int32_t(1000));
@ -385,11 +427,15 @@ void FBXExporter::WriteGlobalSettings ()
p.AddP70int("CurrentTimeMarker", -1); p.AddP70int("CurrentTimeMarker", -1);
gs.AddChild(p); gs.AddChild(p);
gs.Dump(outfile); gs.Dump(outfile, binary, 0);
} }
void FBXExporter::WriteDocuments () void FBXExporter::WriteDocuments ()
{ {
if (!binary) {
WriteAsciiSectionHeader("Documents Description");
}
// not sure what the use of multiple documents would be, // not sure what the use of multiple documents would be,
// or whether any end-application supports it // or whether any end-application supports it
FBX::Node docs("Documents"); FBX::Node docs("Documents");
@ -411,15 +457,19 @@ void FBXExporter::WriteDocuments ()
doc.AddChild("RootNode", int64_t(0)); doc.AddChild("RootNode", int64_t(0));
docs.AddChild(doc); docs.AddChild(doc);
docs.Dump(outfile); docs.Dump(outfile, binary, 0);
} }
void FBXExporter::WriteReferences () void FBXExporter::WriteReferences ()
{ {
if (!binary) {
WriteAsciiSectionHeader("Document References");
}
// always empty for now. // always empty for now.
// not really sure what this is for. // not really sure what this is for.
FBX::Node n("References"); FBX::Node n("References");
n.Dump(outfile); n.force_has_children = true;
n.Dump(outfile, binary, 0);
} }
@ -468,9 +518,6 @@ size_t count_images(const aiScene* scene) {
} }
} }
} }
//for (auto &s : images) {
// std::cout << "found image: " << s << std::endl;
//}
return images.size(); return images.size();
} }
@ -510,6 +557,11 @@ void FBXExporter::WriteDefinitions ()
// determining how many of each type of object there are // determining how many of each type of object there are
// and specifying the base properties to use when otherwise unspecified. // and specifying the base properties to use when otherwise unspecified.
// ascii section header
if (!binary) {
WriteAsciiSectionHeader("Object definitions");
}
// we need to count the objects // we need to count the objects
int32_t count; int32_t count;
int32_t total_count = 0; int32_t total_count = 0;
@ -520,7 +572,7 @@ void FBXExporter::WriteDefinitions ()
// GlobalSettings // GlobalSettings
// this seems to always be here in Maya exports // this seems to always be here in Maya exports
n = FBX::Node("ObjectType", Property("GlobalSettings")); n = FBX::Node("ObjectType", "GlobalSettings");
count = 1; count = 1;
n.AddChild("Count", count); n.AddChild("Count", count);
object_nodes.push_back(n); object_nodes.push_back(n);
@ -531,9 +583,9 @@ void FBXExporter::WriteDefinitions ()
// but no harm seems to come of leaving it out. // but no harm seems to come of leaving it out.
count = mScene->mNumAnimations; count = mScene->mNumAnimations;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("AnimationStack")); n = FBX::Node("ObjectType", "AnimationStack");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxAnimStack")); pt = FBX::Node("PropertyTemplate", "FbxAnimStack");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70string("Description", ""); p.AddP70string("Description", "");
p.AddP70time("LocalStart", 0); p.AddP70time("LocalStart", 0);
@ -553,9 +605,9 @@ void FBXExporter::WriteDefinitions ()
// so there will be one per aiAnimation // so there will be one per aiAnimation
count = mScene->mNumAnimations; count = mScene->mNumAnimations;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("AnimationLayer")); n = FBX::Node("ObjectType", "AnimationLayer");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FBXAnimLayer")); pt = FBX::Node("PropertyTemplate", "FBXAnimLayer");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70("Weight", "Number", "", "A", double(100)); p.AddP70("Weight", "Number", "", "A", double(100));
p.AddP70bool("Mute", 0); p.AddP70bool("Mute", 0);
@ -583,9 +635,9 @@ void FBXExporter::WriteDefinitions ()
count = 1; // TODO: select properly count = 1; // TODO: select properly
if (count) { if (count) {
// FbxSkeleton // FbxSkeleton
n = FBX::Node("ObjectType", Property("NodeAttribute")); n = FBX::Node("ObjectType", "NodeAttribute");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxSkeleton")); pt = FBX::Node("PropertyTemplate", "FbxSkeleton");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70color("Color", 0.8, 0.8, 0.8); p.AddP70color("Color", 0.8, 0.8, 0.8);
p.AddP70double("Size", 33.333333333333); p.AddP70double("Size", 33.333333333333);
@ -601,9 +653,9 @@ void FBXExporter::WriteDefinitions ()
// <~~ node heirarchy // <~~ node heirarchy
count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node) count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node)
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Model")); n = FBX::Node("ObjectType", "Model");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxNode")); pt = FBX::Node("PropertyTemplate", "FbxNode");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70enum("QuaternionInterpolate", 0); p.AddP70enum("QuaternionInterpolate", 0);
p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0); p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0);
@ -698,9 +750,9 @@ void FBXExporter::WriteDefinitions ()
// <~~ aiMesh // <~~ aiMesh
count = mScene->mNumMeshes; count = mScene->mNumMeshes;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Geometry")); n = FBX::Node("ObjectType", "Geometry");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxMesh")); pt = FBX::Node("PropertyTemplate", "FbxMesh");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70color("Color", 0, 0, 0); p.AddP70color("Color", 0, 0, 0);
p.AddP70vector("BBoxMin", 0, 0, 0); p.AddP70vector("BBoxMin", 0, 0, 0);
@ -724,7 +776,7 @@ void FBXExporter::WriteDefinitions ()
count = mScene->mNumMaterials; count = mScene->mNumMaterials;
if (count) { if (count) {
bool has_phong = has_phong_mat(mScene); bool has_phong = has_phong_mat(mScene);
n = FBX::Node("ObjectType", Property("Material")); n = FBX::Node("ObjectType", "Material");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate"); pt = FBX::Node("PropertyTemplate");
if (has_phong) { if (has_phong) {
@ -771,9 +823,9 @@ void FBXExporter::WriteDefinitions ()
// one for each image file. // one for each image file.
count = int32_t(count_images(mScene)); count = int32_t(count_images(mScene));
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Video")); n = FBX::Node("ObjectType", "Video");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxVideo")); pt = FBX::Node("PropertyTemplate", "FbxVideo");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70bool("ImageSequence", 0); p.AddP70bool("ImageSequence", 0);
p.AddP70int("ImageSequenceOffset", 0); p.AddP70int("ImageSequenceOffset", 0);
@ -800,9 +852,9 @@ void FBXExporter::WriteDefinitions ()
// <~~ aiTexture // <~~ aiTexture
count = int32_t(count_textures(mScene)); count = int32_t(count_textures(mScene));
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Texture")); n = FBX::Node("ObjectType", "Texture");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxFileTexture")); pt = FBX::Node("PropertyTemplate", "FbxFileTexture");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70enum("TextureTypeUse", 0); p.AddP70enum("TextureTypeUse", 0);
p.AddP70numberA("Texture alpha", 1.0); p.AddP70numberA("Texture alpha", 1.0);
@ -829,9 +881,9 @@ void FBXExporter::WriteDefinitions ()
// AnimationCurveNode / FbxAnimCurveNode // AnimationCurveNode / FbxAnimCurveNode
count = mScene->mNumAnimations * 3; count = mScene->mNumAnimations * 3;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("AnimationCurveNode")); n = FBX::Node("ObjectType", "AnimationCurveNode");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("FbxAnimCurveNode")); pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
p.AddP70("d", "Compound", "", ""); p.AddP70("d", "Compound", "", "");
pt.AddChild(p); pt.AddChild(p);
@ -843,7 +895,7 @@ void FBXExporter::WriteDefinitions ()
// AnimationCurve / FbxAnimCurve // AnimationCurve / FbxAnimCurve
count = mScene->mNumAnimations * 9; count = mScene->mNumAnimations * 9;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("AnimationCurve")); n = FBX::Node("ObjectType", "AnimationCurve");
n.AddChild("Count", count); n.AddChild("Count", count);
object_nodes.push_back(n); object_nodes.push_back(n);
total_count += count; total_count += count;
@ -856,7 +908,7 @@ void FBXExporter::WriteDefinitions ()
if (mesh->HasBones()) { ++count; } if (mesh->HasBones()) { ++count; }
} }
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Pose")); n = FBX::Node("ObjectType", "Pose");
n.AddChild("Count", count); n.AddChild("Count", count);
object_nodes.push_back(n); object_nodes.push_back(n);
total_count += count; total_count += count;
@ -865,7 +917,7 @@ void FBXExporter::WriteDefinitions ()
// Deformer // Deformer
count = int32_t(count_deformers(mScene)); count = int32_t(count_deformers(mScene));
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("Deformer")); n = FBX::Node("ObjectType", "Deformer");
n.AddChild("Count", count); n.AddChild("Count", count);
object_nodes.push_back(n); object_nodes.push_back(n);
total_count += count; total_count += count;
@ -874,9 +926,9 @@ void FBXExporter::WriteDefinitions ()
// (template) // (template)
count = 0; count = 0;
if (count) { if (count) {
n = FBX::Node("ObjectType", Property("")); n = FBX::Node("ObjectType", "");
n.AddChild("Count", count); n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", Property("")); pt = FBX::Node("PropertyTemplate", "");
p = FBX::Node("Properties70"); p = FBX::Node("Properties70");
pt.AddChild(p); pt.AddChild(p);
n.AddChild(pt); n.AddChild(pt);
@ -889,7 +941,7 @@ void FBXExporter::WriteDefinitions ()
defs.AddChild("Version", int32_t(100)); defs.AddChild("Version", int32_t(100));
defs.AddChild("Count", int32_t(total_count)); defs.AddChild("Count", int32_t(total_count));
for (auto &n : object_nodes) { defs.AddChild(n); } for (auto &n : object_nodes) { defs.AddChild(n); }
defs.Dump(outfile); defs.Dump(outfile, binary, 0);
} }
@ -935,14 +987,20 @@ int64_t to_ktime(double ticks, const aiAnimation* anim) {
void FBXExporter::WriteObjects () void FBXExporter::WriteObjects ()
{ {
if (!binary) {
WriteAsciiSectionHeader("Object properties");
}
// numbers should match those given in definitions! make sure to check // numbers should match those given in definitions! make sure to check
StreamWriterLE outstream(outfile); StreamWriterLE outstream(outfile);
FBX::Node object_node("Objects"); FBX::Node object_node("Objects");
object_node.Begin(outstream); int indent = 0;
object_node.EndProperties(outstream); object_node.Begin(outstream, binary, indent);
object_node.EndProperties(outstream, binary, indent);
object_node.BeginChildren(outstream, binary, indent);
// geometry (aiMesh) // geometry (aiMesh)
mesh_uids.clear(); mesh_uids.clear();
indent = 1;
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
// it's all about this mesh // it's all about this mesh
aiMesh* m = mScene->mMeshes[mi]; aiMesh* m = mScene->mMeshes[mi];
@ -954,9 +1012,11 @@ void FBXExporter::WriteObjects ()
n.AddProperty(uid); n.AddProperty(uid);
n.AddProperty(FBX::SEPARATOR + "Geometry"); n.AddProperty(FBX::SEPARATOR + "Geometry");
n.AddProperty("Mesh"); n.AddProperty("Mesh");
n.Begin(outstream); n.Begin(outstream, binary, indent);
n.DumpProperties(outstream); n.DumpProperties(outstream, binary, indent);
n.EndProperties(outstream); n.EndProperties(outstream, binary, indent);
n.BeginChildren(outstream, binary, indent);
indent = 2;
// output vertex data - each vertex should be unique (probably) // output vertex data - each vertex should be unique (probably)
std::vector<double> flattened_vertices; std::vector<double> flattened_vertices;
@ -980,7 +1040,7 @@ void FBXExporter::WriteObjects ()
} }
} }
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"Vertices", flattened_vertices, outstream "Vertices", flattened_vertices, outstream, binary, indent
); );
// output polygon data as a flattened array of vertex indices. // output polygon data as a flattened array of vertex indices.
@ -996,30 +1056,38 @@ void FBXExporter::WriteObjects ()
); );
} }
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"PolygonVertexIndex", polygon_data, outstream "PolygonVertexIndex", polygon_data, outstream, binary, indent
); );
// here could be edges but they're insane. // here could be edges but they're insane.
// it's optional anyway, so let's ignore it. // it's optional anyway, so let's ignore it.
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"GeometryVersion", int32_t(124), outstream "GeometryVersion", int32_t(124), outstream, binary, indent
); );
// normals, if any // normals, if any
if (m->HasNormals()) { if (m->HasNormals()) {
FBX::Node normals("LayerElementNormal", Property(int32_t(0))); FBX::Node normals("LayerElementNormal", int32_t(0));
normals.Begin(outstream); normals.Begin(outstream, binary, indent);
normals.DumpProperties(outstream); normals.DumpProperties(outstream, binary, indent);
normals.EndProperties(outstream); normals.EndProperties(outstream, binary, indent);
FBX::Node::WritePropertyNode("Version", int32_t(101), outstream); normals.BeginChildren(outstream, binary, indent);
FBX::Node::WritePropertyNode("Name", "", outstream); indent = 3;
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"MappingInformationType", "ByPolygonVertex", outstream "Version", int32_t(101), outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"Name", "", outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"MappingInformationType", "ByPolygonVertex",
outstream, binary, indent
); );
// TODO: vertex-normals or indexed normals when appropriate // TODO: vertex-normals or indexed normals when appropriate
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"ReferenceInformationType", "Direct", outstream "ReferenceInformationType", "Direct",
outstream, binary, indent
); );
std::vector<double> normal_data; std::vector<double> normal_data;
normal_data.reserve(3 * polygon_data.size()); normal_data.reserve(3 * polygon_data.size());
@ -1032,10 +1100,13 @@ void FBXExporter::WriteObjects ()
normal_data.push_back(n.z); normal_data.push_back(n.z);
} }
} }
FBX::Node::WritePropertyNode("Normals", normal_data, outstream); FBX::Node::WritePropertyNode(
"Normals", normal_data, outstream, binary, indent
);
// note: version 102 has a NormalsW also... not sure what it is, // note: version 102 has a NormalsW also... not sure what it is,
// so we can stick with version 101 for now. // so we can stick with version 101 for now.
normals.End(outstream, true); indent = 2;
normals.End(outstream, binary, indent, true);
} }
// uvs, if any // uvs, if any
@ -1055,19 +1126,27 @@ void FBXExporter::WriteObjects ()
err << " but may be incorrectly interpreted on load."; err << " but may be incorrectly interpreted on load.";
DefaultLogger::get()->warn(err.str()); DefaultLogger::get()->warn(err.str());
} }
FBX::Node uv("LayerElementUV", Property(int32_t(uvi))); FBX::Node uv("LayerElementUV", int32_t(uvi));
uv.Begin(outstream); uv.Begin(outstream, binary, indent);
uv.DumpProperties(outstream); uv.DumpProperties(outstream, binary, indent);
uv.EndProperties(outstream); uv.EndProperties(outstream, binary, indent);
FBX::Node::WritePropertyNode("Version", int32_t(101), outstream); uv.BeginChildren(outstream, binary, indent);
indent = 3;
FBX::Node::WritePropertyNode(
"Version", int32_t(101), outstream, binary, indent
);
// it doesn't seem like assimp keeps the uv map name, // it doesn't seem like assimp keeps the uv map name,
// so just leave it blank. // so just leave it blank.
FBX::Node::WritePropertyNode("Name", "", outstream);
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"MappingInformationType", "ByPolygonVertex", outstream "Name", "", outstream, binary, indent
); );
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"ReferenceInformationType", "IndexToDirect", outstream "MappingInformationType", "ByPolygonVertex",
outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"ReferenceInformationType", "IndexToDirect",
outstream, binary, indent
); );
std::vector<double> uv_data; std::vector<double> uv_data;
@ -1092,27 +1171,32 @@ void FBXExporter::WriteObjects ()
} }
} }
} }
FBX::Node::WritePropertyNode("UV", uv_data, outstream); FBX::Node::WritePropertyNode(
FBX::Node::WritePropertyNode("UVIndex", uv_indices, outstream); "UV", uv_data, outstream, binary, indent
uv.End(outstream, true); );
FBX::Node::WritePropertyNode(
"UVIndex", uv_indices, outstream, binary, indent
);
indent = 2;
uv.End(outstream, binary, indent, true);
} }
// i'm not really sure why this material section exists, // i'm not really sure why this material section exists,
// as the material is linked via "Connections". // as the material is linked via "Connections".
// it seems to always have the same "0" value. // it seems to always have the same "0" value.
FBX::Node mat("LayerElementMaterial", Property(int32_t(0))); FBX::Node mat("LayerElementMaterial", int32_t(0));
mat.AddChild("Version", int32_t(101)); mat.AddChild("Version", int32_t(101));
mat.AddChild("Name", ""); mat.AddChild("Name", "");
mat.AddChild("MappingInformationType", "AllSame"); mat.AddChild("MappingInformationType", "AllSame");
mat.AddChild("ReferenceInformationType", "IndexToDirect"); mat.AddChild("ReferenceInformationType", "IndexToDirect");
std::vector<int32_t> mat_indices = {0}; std::vector<int32_t> mat_indices = {0};
mat.AddChild("Materials", mat_indices); mat.AddChild("Materials", mat_indices);
mat.Dump(outstream); mat.Dump(outstream, binary, indent);
// finally we have the layer specifications, // finally we have the layer specifications,
// which select the normals / UV set / etc to use. // which select the normals / UV set / etc to use.
// TODO: handle multiple uv sets correctly? // TODO: handle multiple uv sets correctly?
FBX::Node layer("Layer", Property(int32_t(0))); FBX::Node layer("Layer", int32_t(0));
layer.AddChild("Version", int32_t(100)); layer.AddChild("Version", int32_t(100));
FBX::Node le("LayerElement"); FBX::Node le("LayerElement");
le.AddChild("Type", "LayerElementNormal"); le.AddChild("Type", "LayerElementNormal");
@ -1126,10 +1210,11 @@ void FBXExporter::WriteObjects ()
le.AddChild("Type", "LayerElementUV"); le.AddChild("Type", "LayerElementUV");
le.AddChild("TypedIndex", int32_t(0)); le.AddChild("TypedIndex", int32_t(0));
layer.AddChild(le); layer.AddChild(le);
layer.Dump(outstream); layer.Dump(outstream, binary, indent);
// finish the node record // finish the node record
n.End(outstream, true); indent = 1;
n.End(outstream, binary, indent, true);
} }
// aiMaterial // aiMaterial
@ -1273,7 +1358,7 @@ void FBXExporter::WriteObjects ()
n.AddChild(p); n.AddChild(p);
n.Dump(outstream); n.Dump(outstream, binary, indent);
} }
// we need to look up all the images we're using, // we need to look up all the images we're using,
@ -1321,7 +1406,7 @@ void FBXExporter::WriteObjects ()
n.AddChild("UseMipMap", int32_t(0)); n.AddChild("UseMipMap", int32_t(0));
n.AddChild("Filename", path); n.AddChild("Filename", path);
n.AddChild("RelativeFilename", path); n.AddChild("RelativeFilename", path);
n.Dump(outstream); n.Dump(outstream, binary, indent);
} }
// Textures // Textures
@ -1408,14 +1493,12 @@ void FBXExporter::WriteObjects ()
const int64_t texture_uid = generate_uid(); const int64_t texture_uid = generate_uid();
// link the texture to the material // link the texture to the material
FBX::Node c("C"); connections.emplace_back(
c.AddProperties("OP", texture_uid, material_uid, prop_name); "C", "OP", texture_uid, material_uid, prop_name
connections.push_back(c); );
// link the image data to the texture // link the image data to the texture
c = FBX::Node("C"); connections.emplace_back("C", "OO", image_uid, texture_uid);
c.AddProperties("OO", image_uid, texture_uid);
connections.push_back(c);
// now write the actual texture node // now write the actual texture node
FBX::Node tnode("Texture"); FBX::Node tnode("Texture");
@ -1438,11 +1521,11 @@ void FBXExporter::WriteObjects ()
tnode.AddChild("RelativeFilename", texture_path); tnode.AddChild("RelativeFilename", texture_path);
tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0)); tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0));
tnode.AddChild("ModelUVScaling", double(1.0), double(1.0)); tnode.AddChild("ModelUVScaling", double(1.0), double(1.0));
tnode.AddChild("Texture_Alpha_Soutce", "None"); tnode.AddChild("Texture_Alpha_Source", "None");
tnode.AddChild( tnode.AddChild(
"Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0) "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0)
); );
tnode.Dump(outstream); tnode.Dump(outstream, binary, indent);
} }
} }
@ -1595,12 +1678,10 @@ void FBXExporter::WriteObjects ()
// "acuracy"... this is not a typo.... // "acuracy"... this is not a typo....
dnode.AddChild("Link_DeformAcuracy", double(50)); dnode.AddChild("Link_DeformAcuracy", double(50));
dnode.AddChild("SkinningType", "Linear"); // TODO: other modes? dnode.AddChild("SkinningType", "Linear"); // TODO: other modes?
dnode.Dump(outstream); dnode.Dump(outstream, binary, indent);
// connect it // connect it
FBX::Node c("C"); connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
c.AddProperties("OO", deformer_uid, mesh_uids[mi]);
connections.push_back(c); // TODO: emplace_back
// we will be indexing by vertex... // we will be indexing by vertex...
// but there might be a different number of "vertices" // but there might be a different number of "vertices"
@ -1703,7 +1784,7 @@ void FBXExporter::WriteObjects ()
// this should be the same as the bone's mOffsetMatrix. // this should be the same as the bone's mOffsetMatrix.
// if it's not the same, the skeleton isn't in the bind pose. // if it's not the same, the skeleton isn't in the bind pose.
const float epsilon = 1e-5f; // some error is to be expected const float epsilon = 1e-4f; // some error is to be expected
bool bone_xform_okay = true; bool bone_xform_okay = true;
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) { if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
not_in_bind_pose.insert(b); not_in_bind_pose.insert(b);
@ -1741,17 +1822,17 @@ void FBXExporter::WriteObjects ()
// there's not really any way around this at the moment. // there's not really any way around this at the moment.
// done // done
sdnode.Dump(outstream); sdnode.Dump(outstream, binary, indent);
// lastly, connect to the parent deformer // lastly, connect to the parent deformer
c = FBX::Node("C"); connections.emplace_back(
c.AddProperties("OO", subdeformer_uid, deformer_uid); "C", "OO", subdeformer_uid, deformer_uid
connections.push_back(c); // TODO: emplace_back );
// we also need to connect the limb node to the subdeformer. // we also need to connect the limb node to the subdeformer.
c = FBX::Node("C"); connections.emplace_back(
c.AddProperties("OO", node_uids[bone_node], subdeformer_uid); "C", "OO", node_uids[bone_node], subdeformer_uid
connections.push_back(c); // TODO: emplace_back );
} }
// if we cannot create a valid FBX file, simply die. // if we cannot create a valid FBX file, simply die.
@ -1859,7 +1940,7 @@ void FBXExporter::WriteObjects ()
} }
// now write it // now write it
bpnode.Dump(outstream); bpnode.Dump(outstream, binary, indent);
}*/ }*/
// TODO: cameras, lights // TODO: cameras, lights
@ -1918,11 +1999,8 @@ void FBXExporter::WriteObjects ()
// this node absurdly always pretends it has children // this node absurdly always pretends it has children
// (in this case it does, but just in case...) // (in this case it does, but just in case...)
asnode.Begin(outstream); asnode.force_has_children = true;
asnode.DumpProperties(outstream); asnode.Dump(outstream, binary, indent);
asnode.EndProperties(outstream);
asnode.DumpChildren(outstream);
asnode.End(outstream, true);
// note: animation stacks are not connected to anything // note: animation stacks are not connected to anything
} }
@ -1936,16 +2014,13 @@ void FBXExporter::WriteObjects ()
alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", ""); alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", "");
// this node absurdly always pretends it has children // this node absurdly always pretends it has children
alnode.Begin(outstream); alnode.force_has_children = true;
alnode.DumpProperties(outstream); alnode.Dump(outstream, binary, indent);
alnode.EndProperties(outstream);
alnode.DumpChildren(outstream);
alnode.End(outstream, true);
// connect to the relevant animstack // connect to the relevant animstack
FBX::Node c("C"); connections.emplace_back(
c.AddProperties("OO", animlayer_uid, animation_stack_uids[ai]); "C", "OO", animlayer_uid, animation_stack_uids[ai]
connections.push_back(c); // TODO: emplace_back );
} }
// AnimCurveNode - three per aiNodeAnim // AnimCurveNode - three per aiNodeAnim
@ -2057,7 +2132,8 @@ void FBXExporter::WriteObjects ()
} }
} }
object_node.End(outstream, true); indent = 0;
object_node.End(outstream, binary, indent, true);
} }
// convenience map of magic node name strings to FBX properties, // convenience map of magic node name strings to FBX properties,
@ -2083,13 +2159,14 @@ const std::map<std::string,std::pair<std::string,char>> transform_types = {
}; };
// write a single model node to the stream // write a single model node to the stream
void WriteModelNode( void FBXExporter::WriteModelNode(
StreamWriterLE& outstream, StreamWriterLE& outstream,
bool binary,
const aiNode* node, const aiNode* node,
int64_t node_uid, int64_t node_uid,
const std::string& type, const std::string& type,
const std::vector<std::pair<std::string,aiVector3D>>& transform_chain, const std::vector<std::pair<std::string,aiVector3D>>& transform_chain,
TransformInheritance inherit_type=TransformInheritance_RSrs TransformInheritance inherit_type
){ ){
const aiVector3D zero = {0, 0, 0}; const aiVector3D zero = {0, 0, 0};
const aiVector3D one = {1, 1, 1}; const aiVector3D one = {1, 1, 1};
@ -2157,7 +2234,7 @@ void WriteModelNode(
m.AddChild("Shading", Property(true)); m.AddChild("Shading", Property(true));
m.AddChild("Culling", Property("CullingOff")); m.AddChild("Culling", Property("CullingOff"));
m.Dump(outstream); m.Dump(outstream, binary, 1);
} }
// wrapper for WriteModelNodes to create and pass a blank transform chain // wrapper for WriteModelNodes to create and pass a blank transform chain
@ -2181,15 +2258,6 @@ void FBXExporter::WriteModelNodes(
// first collapse any expanded transformation chains created by FBX import. // first collapse any expanded transformation chains created by FBX import.
std::string node_name(node->mName.C_Str()); std::string node_name(node->mName.C_Str());
if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
if (node->mNumChildren != 1) {
// this should never happen
std::stringstream err;
err << "FBX transformation node should have exactly 1 child,";
err << " but " << node->mNumChildren << " found";
err << " on node \"" << node_name << "\"!";
throw DeadlyExportError(err.str());
}
aiNode* next_node = node->mChildren[0];
auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1; auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1;
std::string type_name = node_name.substr(pos); std::string type_name = node_name.substr(pos);
auto elem = transform_types.find(type_name); auto elem = transform_types.find(type_name);
@ -2223,10 +2291,16 @@ void FBXExporter::WriteModelNodes(
err << elem->second.second; err << elem->second.second;
throw DeadlyExportError(err.str()); throw DeadlyExportError(err.str());
} }
// now just continue to the next node // now continue on to any child nodes
WriteModelNodes( for (unsigned i = 0; i < node->mNumChildren; ++i) {
outstream, next_node, parent_uid, limbnodes, transform_chain WriteModelNodes(
); outstream,
node->mChildren[i],
parent_uid,
limbnodes,
transform_chain
);
}
return; return;
} }
@ -2240,9 +2314,7 @@ void FBXExporter::WriteModelNodes(
node_uid = generate_uid(); node_uid = generate_uid();
node_uids[node] = node_uid; node_uids[node] = node_uid;
} }
FBX::Node c("C"); connections.emplace_back("C", "OO", node_uid, parent_uid);
c.AddProperties("OO", node_uid, parent_uid);
connections.push_back(c);
} }
// what type of node is this? // what type of node is this?
@ -2250,21 +2322,23 @@ void FBXExporter::WriteModelNodes(
// handled later // handled later
} else if (node->mNumMeshes == 1) { } else if (node->mNumMeshes == 1) {
// connect to child mesh, which should have been written previously // connect to child mesh, which should have been written previously
FBX::Node c("C"); connections.emplace_back(
c.AddProperties("OO", mesh_uids[node->mMeshes[0]], node_uid); "C", "OO", mesh_uids[node->mMeshes[0]], node_uid
connections.push_back(c); );
// also connect to the material for the child mesh // also connect to the material for the child mesh
c = FBX::Node("C"); connections.emplace_back(
c.AddProperties( "C", "OO",
"OO",
material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex], material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex],
node_uid node_uid
); );
connections.push_back(c);
// write model node // write model node
WriteModelNode(outstream, node, node_uid, "Mesh", transform_chain); WriteModelNode(
outstream, binary, node, node_uid, "Mesh", transform_chain
);
} else if (limbnodes.count(node)) { } else if (limbnodes.count(node)) {
WriteModelNode(outstream, node, node_uid, "LimbNode", transform_chain); WriteModelNode(
outstream, binary, node, node_uid, "LimbNode", transform_chain
);
// we also need to write a nodeattribute to mark it as a skeleton // we also need to write a nodeattribute to mark it as a skeleton
int64_t node_attribute_uid = generate_uid(); int64_t node_attribute_uid = generate_uid();
FBX::Node na("NodeAttribute"); FBX::Node na("NodeAttribute");
@ -2272,14 +2346,14 @@ void FBXExporter::WriteModelNodes(
node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode" node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode"
); );
na.AddChild("TypeFlags", Property("Skeleton")); na.AddChild("TypeFlags", Property("Skeleton"));
na.Dump(outstream); na.Dump(outstream, binary, 1);
// and connect them // and connect them
FBX::Node c("C"); connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
c.AddProperties("OO", node_attribute_uid, node_uid);
connections.push_back(c);
} else { } else {
// generate a null node so we can add children to it // generate a null node so we can add children to it
WriteModelNode(outstream, node, node_uid, "Null", transform_chain); WriteModelNode(
outstream, binary, node, node_uid, "Null", transform_chain
);
} }
// if more than one child mesh, make nodes for each mesh // if more than one child mesh, make nodes for each mesh
@ -2288,23 +2362,19 @@ void FBXExporter::WriteModelNodes(
// make a new model node // make a new model node
int64_t new_node_uid = generate_uid(); int64_t new_node_uid = generate_uid();
// connect to parent node // connect to parent node
FBX::Node c("C"); connections.emplace_back("C", "OO", new_node_uid, node_uid);
c.AddProperties("OO", new_node_uid, node_uid);
connections.push_back(c);
// connect to child mesh, which should have been written previously // connect to child mesh, which should have been written previously
c = FBX::Node("C"); connections.emplace_back(
c.AddProperties("OO", mesh_uids[node->mMeshes[i]], new_node_uid); "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid
connections.push_back(c); );
// also connect to the material for the child mesh // also connect to the material for the child mesh
c = FBX::Node("C"); connections.emplace_back(
c.AddProperties( "C", "OO",
"OO",
material_uids[ material_uids[
mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex
], ],
new_node_uid new_node_uid
); );
connections.push_back(c);
// write model node // write model node
FBX::Node m("Model"); FBX::Node m("Model");
// take name from mesh name, if it exists // take name from mesh name, if it exists
@ -2315,7 +2385,7 @@ void FBXExporter::WriteModelNodes(
FBX::Node p("Properties70"); FBX::Node p("Properties70");
p.AddP70enum("InheritType", 1); p.AddP70enum("InheritType", 1);
m.AddChild(p); m.AddChild(p);
m.Dump(outstream); m.Dump(outstream, binary, 1);
} }
} }
@ -2344,15 +2414,11 @@ void FBXExporter::WriteAnimationCurveNode(
p.AddP70numberA("d|Y", default_value.y); p.AddP70numberA("d|Y", default_value.y);
p.AddP70numberA("d|Z", default_value.z); p.AddP70numberA("d|Z", default_value.z);
n.AddChild(p); n.AddChild(p);
n.Dump(outstream); n.Dump(outstream, binary, 1);
// connect to layer // connect to layer
FBX::Node cl("C"); this->connections.emplace_back("C", "OO", uid, layer_uid);
cl.AddProperties("OO", uid, layer_uid);
this->connections.push_back(cl); // TODO: emplace_back
// connect to bone // connect to bone
FBX::Node cb("C"); this->connections.emplace_back("C", "OP", uid, node_uid, property_name);
cb.AddProperties("OP", uid, node_uid, property_name);
this->connections.push_back(cb); // TODO: emplace_back
} }
@ -2379,10 +2445,10 @@ void FBXExporter::WriteAnimationCurve(
"KeyAttrRefCount", "KeyAttrRefCount",
std::vector<int32_t>{static_cast<int32_t>(times.size())} std::vector<int32_t>{static_cast<int32_t>(times.size())}
); );
n.Dump(outstream); n.Dump(outstream, binary, 1);
FBX::Node c("C"); this->connections.emplace_back(
c.AddProperties("OP", curve_uid, curvenode_uid, property_link); "C", "OP", curve_uid, curvenode_uid, property_link
this->connections.push_back(c); // TODO: emplace_back );
} }
@ -2390,13 +2456,18 @@ void FBXExporter::WriteConnections ()
{ {
// we should have completed the connection graph already, // we should have completed the connection graph already,
// so basically just dump it here // so basically just dump it here
if (!binary) {
WriteAsciiSectionHeader("Object connections");
}
// TODO: comments with names in the ascii version
FBX::Node conn("Connections"); FBX::Node conn("Connections");
StreamWriterLE outstream(outfile); StreamWriterLE outstream(outfile);
conn.Begin(outstream); conn.Begin(outstream, binary, 0);
conn.BeginChildren(outstream, binary, 0);
for (auto &n : connections) { for (auto &n : connections) {
n.Dump(outstream); n.Dump(outstream, binary, 1);
} }
conn.End(outstream, !connections.empty()); conn.End(outstream, binary, 0, !connections.empty());
connections.clear(); connections.clear();
} }

View File

@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportNode.h" // FBX::Node #include "FBXExportNode.h" // FBX::Node
#include "FBXCommon.h" // FBX::TransformInheritance
#include <assimp/types.h> #include <assimp/types.h>
//#include <assimp/material.h> //#include <assimp/material.h>
@ -104,6 +105,9 @@ namespace Assimp
void WriteBinaryHeader(); void WriteBinaryHeader();
void WriteBinaryFooter(); void WriteBinaryFooter();
// ascii files have a comment at the top
void WriteAsciiHeader();
// WriteAllNodes does the actual export. // WriteAllNodes does the actual export.
// It just calls all the Write<Section> methods below in order. // It just calls all the Write<Section> methods below in order.
void WriteAllNodes(); void WriteAllNodes();
@ -126,6 +130,7 @@ namespace Assimp
// WriteTakes(); // deprecated since at least 2015 (fbx 7.4) // WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
// helpers // helpers
void WriteAsciiSectionHeader(const std::string& title);
void WriteModelNodes( void WriteModelNodes(
Assimp::StreamWriterLE& s, Assimp::StreamWriterLE& s,
const aiNode* node, const aiNode* node,
@ -139,6 +144,15 @@ namespace Assimp
const std::unordered_set<const aiNode*>& limbnodes, const std::unordered_set<const aiNode*>& limbnodes,
std::vector<std::pair<std::string,aiVector3D>>& transform_chain 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( void WriteAnimationCurveNode(
StreamWriterLE& outstream, StreamWriterLE& outstream,
int64_t uid, int64_t uid,

View File

@ -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

View File

@ -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) {

78
code/simd.cpp 100644
View File

@ -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

53
code/simd.h 100644
View File

@ -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

View File

@ -283,7 +283,6 @@ public:
return *this; return *this;
} }
private:
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** Generic read method. ByteSwap::Swap(T*) *must* be defined */ /** Generic read method. ByteSwap::Swap(T*) *must* be defined */
template <typename T> template <typename T>
@ -300,6 +299,7 @@ private:
return f; return f;
} }
private:
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
void InternBegin() { void InternBegin() {
if (!stream) { if (!stream) {

View File

@ -203,6 +203,12 @@ public:
Put(n); Put(n);
} }
// ---------------------------------------------------------------------
/** Write a single character to the stream */
void PutChar(char c) {
Put(c);
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** Write an aiString to the stream */ /** Write an aiString to the stream */
void PutString(const aiString& s) void PutString(const aiString& s)
@ -249,8 +255,6 @@ public:
cursor = new_cursor; cursor = new_cursor;
} }
private:
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** Generic write method. ByteSwap::Swap(T*) *must* be defined */ /** Generic write method. ByteSwap::Swap(T*) *must* be defined */
template <typename T> template <typename T>

View File

@ -53,6 +53,7 @@ endif()
LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib ) LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib )
SET( COMMON SET( COMMON
unit/utSimd.cpp
unit/utIOSystem.cpp unit/utIOSystem.cpp
unit/utIOStreamBuffer.cpp unit/utIOStreamBuffer.cpp
unit/utIssues.cpp unit/utIssues.cpp

View File

@ -45,5 +45,5 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace ::Assimp; using namespace ::Assimp;
AbstractImportExportBase::~AbstractImportExportBase() { AbstractImportExportBase::~AbstractImportExportBase() {
// empty // empty
} }

View File

@ -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,
@ -106,4 +104,4 @@ TEST_F( utAnim, aiAnimationTest ) {
ok = false; ok = false;
} }
EXPECT_TRUE( ok ); EXPECT_TRUE( ok );
} }

View File

@ -0,0 +1,62 @@
/*
---------------------------------------------------------------------------
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 "UnitTestPCH.h"
#include "simd.h"
using namespace ::Assimp;
class utSimd : public ::testing::Test {
protected:
// empty
};
TEST_F( utSimd, SSE2SupportedTest ) {
bool isSupported;
isSupported = CPUSupportsSSE2();
if ( isSupported ) {
std::cout << "Supported" << std::endl;
} else {
std::cout << "Not supported" << std::endl;
}
}

View File

@ -46,12 +46,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Main.h" #include "Main.h"
#include <cstdio>
#include <iostream>
#include <string>
const char* AICMD_MSG_INFO_HELP_E = const char* AICMD_MSG_INFO_HELP_E =
"assimp info <file> [-r] [-v]\n" "assimp info <file> [-r] [-v]\n"
"\tPrint basic structure of a 3D model\n" "\tPrint basic structure of a 3D model\n"
"\t-r,--raw: No postprocessing, do a raw import\n" "\t-r,--raw: No postprocessing, do a raw import\n"
"\t-v,--verbose: Print verbose info such as node transform data\n"; "\t-v,--verbose: Print verbose info such as node transform data\n";
const std::string TREE_BRANCH_ASCII = "|-";
const std::string TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4";
const std::string TREE_STOP_ASCII = "'-";
const std::string TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4";
const std::string TREE_CONTINUE_ASCII = "| ";
const std::string TREE_CONTINUE_UTF8 = "\xe2\x94\x82 ";
// note: by default this is outputing utf-8 text.
// this is well supported on pretty much any linux terminal.
// if this causes problems on some platform,
// put an #ifdef to use the ascii version for that platform.
const std::string TREE_BRANCH = TREE_BRANCH_UTF8;
const std::string TREE_STOP = TREE_STOP_UTF8;
const std::string TREE_CONTINUE = TREE_CONTINUE_UTF8;
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
unsigned int CountNodes(const aiNode* root) unsigned int CountNodes(const aiNode* root)
@ -184,46 +203,77 @@ std::string FindPTypes(const aiScene* scene)
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline, // Prettily print the node graph to stdout
unsigned int cline, bool verbose, unsigned int cnest=0) void PrintHierarchy(
{ const aiNode* node,
if (cline++ >= maxline || cnest >= maxnest) { const std::string &indent,
return; bool verbose,
bool last = false,
bool first = true
){
// tree visualization
std::string branchchar;
if (first) { branchchar = ""; }
else if (last) { branchchar = TREE_STOP; } // "'-"
else { branchchar = TREE_BRANCH; } // "|-"
// print the indent and the branch character and the name
std::cout << indent << branchchar << node->mName.C_Str();
// if there are meshes attached, indicate this
if (node->mNumMeshes) {
std::cout << " (mesh ";
bool sep = false;
for (size_t i=0; i < node->mNumMeshes; ++i) {
unsigned int mesh_index = node->mMeshes[i];
if (sep) { std::cout << ", "; }
std::cout << mesh_index;
sep = true;
}
std::cout << ")";
} }
for(unsigned int i = 0; i < cnest; ++i) { // finish the line
printf("-- "); std::cout << std::endl;
}
printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
// in verbose mode, print the transform data as well
if (verbose) { if (verbose) {
// print the actual transform // indent to use
//printf(","); std::string indentadd;
if (last) { indentadd += " "; }
else { indentadd += TREE_CONTINUE; } // "| "..
if (node->mNumChildren == 0) { indentadd += " "; }
else { indentadd += TREE_CONTINUE; } // .."| "
aiVector3D s, r, t; aiVector3D s, r, t;
root->mTransformation.Decompose(s, r, t); node->mTransformation.Decompose(s, r, t);
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) { if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } std::cout << indent << indentadd;
printf(" S:[%f %f %f]\n", s.x, s.y, s.z); printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
} }
if (r.x || r.y || r.z) { if (r.x || r.y || r.z) {
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } std::cout << indent << indentadd;
printf(" R:[%f %f %f]\n", r.x, r.y, r.z); printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
} }
if (t.x || t.y || t.z) { if (t.x || t.y || t.z) {
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } std::cout << indent << indentadd;
printf(" T:[%f %f %f]\n", t.x, t.y, t.z); printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
} }
} }
//printf("\n");
for (unsigned int i = 0; i < root->mNumChildren; ++i ) { // and recurse
PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1); std::string nextIndent;
if(i == root->mNumChildren-1) { if (first) { nextIndent = indent; }
for(unsigned int i = 0; i < cnest; ++i) { else if (last) { nextIndent = indent + " "; }
printf(" "); else { nextIndent = indent + TREE_CONTINUE; } // "| "
} for (size_t i = 0; i < node->mNumChildren; ++i) {
printf("<--\n"); bool lastone = (i == node->mNumChildren - 1);
} PrintHierarchy(
node->mChildren[i],
nextIndent,
verbose,
lastone,
false
);
} }
} }
@ -406,8 +456,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
// node hierarchy // node hierarchy
printf("\nNode hierarchy:\n"); printf("\nNode hierarchy:\n");
unsigned int cline=0; PrintHierarchy(scene->mRootNode,"",verbose);
PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);
printf("\n"); printf("\n");
return 0; return 0;

View File

@ -560,6 +560,30 @@ void CGLView::Enable_Textures(const bool pEnable)
} }
} }
void CGLView::Enable_Axes(const bool pEnable){
if(pEnable)
{
this->mAxesEnabled = true;
}
else
{
this->mAxesEnabled = false;
}
}
void CGLView::Enable_Reload_Textures(const bool pEnable)
{
if(pEnable)
{
this->mReloadTexturesEnabled = true;
// this->mScene->ImportTextures(this->mScene->pScenePath);
}
else
{
this->mReloadTexturesEnabled = false;
}
}
/********************************************************************/ /********************************************************************/
/*********************** Override functions ************************/ /*********************** Override functions ************************/
/********************************************************************/ /********************************************************************/
@ -609,6 +633,7 @@ void CGLView::drawCoordSystem() {
// Z, -Z // Z, -Z
qglColor(QColor(Qt::blue)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0); qglColor(QColor(Qt::blue)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0);
qglColor(QColor(Qt::yellow)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0); qglColor(QColor(Qt::yellow)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0);
qglColor(QColor(Qt::white));
glEnd(); glEnd();
} }
@ -629,7 +654,10 @@ void CGLView::paintGL()
if ( mLightingEnabled ) { if ( mLightingEnabled ) {
glDisable( GL_LIGHTING );///TODO: display list glDisable( GL_LIGHTING );///TODO: display list
} }
drawCoordSystem(); if (this->mAxesEnabled == true)
{
drawCoordSystem();
}
glDisable(GL_COLOR_MATERIAL); glDisable(GL_COLOR_MATERIAL);
if(mLightingEnabled) glEnable(GL_LIGHTING); if(mLightingEnabled) glEnable(GL_LIGHTING);

View File

@ -75,7 +75,9 @@ private:
}; };
public: public:
bool mAxesEnabled = true;
// Textures
bool mReloadTexturesEnabled = false; // If true then textures will reload when the window is activated.
/// \enum ELightType /// \enum ELightType
/// Type of light source. /// Type of light source.
enum class ELightType { Directional, Point, Spot }; enum class ELightType { Directional, Point, Spot };
@ -155,7 +157,6 @@ private:
GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
// Lighting // Lighting
bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled. bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled.
// Textures
///TODO: map is goooood, but not for case when one image can be used in different materials with difference in: texture transformation, targeting of the ///TODO: map is goooood, but not for case when one image can be used in different materials with difference in: texture transformation, targeting of the
/// texture (ambient or emission, or even height map), texture properties. /// texture (ambient or emission, or even height map), texture properties.
QMap<QString, GLuint> mTexture_IDMap;///< Map image filenames to textures ID's. QMap<QString, GLuint> mTexture_IDMap;///< Map image filenames to textures ID's.
@ -306,6 +307,12 @@ public:
/// \param [in] pEnable - if true then enable textures, false - disable textures. /// \param [in] pEnable - if true then enable textures, false - disable textures.
void Enable_Textures(const bool pEnable); void Enable_Textures(const bool pEnable);
void Enable_Axes(const bool pEnable);
/// \fn void Enable_Textures(const bool pEnable)
/// Control textures drawing.
/// \param [in] pEnable - if true then enable textures, false - disable textures.
void Enable_Reload_Textures(const bool pEnable);
/********************************************************************/ /********************************************************************/
/******************** Lighting control functions ********************/ /******************** Lighting control functions ********************/
/********************************************************************/ /********************************************************************/

View File

@ -48,6 +48,7 @@ QTime time_begin = QTime::currentTime();
ui->cbxLighting->setChecked(true); mGLView->Lighting_Enable(); ui->cbxLighting->setChecked(true); mGLView->Lighting_Enable();
ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false); ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false);
ui->cbxTextures->setChecked(true); mGLView->Enable_Textures(true); ui->cbxTextures->setChecked(true); mGLView->Enable_Textures(true);
ui->cbxReloadTextures->setChecked(true); mGLView->Enable_Reload_Textures(false);
// //
// Fill info labels // Fill info labels
// //
@ -194,6 +195,13 @@ GLfloat step;
/********************************************************************/ /********************************************************************/
/********************** Constructor/Destructor **********************/ /********************** Constructor/Destructor **********************/
/********************************************************************/ /********************************************************************/
bool MainWindow::event(QEvent *e)
{
if (e->type() == QEvent::WindowActivate && this->mGLView->mReloadTexturesEnabled == true) {
qInfo() << "Window Activated";
}
return QWidget::event(e);
}
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), : QMainWindow(parent), ui(new Ui::MainWindow),
@ -364,6 +372,18 @@ void MainWindow::on_cbxBBox_clicked(bool checked)
mGLView->updateGL(); mGLView->updateGL();
} }
void MainWindow::on_cbxDrawAxes_clicked(bool checked)
{
mGLView->Enable_Axes(checked);
mGLView->updateGL();
}
void MainWindow::on_cbxReloadTextures_clicked(bool checked)
{
mGLView->Enable_Reload_Textures(checked);
mGLView->updateGL();
}
void MainWindow::on_cbxTextures_clicked(bool checked) void MainWindow::on_cbxTextures_clicked(bool checked)
{ {
mGLView->Enable_Textures(checked); mGLView->Enable_Textures(checked);

View File

@ -90,7 +90,7 @@ protected:
/// \param [in] pEvent - pointer to event data. /// \param [in] pEvent - pointer to event data.
void keyPressEvent(QKeyEvent* pEvent) override; void keyPressEvent(QKeyEvent* pEvent) override;
bool event(QEvent*);
public: public:
/********************************************************************/ /********************************************************************/
@ -133,4 +133,6 @@ private slots:
void on_lstCamera_clicked(const QModelIndex &index); void on_lstCamera_clicked(const QModelIndex &index);
void on_cbxBBox_clicked(bool checked); void on_cbxBBox_clicked(bool checked);
void on_cbxTextures_clicked(bool checked); void on_cbxTextures_clicked(bool checked);
void on_cbxDrawAxes_clicked(bool checked);
void on_cbxReloadTextures_clicked(bool checked);
}; };

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>641</width> <width>641</width>
<height>734</height> <height>778</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -501,6 +501,23 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QCheckBox" name="cbxDrawAxes">
<property name="text">
<string>Show Axes</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="cbxReloadTextures">
<property name="text">
<string>Live Reload Textures</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -513,4 +530,7 @@
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>
<connections/> <connections/>
<slots>
<signal>installEventFilter()</signal>
</slots>
</ui> </ui>