Merge branch 'master' into isue_1621

pull/1884/head
Kim Kulling 2018-04-06 20:54:01 +02:00 committed by GitHub
commit 483541ee25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
150 changed files with 7899 additions and 2509 deletions

View File

@ -110,7 +110,6 @@ if (WIN32)
endif() endif()
IF(MSVC) IF(MSVC)
SET (CMAKE_PREFIX_PATH "D:\\libs\\devil")
OPTION( ASSIMP_INSTALL_PDB OPTION( ASSIMP_INSTALL_PDB
"Install MSVC debug files." "Install MSVC debug files."
ON ON
@ -139,8 +138,7 @@ SET (PROJECT_VERSION "${ASSIMP_VERSION}")
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
# Needed for openddl_parser config, no use of c++11 at this moment # Enable C++1 globally
ADD_DEFINITIONS( -DOPENDDL_NO_USE_CPP11 )
set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
# Get the current working branch # Get the current working branch
@ -193,14 +191,6 @@ SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPO
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
IF( UNIX ) IF( UNIX )
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
IF( ${OPERATING_SYSTEM} MATCHES "Android")
ELSE()
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
#ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF()
ENDIF()
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
ENDIF( UNIX ) ENDIF( UNIX )
@ -213,13 +203,13 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
SET(LIBSTDC++_LIBRARIES -lstdc++) SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSEIF(MSVC) ELSEIF(MSVC)
# enable multi-core compilation with MSVC # enable multi-core compilation with MSVC
add_compile_options(/MP) ADD_COMPILE_OPTIONS(/MP)
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
add_compile_options( /bigobj ) ADD_COMPILE_OPTIONS( /bigobj )
endif() ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12) IF(MSVC12)
add_compile_options(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" )
@ -230,34 +220,39 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF() ENDIF()
if (ASSIMP_COVERALLS) IF (IOS)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
ENDIF()
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)
@ -290,42 +285,42 @@ ENDIF()
IF (NOT TARGET uninstall) IF (NOT TARGET uninstall)
# add make uninstall capability # add make uninstall capability
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF() ENDIF()
# cmake configuration files # cmake configuration files
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
FIND_PACKAGE( DirectX ) FIND_PACKAGE( DirectX )
IF( BUILD_DOCS ) IF( BUILD_DOCS )
add_subdirectory(doc) ADD_SUBDIRECTORY(doc)
ENDIF( BUILD_DOCS ) ENDIF( BUILD_DOCS )
# Look for system installed irrXML # Look for system installed irrXML
IF ( SYSTEM_IRRXML ) IF ( SYSTEM_IRRXML )
find_package( IrrXML REQUIRED ) FIND_PACKAGE( IrrXML REQUIRED )
ENDIF( SYSTEM_IRRXML ) ENDIF( SYSTEM_IRRXML )
# Search for external dependencies, and build them from source if not found # Search for external dependencies, and build them from source if not found
# Search for zlib # Search for zlib
IF ( NOT ASSIMP_BUILD_ZLIB ) IF ( NOT ASSIMP_BUILD_ZLIB )
find_package(ZLIB) FIND_PACKAGE(ZLIB)
ENDIF( NOT ASSIMP_BUILD_ZLIB ) ENDIF( NOT ASSIMP_BUILD_ZLIB )
IF( NOT ZLIB_FOUND ) IF( NOT ZLIB_FOUND )
message(STATUS "compiling zlib from souces") MESSAGE(STATUS "compiling zlib from souces")
INCLUDE(CheckIncludeFile) INCLUDE(CheckIncludeFile)
INCLUDE(CheckTypeSize) INCLUDE(CheckTypeSize)
INCLUDE(CheckFunctionExists) INCLUDE(CheckFunctionExists)
# compile from sources # compile from sources
add_subdirectory(contrib/zlib) ADD_SUBDIRECTORY(contrib/zlib)
SET(ZLIB_FOUND 1) SET(ZLIB_FOUND 1)
SET(ZLIB_LIBRARIES zlibstatic) SET(ZLIB_LIBRARIES zlibstatic)
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
else(NOT ZLIB_FOUND) ELSE(NOT ZLIB_FOUND)
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
SET(ZLIB_LIBRARIES_LINKED -lz) SET(ZLIB_LIBRARIES_LINKED -lz)
ENDIF(NOT ZLIB_FOUND) ENDIF(NOT ZLIB_FOUND)
@ -367,7 +362,9 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes") SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
# pick the correct prebuilt library # pick the correct prebuilt library
IF(MSVC14) IF(MSVC15)
SET(C4D_LIB_POSTFIX "_2017")
ELSEIF(MSVC14)
SET(C4D_LIB_POSTFIX "_2015") SET(C4D_LIB_POSTFIX "_2015")
ELSEIF(MSVC12) ELSEIF(MSVC12)
SET(C4D_LIB_POSTFIX "_2013") SET(C4D_LIB_POSTFIX "_2013")
@ -408,7 +405,7 @@ ADD_SUBDIRECTORY(contrib)
ADD_SUBDIRECTORY( code/ ) ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
IF ( WIN32 AND DirectX_D3DX9_LIBRARY ) IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} ) OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
IF ( ASSIMP_BUILD_ASSIMP_VIEW ) IF ( ASSIMP_BUILD_ASSIMP_VIEW )
ADD_SUBDIRECTORY( tools/assimp_view/ ) ADD_SUBDIRECTORY( tools/assimp_view/ )
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW ) ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
@ -472,8 +469,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
string(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
string(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools") SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" ) SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
@ -503,8 +500,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release") SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
ENDIF() ENDIF()
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources") SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
include(CPack) INCLUDE(CPack)
include(DebSourcePPA) INCLUDE(DebSourcePPA)
ENDIF() ENDIF()
if(WIN32) if(WIN32)
@ -516,14 +513,16 @@ if(WIN32)
SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/") SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/")
ENDIF() ENDIF()
if(MSVC12) IF(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120") SET(ASSIMP_MSVC_VERSION "vc120")
elseif(MSVC14) ELSEIF(MSVC14)
SET(ASSIMP_MSVC_VERSION "vc140") SET(ASSIMP_MSVC_VERSION "vc140")
ELSEIF(MSVC15)
SET(ASSIMP_MSVC_VERSION "vc141")
ENDIF(MSVC12) ENDIF(MSVC12)
if(MSVC12 OR MSVC14) IF(MSVC12 OR MSVC14 OR MSVC15 )
add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) ADD_CUSTOM_TARGET(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
IF(CMAKE_GENERATOR MATCHES "^Visual Studio") IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
@ -544,5 +543,5 @@ if(WIN32)
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
ENDIF() ENDIF()
ENDIF(MSVC12 OR MSVC14) ENDIF(MSVC12 OR MSVC14 OR MSVC15 )
ENDIF (WIN32) ENDIF (WIN32)

17
CREDITS
View File

@ -157,12 +157,27 @@ Contributed ExportProperties interface
Contributed X File exporter Contributed X File exporter
Contributed Step (stp) exporter Contributed Step (stp) exporter
- Thomas Iorns (mesilliac)
Initial FBX Export support
For a more detailed list just check: https://github.com/assimp/assimp/network/members For a more detailed list just check: https://github.com/assimp/assimp/network/members
Patreons:
========
Patreons
========
Huge thanks to our Patreons!
- migenius - migenius
- Marcus - Marcus
- Cort - Cort
- elect - elect
- Steffen - Steffen
===================
Commercial Sponsors
===================
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support

View File

@ -32,32 +32,32 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki
#### Supported file formats #### #### Supported file formats ####
A full list [is here](http://assimp.org/main_features_formats.html).
__Importers__: __Importers__:
- 3D - 3D
- 3DS - [3DS](https://en.wikipedia.org/wiki/.3ds)
- 3MF - [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format)
- AC - AC
- AC3D - [AC3D](https://en.wikipedia.org/wiki/AC3D)
- ACC - ACC
- AMJ - AMJ
- ASE - ASE
- ASK - ASK
- B3D - B3D
- BLEND (Blender) - [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
- BVH - [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
- COB
- CMS - CMS
- DAE/Collada - COB
- DXF - [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA)
- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF)
- ENFF - ENFF
- FBX - [FBX](https://en.wikipedia.org/wiki/FBX)
- glTF 1.0 + GLB - [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
- glTF 2.0 - [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0)
- HMB - HMB
- IFC-STEP - IFC-STEP
- IRR / IRRMESH - IRR / IRRMESH
- LWO - [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
- LWS - LWS
- LXO - LXO
- MD2 - MD2
@ -70,10 +70,10 @@ __Importers__:
- MS3D - MS3D
- NDO - NDO
- NFF - NFF
- OBJ - [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
- OFF - [OFF](https://en.wikipedia.org/wiki/OFF_(file_format))
- OGEX - [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange)
- PLY - [PLY](https://en.wikipedia.org/wiki/PLY_(file_format))
- PMX - PMX
- PRJ - PRJ
- Q3O - Q3O
@ -82,19 +82,19 @@ __Importers__:
- SCN - SCN
- SIB - SIB
- SMD - SMD
- STL - [STP](https://en.wikipedia.org/wiki/ISO_10303-21)
- STP - [STL](https://en.wikipedia.org/wiki/STL_(file_format))
- TER - TER
- UC - UC
- VTA - VTA
- X - X
- X3D - [X3D](https://en.wikipedia.org/wiki/X3D)
- XGL - XGL
- ZGL - ZGL
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
- C4D (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) - [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange)
__Exporters__: __Exporters__:
@ -109,6 +109,8 @@ __Exporters__:
- STEP - STEP
- glTF 1.0 (partial) - glTF 1.0 (partial)
- glTF 2.0 (partial) - glTF 2.0 (partial)
- 3MF ( experimental )
- FBX ( experimental )
### Building ### ### Building ###
Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do. Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
@ -120,7 +122,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
* [Pascal](port/AssimpPascal/Readme.md) * [Pascal](port/AssimpPascal/Readme.md)
* [Javascript (Alpha)](https://github.com/makc/assimp2json) * [Javascript (Alpha)](https://github.com/makc/assimp2json)
* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777) * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, collada, md2) * [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
### Other tools ### ### Other tools ###
[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.

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

@ -72,7 +72,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
unsigned int idx( NotSet ); unsigned int idx( NotSet );
for (unsigned int i = 0; i < mScene->mMaterials.size();++i) for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
{ {
std::string s = mScene->mMaterials[i].mName; std::string &s = mScene->mMaterials[i].mName;
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) { for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
*it = static_cast< char >( ::tolower( *it ) ); *it = static_cast< char >( ::tolower( *it ) );
} }

View File

@ -184,7 +184,7 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
} // end of namespace Assimp } // end of namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* scene) Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
: scene(scene) : scene(scene)
, writer(outfile) , writer(outfile)
{ {

View File

@ -67,7 +67,7 @@ namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
class Discreet3DSExporter { class Discreet3DSExporter {
public: public:
Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene); Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* pScene);
~Discreet3DSExporter(); ~Discreet3DSExporter();
private: private:

View File

@ -71,7 +71,7 @@ static const aiImporterDesc desc = {
0, 0,
0, 0,
0, 0,
"3ds prj" "3ds prj 3DS PRJ"
}; };
@ -113,22 +113,24 @@ Discreet3DSImporter::Discreet3DSImporter()
, mScene() , mScene()
, mMasterScale() , mMasterScale()
, bHasBG() , bHasBG()
, bIsPrj() , bIsPrj() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
Discreet3DSImporter::~Discreet3DSImporter() Discreet3DSImporter::~Discreet3DSImporter() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if(extension == "3ds" || extension == "prj" ) { if(extension == "3ds" || extension == "3DS" || extension == "prj"|| extension == "PRJ" ) {
return true; return true;
} }
if (!extension.length() || checkSig) { if (!extension.length() || checkSig) {
uint16_t token[3]; uint16_t token[3];
token[0] = 0x4d4d; token[0] = 0x4d4d;
@ -210,7 +212,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
ConvertScene(pScene); ConvertScene(pScene);
// Generate the node graph for the scene. This is a little bit // Generate the node graph for the scene. This is a little bit
// tricky since we'll need to split some meshes into submeshes // tricky since we'll need to split some meshes into sub-meshes
GenerateNodeGraph(pScene); GenerateNodeGraph(pScene);
// Now apply the master scaling factor to the scene // Now apply the master scaling factor to the scene
@ -347,7 +349,7 @@ void Discreet3DSImporter::ParseObjectChunk()
case Discreet3DS::CHUNK_MAT_MATERIAL: case Discreet3DS::CHUNK_MAT_MATERIAL:
// Add a new material to the list // Add a new material to the list
mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + std::to_string(mScene->mMaterials.size())))); mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + to_string(mScene->mMaterials.size()))));
ParseMaterialChunk(); ParseMaterialChunk();
break; break;

View File

@ -45,6 +45,11 @@ namespace Assimp {
namespace D3MF { namespace D3MF {
namespace XmlTag { namespace XmlTag {
// Meta-data
static const std::string meta = "metadata";
static const std::string meta_name = "name";
// Model-data specific tags
static const std::string model = "model"; static const std::string model = "model";
static const std::string model_unit = "unit"; static const std::string model_unit = "unit";
static const std::string metadata = "metadata"; static const std::string metadata = "metadata";
@ -62,6 +67,8 @@ namespace XmlTag {
static const std::string v2 = "v2"; static const std::string v2 = "v2";
static const std::string v3 = "v3"; static const std::string v3 = "v3";
static const std::string id = "id"; static const std::string id = "id";
static const std::string pid = "pid";
static const std::string p1 = "p1";
static const std::string name = "name"; static const std::string name = "name";
static const std::string type = "type"; static const std::string type = "type";
static const std::string build = "build"; static const std::string build = "build";
@ -69,6 +76,14 @@ namespace XmlTag {
static const std::string objectid = "objectid"; static const std::string objectid = "objectid";
static const std::string transform = "transform"; static const std::string transform = "transform";
// Material definitions
static const std::string basematerials = "basematerials";
static const std::string basematerials_id = "id";
static const std::string basematerials_base = "base";
static const std::string basematerials_name = "name";
static const std::string basematerials_displaycolor = "displaycolor";
// Meta info tags
static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml"; static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels"; static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types"; static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
@ -83,7 +98,6 @@ namespace XmlTag {
static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture"; static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"; static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
} }
} // Namespace D3MF } // Namespace D3MF

View File

@ -156,10 +156,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
TextureConverted_Index = 0; TextureConverted_Index = 0;
for(const SPP_Texture& tex_convd: mTexture_Converted) for(const SPP_Texture& tex_convd: mTexture_Converted)
{ {
if(tex_convd.ID == TextureConverted_ID) if ( tex_convd.ID == TextureConverted_ID ) {
return TextureConverted_Index; return TextureConverted_Index;
else } else {
TextureConverted_Index++; ++TextureConverted_Index;
}
} }
// //

View File

@ -583,7 +583,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
node->mTransformation = mParentAdjust*snode->mTransform; node->mTransformation = mParentAdjust*snode->mTransform;
// Add sub nodes - prevent stack overflow due to recursive parenting // Add sub nodes - prevent stack overflow due to recursive parenting
if (node->mName != node->mParent->mName) { if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName ) {
AddNodes(nodes,node,node->mName.data,snode->mTransform); AddNodes(nodes,node,node->mName.data,snode->mTransform);
} }

View File

@ -267,7 +267,9 @@ void Parser::Parse()
// at the file extension (ASE, ASK, ASC) // at the file extension (ASE, ASK, ASC)
// ************************************************************* // *************************************************************
if (fmt)iFileFormat = fmt; if ( fmt ) {
iFileFormat = fmt;
}
continue; continue;
} }
// main scene information // main scene information
@ -427,27 +429,24 @@ void Parser::ParseLV1SoftSkinBlock()
// Reserve enough storage // Reserve enough storage
vert.mBoneWeights.reserve(numWeights); vert.mBoneWeights.reserve(numWeights);
for (unsigned int w = 0; w < numWeights;++w)
{
std::string bone; std::string bone;
for (unsigned int w = 0; w < numWeights;++w) {
bone.clear();
ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
// Find the bone in the mesh's list // Find the bone in the mesh's list
std::pair<int,ai_real> me; std::pair<int,ai_real> me;
me.first = -1; me.first = -1;
for (unsigned int n = 0; n < curMesh->mBones.size();++n) for (unsigned int n = 0; n < curMesh->mBones.size();++n) {
{ if (curMesh->mBones[n].mName == bone) {
if (curMesh->mBones[n].mName == bone)
{
me.first = n; me.first = n;
break; break;
} }
} }
if (-1 == me.first) if (-1 == me.first) {
{
// We don't have this bone yet, so add it to the list // We don't have this bone yet, so add it to the list
me.first = (int)curMesh->mBones.size(); me.first = static_cast<int>( curMesh->mBones.size() );
curMesh->mBones.push_back( ASE::Bone( bone ) ); curMesh->mBones.push_back( ASE::Bone( bone ) );
} }
ParseLV4MeshFloat( me.second ); ParseLV4MeshFloat( me.second );
@ -745,6 +744,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
// empty the texture won't be used later. // empty the texture won't be used later.
// *********************************************************** // ***********************************************************
bool parsePath = true; bool parsePath = true;
std::string temp;
while (true) while (true)
{ {
if ('*' == *filePtr) if ('*' == *filePtr)
@ -753,7 +753,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
// type of map // type of map
if (TokenMatch(filePtr,"MAP_CLASS" ,9)) if (TokenMatch(filePtr,"MAP_CLASS" ,9))
{ {
std::string temp; temp.clear();
if(!ParseString(temp,"*MAP_CLASS")) if(!ParseString(temp,"*MAP_CLASS"))
SkipToNextToken(); SkipToNextToken();
if (temp != "Bitmap" && temp != "Normal Bump") if (temp != "Bitmap" && temp != "Normal Bump")

View File

@ -199,6 +199,7 @@ aiNode* BVHLoader::ReadNode()
Node& internNode = mNodes.back(); Node& internNode = mNodes.back();
// now read the node's contents // now read the node's contents
std::string siteToken;
while( 1) while( 1)
{ {
std::string token = GetNextToken(); std::string token = GetNextToken();
@ -218,7 +219,8 @@ aiNode* BVHLoader::ReadNode()
else if( token == "End") else if( token == "End")
{ {
// The real symbol is "End Site". Second part comes in a separate token // The real symbol is "End Site". Second part comes in a separate token
std::string siteToken = GetNextToken(); siteToken.clear();
siteToken = GetNextToken();
if( siteToken != "Site") if( siteToken != "Site")
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." ); ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
@ -262,21 +264,18 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
aiNode* node = new aiNode( "EndSite_" + pParentName); aiNode* node = new aiNode( "EndSite_" + pParentName);
// now read the node's contents. Only possible entry is "OFFSET" // now read the node's contents. Only possible entry is "OFFSET"
while( 1) std::string token;
{ while( 1) {
std::string token = GetNextToken(); token.clear();
token = GetNextToken();
// end node's offset // end node's offset
if( token == "OFFSET") if( token == "OFFSET") {
{
ReadNodeOffset( node); ReadNodeOffset( node);
} } else if( token == "}") {
else if( token == "}")
{
// we're done with the end node // we're done with the end node
break; break;
} else } else {
{
// everything else is a parse error // everything else is a parse error
ThrowException( format() << "Unknown keyword \"" << token << "\"." ); ThrowException( format() << "Unknown keyword \"" << token << "\"." );
} }
@ -296,8 +295,10 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
offset.z = GetNextTokenAsFloat(); offset.z = GetNextTokenAsFloat();
// build a transformation matrix from it // build a transformation matrix from it
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z,
0.0f, 0.0f, 0.0f, 1.0f);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -84,7 +84,10 @@ class BVHLoader : public BaseImporter
std::vector<ChannelType> mChannels; std::vector<ChannelType> mChannels;
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
Node() { } Node()
: mNode(nullptr)
{ }
explicit Node( const aiNode* pNode) : mNode( pNode) { } explicit Node( const aiNode* pNode) : mNode( pNode) { }
}; };

View File

@ -115,13 +115,12 @@ void BaseImporter::SetupProperties(const Importer* /*pImp*/)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BaseImporter::GetExtensionList(std::set<std::string>& extensions) void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
{
const aiImporterDesc* desc = GetInfo(); const aiImporterDesc* desc = GetInfo();
ai_assert(desc != NULL); ai_assert(desc != nullptr);
const char* ext = desc->mFileExtensions; const char* ext = desc->mFileExtensions;
ai_assert(ext != NULL); ai_assert(ext != nullptr );
const char* last = ext; const char* last = ext;
do { do {
@ -145,21 +144,19 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
unsigned int searchBytes /* = 200 */, unsigned int searchBytes /* = 200 */,
bool tokensSol /* false */) bool tokensSol /* false */)
{ {
ai_assert( NULL != tokens ); ai_assert( nullptr != tokens );
ai_assert( 0 != numTokens ); ai_assert( 0 != numTokens );
ai_assert( 0 != searchBytes); ai_assert( 0 != searchBytes);
if (!pIOHandler) if ( nullptr == pIOHandler ) {
return false; return false;
}
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile)); std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
if (pStream.get() ) { if (pStream.get() ) {
// read 200 characters from the file // read 200 characters from the file
std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]); std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
char* buffer = _buffer.get(); char* buffer = _buffer.get();
if( NULL == buffer ) {
return false;
}
const size_t read = pStream->Read(buffer,1,searchBytes); const size_t read = pStream->Read(buffer,1,searchBytes);
if( !read ) { if( !read ) {
@ -181,9 +178,17 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
} }
*cur2 = '\0'; *cur2 = '\0';
std::string token;
for (unsigned int i = 0; i < numTokens; ++i ) { for (unsigned int i = 0; i < numTokens; ++i ) {
ai_assert(NULL != tokens[i]); ai_assert( nullptr != tokens[i] );
const char* r = strstr(buffer,tokens[i]); const size_t len( strlen( tokens[ i ] ) );
token.clear();
const char *ptr( tokens[ i ] );
for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
token.push_back( tolower( *ptr ) );
++ptr;
}
const char* r = strstr( buffer, token.c_str() );
if( !r ) { if( !r ) {
continue; continue;
} }
@ -246,7 +251,8 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
const void* _magic, unsigned int num, unsigned int offset, unsigned int size) const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
{ {
ai_assert(size <= 16 && _magic); ai_assert( size <= 16 );
ai_assert( _magic );
if (!pIOHandler) { if (!pIOHandler) {
return false; return false;

View File

@ -58,12 +58,11 @@ using namespace Assimp::Formatter;
static bool match4(StreamReaderAny& stream, const char* string) { static bool match4(StreamReaderAny& stream, const char* string) {
ai_assert( nullptr != string ); ai_assert( nullptr != string );
char tmp[] = { char tmp[4];
(const char)(stream).GetI1(), tmp[ 0 ] = ( stream ).GetI1();
(const char)(stream).GetI1(), tmp[ 1 ] = ( stream ).GetI1();
(const char)(stream).GetI1(), tmp[ 2 ] = ( stream ).GetI1();
(const char)(stream).GetI1() tmp[ 3 ] = ( stream ).GetI1();
};
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
} }

View File

@ -205,7 +205,7 @@ enum ErrorPolicy {
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** Represents a data structure in a BLEND file. A Structure defines n fields /** Represents a data structure in a BLEND file. A Structure defines n fields
* and their locatios and encodings the input stream. Usually, every * and their locations and encodings the input stream. Usually, every
* Structure instance pertains to one equally-named data structure in the * Structure instance pertains to one equally-named data structure in the
* BlenderScene.h header. This class defines various utilities to map a * BlenderScene.h header. This class defines various utilities to map a
* binary `blob` read from the file to such a structure instance with * binary `blob` read from the file to such a structure instance with

View File

@ -502,7 +502,7 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
{ {
// the file blocks appear in list sorted by // the file blocks appear in list sorted by
// with ascending base addresses so we can run a // with ascending base addresses so we can run a
// binary search to locate the pointee quickly. // binary search to locate the pointer quickly.
// NOTE: Blender seems to distinguish between side-by-side // NOTE: Blender seems to distinguish between side-by-side
// data (stored in the same data block) and far pointers, // data (stored in the same data block) and far pointers,

View File

@ -122,9 +122,11 @@ namespace Blender {
# pragma warning(disable:4351) # pragma warning(disable:4351)
#endif #endif
// As counter-intuitive as it may seem, a comparator must return false for equal values.
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
struct ObjectCompare { struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const { bool operator() (const Object* left, const Object* right) const {
return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) == 0; return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
} }
}; };
@ -143,9 +145,11 @@ namespace Blender {
, db(db) , db(db)
{} {}
// As counter-intuitive as it may seem, a comparator must return false for equal values.
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
struct ObjectCompare { struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const { bool operator() (const Object* left, const Object* right) const {
return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) == 0; return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
} }
}; };

View File

@ -154,14 +154,6 @@ void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
// nothing to be done for the moment // nothing to be done for the moment
} }
struct free_it {
free_it(void* free) : free(free) {}
~free_it() {
::free(this->free);
}
void* free;
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
@ -169,8 +161,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
Bytef* dest = NULL; std::vector<Bytef> uncompressed;
free_it free_it_really(dest);
#endif #endif
@ -218,6 +209,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
size_t total = 0l; size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024 #define MYBLOCK 1024
Bytef block[MYBLOCK]; Bytef block[MYBLOCK];
@ -232,8 +224,8 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
} }
const size_t have = MYBLOCK - zstream.avail_out; const size_t have = MYBLOCK - zstream.avail_out;
total += have; total += have;
dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); uncompressed.resize(total);
memcpy(dest + total - have,block,have); memcpy(uncompressed.data() + total - have,block,have);
} }
while (ret != Z_STREAM_END); while (ret != Z_STREAM_END);
@ -241,7 +233,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
inflateEnd(&zstream); inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
// .. and retry // .. and retry
stream->Read(magic,7,1); stream->Read(magic,7,1);

View File

@ -116,7 +116,7 @@ template <> void Structure :: Convert<MTex> (
ReadField<ErrorPolicy_Igno>(temp,"projy",db); ReadField<ErrorPolicy_Igno>(temp,"projy",db);
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp); dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp,"projz",db); ReadField<ErrorPolicy_Igno>(temp,"projz",db);
dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp); dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db); ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db); ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db); ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);

View File

@ -72,6 +72,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/matrix4x4.h ${HEADER_PATH}/matrix4x4.h
${HEADER_PATH}/matrix4x4.inl ${HEADER_PATH}/matrix4x4.inl
${HEADER_PATH}/mesh.h ${HEADER_PATH}/mesh.h
${HEADER_PATH}/pbrmaterial.h
${HEADER_PATH}/postprocess.h ${HEADER_PATH}/postprocess.h
${HEADER_PATH}/quaternion.h ${HEADER_PATH}/quaternion.h
${HEADER_PATH}/quaternion.inl ${HEADER_PATH}/quaternion.inl
@ -176,8 +177,6 @@ SET( Common_SRCS
SkeletonMeshBuilder.cpp SkeletonMeshBuilder.cpp
SplitByBoneCountProcess.cpp SplitByBoneCountProcess.cpp
SplitByBoneCountProcess.h SplitByBoneCountProcess.h
ScaleProcess.cpp
ScaleProcess.h
StandardShapes.cpp StandardShapes.cpp
TargetAnimation.cpp TargetAnimation.cpp
TargetAnimation.h TargetAnimation.h
@ -187,6 +186,8 @@ SET( Common_SRCS
Bitmap.cpp Bitmap.cpp
Version.cpp Version.cpp
CreateAnimMesh.cpp CreateAnimMesh.cpp
simd.h
simd.cpp
) )
SOURCE_GROUP(Common FILES ${Common_SRCS}) SOURCE_GROUP(Common FILES ${Common_SRCS})
@ -484,9 +485,9 @@ ADD_ASSIMP_IMPORTER( IFC
) )
if (ASSIMP_BUILD_IFC_IMPORTER) if (ASSIMP_BUILD_IFC_IMPORTER)
if (MSVC) if (MSVC)
set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "/bigobj") set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
elseif(CMAKE_COMPILER_IS_MINGW) elseif(CMAKE_COMPILER_IS_MINGW)
set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj") set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj")
endif() endif()
endif (ASSIMP_BUILD_IFC_IMPORTER) endif (ASSIMP_BUILD_IFC_IMPORTER)
@ -522,6 +523,13 @@ ADD_ASSIMP_IMPORTER( FBX
FBXDeformer.cpp FBXDeformer.cpp
FBXBinaryTokenizer.cpp FBXBinaryTokenizer.cpp
FBXDocumentUtil.cpp FBXDocumentUtil.cpp
FBXExporter.h
FBXExporter.cpp
FBXExportNode.h
FBXExportNode.cpp
FBXExportProperty.h
FBXExportProperty.cpp
FBXCommon.h
) )
SET( PostProcessing_SRCS SET( PostProcessing_SRCS
@ -578,6 +586,8 @@ SET( PostProcessing_SRCS
PolyTools.h PolyTools.h
MakeVerboseFormat.cpp MakeVerboseFormat.cpp
MakeVerboseFormat.h MakeVerboseFormat.h
ScaleProcess.cpp
ScaleProcess.h
) )
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})

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

@ -136,7 +136,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
TextFileToBuffer(file.get(),mBuffer2); TextFileToBuffer(file.get(),mBuffer2);
const char* buffer = &mBuffer2[0]; const char* buffer = &mBuffer2[0];
aiAnimation* anim = new aiAnimation(); std::unique_ptr<aiAnimation> anim(new aiAnimation());
int first = 0, last = 0x00ffffff; int first = 0, last = 0x00ffffff;
// now process the file and look out for '$' sections // now process the file and look out for '$' sections
@ -294,8 +294,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
// Store the one and only animation in the scene // Store the one and only animation in the scene
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1]; pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
pScene->mAnimations[0] = anim;
anim->mName.Set("$CSM_MasterAnim"); anim->mName.Set("$CSM_MasterAnim");
pScene->mAnimations[0] = anim.release();
// mark the scene as incomplete and run SkeletonMeshBuilder on it // mark the scene as incomplete and run SkeletonMeshBuilder on it
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;

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

@ -1270,6 +1270,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr; mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
PushTag(); PushTag();
std::string node_idstr;
for (size_t a = 0; a < anim->mNumChannels; ++a) { for (size_t a = 0; a < anim->mNumChannels; ++a) {
const aiNodeAnim * nodeAnim = anim->mChannels[a]; const aiNodeAnim * nodeAnim = anim->mChannels[a];
@ -1277,7 +1278,9 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue; if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
{ {
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-input"); node_idstr.clear();
node_idstr += nodeAnim->mNodeName.data;
node_idstr += std::string( "_matrix-input" );
std::vector<ai_real> frames; std::vector<ai_real> frames;
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
@ -1289,12 +1292,14 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
} }
{ {
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-output"); node_idstr.clear();
node_idstr += nodeAnim->mNodeName.data;
node_idstr += std::string("_matrix-output");
std::vector<ai_real> keyframes; std::vector<ai_real> keyframes;
keyframes.reserve(nodeAnim->mNumPositionKeys * 16); keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue; aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
aiMatrix4x4 ScalingM; // identity aiMatrix4x4 ScalingM; // identity
ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z; ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
@ -1361,7 +1366,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
PopTag(); PopTag();
mOutput << startstr << "</source>" << endstr; mOutput << startstr << "</source>" << endstr;
} }
} }
for (size_t a = 0; a < anim->mNumChannels; ++a) { for (size_t a = 0; a < anim->mNumChannels; ++a) {

View File

@ -131,6 +131,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
{ {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1120,6 +1121,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
continue; continue;
// now check all channels if they affect the current node // now check all channels if they affect the current node
std::string targetID, subElement;
for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin(); for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
cit != pSrcAnim->mChannels.end(); ++cit) cit != pSrcAnim->mChannels.end(); ++cit)
{ {
@ -1146,7 +1148,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
} }
if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos) if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
continue; continue;
std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
targetID.clear();
targetID = srcChannel.mTarget.substr( 0, slashPos);
if( targetID != srcNode->mID) if( targetID != srcNode->mID)
continue; continue;
@ -1159,7 +1163,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1); entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
std::string subElement = srcChannel.mTarget.substr( dotPos+1); subElement.clear();
subElement = srcChannel.mTarget.substr( dotPos+1);
if( subElement == "ANGLE") if( subElement == "ANGLE")
entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
else if( subElement == "X") else if( subElement == "X")
@ -1180,7 +1185,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
if (bracketPos != std::string::npos) if (bracketPos != std::string::npos)
{ {
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1); entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
std::string subElement = srcChannel.mTarget.substr(bracketPos); subElement.clear();
subElement = srcChannel.mTarget.substr(bracketPos);
if (subElement == "(0)(0)") if (subElement == "(0)(0)")
entry.mSubElement = 0; entry.mSubElement = 0;
@ -1214,7 +1220,6 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
entry.mSubElement = 14; entry.mSubElement = 14;
else if (subElement == "(3)(3)") else if (subElement == "(3)(3)")
entry.mSubElement = 15; entry.mSubElement = 15;
} }
// determine which transform step is affected by this channel // determine which transform step is affected by this channel
@ -1913,6 +1918,11 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
// The name must be unique for proper node-bone association. // The name must be unique for proper node-bone association.
std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
{ {
// If explicitly requested, just use the collada name.
if (useColladaName) {
return pNode->mName;
}
// Now setup the name of the assimp node. The collada name might not be // Now setup the name of the assimp node. The collada name might not be
// unique, so we use the collada ID. // unique, so we use the collada ID.
if (!pNode->mID.empty()) if (!pNode->mID.empty())

View File

@ -248,6 +248,7 @@ protected:
bool noSkeletonMesh; bool noSkeletonMesh;
bool ignoreUpDirection; bool ignoreUpDirection;
bool useColladaName;
/** Used by FindNameForNode() to generate unique node names */ /** Used by FindNameForNode() to generate unique node names */
unsigned int mNodeNameCounter; unsigned int mNodeNameCounter;

View File

@ -222,6 +222,7 @@ void ColladaParser::ReadStructure()
} }
PostProcessRootAnimations(); PostProcessRootAnimations();
PostProcessControllers();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -360,6 +361,21 @@ void ColladaParser::ReadAnimationClipLibrary()
} }
} }
void ColladaParser::PostProcessControllers()
{
for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it)
{
std::string meshId = it->second.mMeshId;
ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
while(findItr != mControllerLibrary.end()) {
meshId = findItr->second.mMeshId;
findItr = mControllerLibrary.find(meshId);
}
it->second.mMeshId = meshId;
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Re-build animations from animation clip library, if present, otherwise combine single-channel animations // Re-build animations from animation clip library, if present, otherwise combine single-channel animations
void ColladaParser::PostProcessRootAnimations() void ColladaParser::PostProcessRootAnimations()

View File

@ -87,6 +87,9 @@ namespace Assimp
/** Reads the animation clip library */ /** Reads the animation clip library */
void ReadAnimationClipLibrary(); void ReadAnimationClipLibrary();
/** Unwrap controllers dependency hierarchy */
void PostProcessControllers();
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */ /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
void PostProcessRootAnimations(); void PostProcessRootAnimations();

View File

@ -91,12 +91,14 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
ProcessNode( pScene->mRootNode, aiMatrix4x4()); ProcessNode( pScene->mRootNode, aiMatrix4x4());
// process the meshes accordingly // process the meshes accordingly
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
ProcessMesh( pScene->mMeshes[ a ] ); ProcessMesh( pScene->mMeshes[ a ] );
}
// process the materials accordingly // process the materials accordingly
for( unsigned int a = 0; a < pScene->mNumMaterials; ++a) for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
ProcessMaterial( pScene->mMaterials[ a ] ); ProcessMaterial( pScene->mMaterials[ a ] );
}
// transform all animation channels as well // transform all animation channels as well
for( unsigned int a = 0; a < pScene->mNumAnimations; a++) for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
@ -136,8 +138,11 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts a single mesh to left handed coordinates. // Converts a single mesh to left handed coordinates.
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
{ if ( nullptr == pMesh ) {
DefaultLogger::get()->error( "Nullptr to mesh found." );
return;
}
// mirror positions, normals and stuff along the Z axis // mirror positions, normals and stuff along the Z axis
for( size_t a = 0; a < pMesh->mNumVertices; ++a) for( size_t a = 0; a < pMesh->mNumVertices; ++a)
{ {
@ -173,8 +178,12 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts a single material to left handed coordinates. // Converts a single material to left handed coordinates.
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
{ if ( nullptr == _mat ) {
DefaultLogger::get()->error( "Nullptr to aiMaterial found." );
return;
}
aiMaterial* mat = (aiMaterial*)_mat; aiMaterial* mat = (aiMaterial*)_mat;
for (unsigned int a = 0; a < mat->mNumProperties;++a) { for (unsigned int a = 0; a < mat->mNumProperties;++a) {
aiMaterialProperty* prop = mat->mProperties[a]; aiMaterialProperty* prop = mat->mProperties[a];
@ -183,7 +192,6 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) { if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */ ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
aiVector3D* pff = (aiVector3D*)prop->mData; aiVector3D* pff = (aiVector3D*)prop->mData;
pff->z *= -1.f; pff->z *= -1.f;
} }
} }

View File

@ -49,8 +49,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/StringUtils.h>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
@ -116,6 +117,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
if ( nullptr == m_zipArchive ) { if ( nullptr == m_zipArchive ) {
return false; return false;
} }
ok |= exportContentTypes(); ok |= exportContentTypes();
ok |= export3DModel(); ok |= export3DModel();
ok |= exportRelations(); ok |= exportRelations();
@ -126,7 +128,6 @@ bool D3MFExporter::exportArchive( const char *file ) {
return ok; return ok;
} }
bool D3MFExporter::exportContentTypes() { bool D3MFExporter::exportContentTypes() {
mContentOutput.clear(); mContentOutput.clear();
@ -153,7 +154,11 @@ bool D3MFExporter::exportRelations() {
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"; mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
for ( size_t i = 0; i < mRelations.size(); ++i ) { for ( size_t i = 0; i < mRelations.size(); ++i ) {
if ( mRelations[ i ]->target[ 0 ] == '/' ) {
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
} else {
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" "; mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
}
mRelOutput << "Id=\"" << mRelations[i]->id << "\" "; mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />"; mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
mRelOutput << std::endl; mRelOutput << std::endl;
@ -177,6 +182,10 @@ bool D3MFExporter::export3DModel() {
mModelOutput << "<" << XmlTag::resources << ">"; mModelOutput << "<" << XmlTag::resources << ">";
mModelOutput << std::endl; mModelOutput << std::endl;
writeMetaData();
writeBaseMaterials();
writeObjects(); writeObjects();
@ -203,6 +212,63 @@ void D3MFExporter::writeHeader() {
mModelOutput << std::endl; mModelOutput << std::endl;
} }
void D3MFExporter::writeMetaData() {
if ( nullptr == mScene->mMetaData ) {
return;
}
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
if ( 0 == numMetaEntries ) {
return;
}
const aiString *key;
const aiMetadataEntry *entry(nullptr);
for ( size_t i = 0; i < numMetaEntries; ++i ) {
mScene->mMetaData->Get( i, key, entry );
std::string k( key->C_Str() );
aiString value;
mScene->mMetaData->Get( k, value );
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
mModelOutput << value.C_Str();
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
}
}
void D3MFExporter::writeBaseMaterials() {
mModelOutput << "<basematerials id=\"1\">\n";
std::string strName, hexDiffuseColor , tmp;
for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
aiMaterial *mat = mScene->mMaterials[ i ];
aiString name;
if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
strName = "basemat_" + to_string( i );
} else {
strName = name.C_Str();
}
aiColor4D color;
if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
hexDiffuseColor.clear();
tmp.clear();
hexDiffuseColor = "#";
tmp = DecimalToHexa( color.r );
hexDiffuseColor += tmp;
tmp = DecimalToHexa( color.g );
hexDiffuseColor += tmp;
tmp = DecimalToHexa( color.b );
hexDiffuseColor += tmp;
tmp = DecimalToHexa( color.a );
hexDiffuseColor += tmp;
} else {
hexDiffuseColor = "#FFFFFFFF";
}
mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
}
mModelOutput << "</basematerials>\n";
}
void D3MFExporter::writeObjects() { void D3MFExporter::writeObjects() {
if ( nullptr == mScene->mRootNode ) { if ( nullptr == mScene->mRootNode ) {
return; return;
@ -242,7 +308,9 @@ void D3MFExporter::writeMesh( aiMesh *mesh ) {
} }
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl; mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
writeFaces( mesh ); const unsigned int matIdx( mesh->mMaterialIndex );
writeFaces( mesh, matIdx );
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl; mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
} }
@ -252,7 +320,7 @@ void D3MFExporter::writeVertex( const aiVector3D &pos ) {
mModelOutput << std::endl; mModelOutput << std::endl;
} }
void D3MFExporter::writeFaces( aiMesh *mesh ) { void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
if ( nullptr == mesh ) { if ( nullptr == mesh ) {
return; return;
} }
@ -264,7 +332,8 @@ void D3MFExporter::writeFaces( aiMesh *mesh ) {
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) { for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
aiFace &currentFace = mesh->mFaces[ i ]; aiFace &currentFace = mesh->mFaces[ i ];
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\"" mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] << "\"/>"; << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
<< "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
mModelOutput << std::endl; mModelOutput << std::endl;
} }
mModelOutput << "</" << XmlTag::triangles << ">"; mModelOutput << "</" << XmlTag::triangles << ">";

View File

@ -76,10 +76,12 @@ public:
protected: protected:
void writeHeader(); void writeHeader();
void writeMetaData();
void writeBaseMaterials();
void writeObjects(); void writeObjects();
void writeMesh( aiMesh *mesh ); void writeMesh( aiMesh *mesh );
void writeVertex( const aiVector3D &pos ); void writeVertex( const aiVector3D &pos );
void writeFaces( aiMesh *mesh ); void writeFaces( aiMesh *mesh, unsigned int matIdx );
void writeBuild(); void writeBuild();
void exportContentTyp( const std::string &filename ); void exportContentTyp( const std::string &filename );
void writeModelToArchive( const std::string &folder, const std::string &modelName ); void writeModelToArchive( const std::string &folder, const std::string &modelName );

View File

@ -61,14 +61,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unzip.h> #include <unzip.h>
#include <assimp/irrXMLWrapper.h> #include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include <assimp/fast_atof.h>
#include <iomanip>
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
class XmlSerializer { class XmlSerializer {
public: public:
using MatArray = std::vector<aiMaterial*>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
XmlSerializer(XmlReader* xmlReader) XmlSerializer(XmlReader* xmlReader)
: xmlReader(xmlReader) { : mMeshes()
, mMatArray()
, mActiveMatGroup( 99999999 )
, mMatId2MatArray()
, xmlReader(xmlReader){
// empty // empty
} }
@ -77,14 +87,24 @@ public:
} }
void ImportXml(aiScene* scene) { void ImportXml(aiScene* scene) {
if ( nullptr == scene ) {
return;
}
scene->mRootNode = new aiNode(); scene->mRootNode = new aiNode();
std::vector<aiNode*> children; std::vector<aiNode*> children;
std::string nodeName;
while(ReadToEndElement(D3MF::XmlTag::model)) { while(ReadToEndElement(D3MF::XmlTag::model)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::object) { nodeName = xmlReader->getNodeName();
if( nodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(scene)); children.push_back(ReadObject(scene));
} else if(xmlReader->getNodeName() == D3MF::XmlTag::build) { } else if( nodeName == D3MF::XmlTag::build) {
//
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
ReadBaseMaterials();
} else if ( nodeName == D3MF::XmlTag::meta ) {
ReadMetadata();
} }
} }
@ -92,31 +112,47 @@ public:
scene->mRootNode->mName.Set( "3MF" ); scene->mRootNode->mName.Set( "3MF" );
} }
scene->mNumMeshes = static_cast<unsigned int>(meshes.size()); // import the metadata
if ( !mMetaData.empty() ) {
const size_t numMeta( mMetaData.size() );
scene->mMetaData = aiMetadata::Alloc( numMeta );
for ( size_t i = 0; i < numMeta; ++i ) {
aiString val( mMetaData[ i ].value );
scene->mMetaData->Set( i, mMetaData[ i ].name, val );
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
scene->mMeshes = new aiMesh*[scene->mNumMeshes](); scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
std::copy(meshes.begin(), meshes.end(), scene->mMeshes); // import the materials
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
if ( 0 != scene->mNumMaterials ) {
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
}
// create the scenegraph
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size()); scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren](); scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
} }
private: private:
aiNode* ReadObject(aiScene* scene) aiNode* ReadObject(aiScene* scene) {
{
std::unique_ptr<aiNode> node(new aiNode()); std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds; std::vector<unsigned long> meshIds;
const char *attrib( nullptr ); const char *attrib( nullptr );
std::string name, type; std::string name, type;
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
if ( nullptr != attrib ) { if ( nullptr != attrib ) {
name = attrib; name = attrib;
} }
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
if ( nullptr != attrib ) { if ( nullptr != attrib ) {
type = attrib; type = attrib;
} }
@ -124,19 +160,16 @@ private:
node->mParent = scene->mRootNode; node->mParent = scene->mRootNode;
node->mName.Set(name); node->mName.Set(name);
size_t meshIdx = meshes.size(); size_t meshIdx = mMeshes.size();
while(ReadToEndElement(D3MF::XmlTag::object)) while(ReadToEndElement(D3MF::XmlTag::object)) {
{ if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
{
auto mesh = ReadMesh(); auto mesh = ReadMesh();
mesh->mName.Set(name); mesh->mName.Set(name);
meshes.push_back(mesh); mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx)); meshIds.push_back(static_cast<unsigned long>(meshIdx));
meshIdx++; ++meshIdx;
} }
} }
@ -147,19 +180,14 @@ private:
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
return node.release(); return node.release();
} }
aiMesh *ReadMesh() { aiMesh *ReadMesh() {
aiMesh* mesh = new aiMesh(); aiMesh* mesh = new aiMesh();
while(ReadToEndElement(D3MF::XmlTag::mesh)) while(ReadToEndElement(D3MF::XmlTag::mesh)) {
{ if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
{
ImportVertices(mesh); ImportVertices(mesh);
} } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
{
ImportTriangles(mesh); ImportTriangles(mesh);
} }
} }
@ -167,14 +195,25 @@ private:
return mesh; return mesh;
} }
void ImportVertices(aiMesh* mesh) void ReadMetadata() {
{ const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
std::vector<aiVector3D> vertices; xmlReader->read();
const std::string value = xmlReader->getNodeData();
while(ReadToEndElement(D3MF::XmlTag::vertices)) if ( name.empty() ) {
{ return;
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) }
{
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back( entry );
}
void ImportVertices(aiMesh* mesh) {
std::vector<aiVector3D> vertices;
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex()); vertices.push_back(ReadVertex());
} }
} }
@ -182,11 +221,9 @@ private:
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices); std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
} }
aiVector3D ReadVertex() aiVector3D ReadVertex() {
{
aiVector3D vertex; aiVector3D vertex;
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
@ -196,16 +233,18 @@ private:
return vertex; return vertex;
} }
void ImportTriangles(aiMesh* mesh) void ImportTriangles(aiMesh* mesh) {
{
std::vector<aiFace> faces; std::vector<aiFace> faces;
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
while(ReadToEndElement(D3MF::XmlTag::triangles)) const std::string nodeName( xmlReader->getNodeName() );
{ if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
{
faces.push_back(ReadTriangle()); faces.push_back(ReadTriangle());
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
if ( nullptr != pidToken ) {
int matIdx( std::atoi( pidToken ) );
mesh->mMaterialIndex = matIdx;
}
} }
} }
@ -216,8 +255,7 @@ private:
std::copy(faces.begin(), faces.end(), mesh->mFaces); std::copy(faces.begin(), faces.end(), mesh->mFaces);
} }
aiFace ReadTriangle() aiFace ReadTriangle() {
{
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
@ -229,45 +267,150 @@ private:
return face; return face;
} }
private: void ReadBaseMaterials() {
bool ReadToStartElement(const std::string& startTag) std::vector<unsigned int> MatIdArray;
{ const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
while(xmlReader->read()) if ( nullptr != baseMaterialId ) {
{ unsigned int id = std::atoi( baseMaterialId );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag) const size_t newMatIdx( mMatArray.size() );
{ if ( id != mActiveMatGroup ) {
return true; mActiveMatGroup = id;
} MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && if ( mMatId2MatArray.end() == it ) {
xmlReader->getNodeName() == startTag) MatIdArray.clear();
{ mMatId2MatArray[ id ] = MatIdArray;
return false; } else {
MatIdArray = it->second;
} }
} }
//DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag"); MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
}
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
mMatArray.push_back( readMaterialDef() );
}
}
bool parseColor( const char *color, aiColor4D &diffuse ) {
if ( nullptr == color ) {
return false; return false;
} }
bool ReadToEndElement(const std::string& closeTag) const size_t len( strlen( color ) );
{ if ( 9 != len ) {
while(xmlReader->read()) return false;
{ }
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
const char *buf( color );
if ( '#' != *buf ) {
return false;
}
++buf;
char comp[ 3 ] = { 0,0,'\0' };
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
return true; return true;
} }
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
&& xmlReader->getNodeName() == closeTag) void assignDiffuseColor( aiMaterial *mat ) {
{ const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
aiColor4D diffuse;
if ( parseColor( color, diffuse ) ) {
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
}
}
aiMaterial *readMaterialDef() {
aiMaterial *mat( nullptr );
const char *name( nullptr );
const std::string nodeName( xmlReader->getNodeName() );
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
std::string stdMatName;
aiString matName;
std::string strId( to_string( mActiveMatGroup ) );
stdMatName += "id";
stdMatName += strId;
stdMatName += "_";
if ( nullptr != name ) {
stdMatName += std::string( name );
} else {
stdMatName += "basemat";
}
matName.Set( stdMatName );
mat = new aiMaterial;
mat->AddProperty( &matName, AI_MATKEY_NAME );
assignDiffuseColor( mat );
}
return mat;
}
private:
bool ReadToStartElement(const std::string& startTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
return false;
}
bool ReadToEndElement(const std::string& closeTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false; return false;
} }
} }
DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag"); DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
return false; return false;
} }
private: private:
std::vector<aiMesh*> meshes; struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::vector<aiMesh*> mMeshes;
MatArray mMatArray;
unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray;
XmlReader* xmlReader; XmlReader* xmlReader;
}; };
@ -288,7 +431,6 @@ static const aiImporterDesc desc = {
Extension.c_str() Extension.c_str()
}; };
D3MFImporter::D3MFImporter() D3MFImporter::D3MFImporter()
: BaseImporter() { : BaseImporter() {
// empty // empty
@ -298,14 +440,19 @@ D3MFImporter::~D3MFImporter() {
// empty // empty
} }
bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension = GetExtension(pFile); const std::string extension( GetExtension( filename ) );
if(extension == Extension ) { if(extension == Extension ) {
return true; return true;
} else if ( !extension.length() || checkSig ) { } else if ( !extension.length() || checkSig ) {
if ( nullptr == pIOHandler ) { if ( nullptr == pIOHandler ) {
return true; return false;
} }
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
return false;
}
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
return opcPackage.validate();
} }
return false; return false;
@ -319,8 +466,8 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
return &desc; return &desc;
} }
void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile); D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));

View File

@ -247,13 +247,13 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. // Constructor.
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile) D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
: m_ZipFileHandle(NULL) : m_ZipFileHandle( nullptr )
, m_ArchiveMap() { , m_ArchiveMap() {
if (! rFile.empty()) { if (! rFile.empty()) {
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping); m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
if(m_ZipFileHandle != NULL) { if(m_ZipFileHandle != nullptr ) {
mapArchive(); mapArchive();
} }
} }
@ -267,33 +267,33 @@ D3MFZipArchive::~D3MFZipArchive() {
} }
m_ArchiveMap.clear(); m_ArchiveMap.clear();
if(m_ZipFileHandle != NULL) { if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle); unzClose(m_ZipFileHandle);
m_ZipFileHandle = NULL; m_ZipFileHandle = nullptr;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open. // Returns true, if the archive is already open.
bool D3MFZipArchive::isOpen() const { bool D3MFZipArchive::isOpen() const {
return (m_ZipFileHandle != NULL); return (m_ZipFileHandle != nullptr );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive. // Returns true, if the filename is part of the archive.
bool D3MFZipArchive::Exists(const char* pFile) const { bool D3MFZipArchive::Exists(const char* pFile) const {
ai_assert(pFile != NULL); ai_assert(pFile != nullptr );
bool exist = false; if ( pFile == nullptr ) {
return false;
if (pFile != NULL) { }
std::string rFile(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
std::string filename(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
bool exist( false );
if(it != m_ArchiveMap.end()) { if(it != m_ArchiveMap.end()) {
exist = true; exist = true;
} }
}
return exist; return exist;
} }
@ -434,8 +434,8 @@ public:
std::vector<OpcPackageRelationshipPtr> m_relationShips; std::vector<OpcPackageRelationshipPtr> m_relationShips;
}; };
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr) : mRootStream(nullptr)
, mZipArchive() { , mZipArchive() {
@ -460,7 +460,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) { if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
rootFile = rootFile.substr( 1 ); rootFile = rootFile.substr( 1 );
if ( rootFile[ 0 ] == '/' ) { if ( rootFile[ 0 ] == '/' ) {
// deal with zipbug // deal with zip-bug
rootFile = rootFile.substr( 1 ); rootFile = rootFile.substr( 1 );
} }
} }
@ -470,18 +470,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
mRootStream = mZipArchive->Open(rootFile.c_str()); mRootStream = mZipArchive->Open(rootFile.c_str());
ai_assert( mRootStream != nullptr ); ai_assert( mRootStream != nullptr );
if ( nullptr == mRootStream ) { if ( nullptr == mRootStream ) {
throw DeadlyExportError( "Cannot open rootfile in archive : " + rootFile ); throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
} }
// const size_t size = zipArchive->FileSize();
// m_Data.resize( size );
// const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
// if ( readSize != size )
// {
// m_Data.clear();
// return false;
// }
mZipArchive->Close( fileStream ); mZipArchive->Close( fileStream );
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
@ -498,6 +489,25 @@ IOStream* D3MFOpcPackage::RootStream() const {
return mRootStream; return mRootStream;
} }
static const std::string ModelRef = "3D/3dmodel.model";
bool D3MFOpcPackage::validate() {
if ( nullptr == mRootStream || nullptr == mZipArchive ) {
return false;
}
return mZipArchive->Exists( ModelRef.c_str() );
}
bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) {
D3MF::D3MFZipArchive ar( pIOHandler, rFile );
if ( !ar.isOpen() ) {
return false;
}
return true;
}
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream)); std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get())); std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
@ -508,14 +518,14 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
}); });
if(itr == reader.m_relationShips.end()) if ( itr == reader.m_relationShips.end() ) {
throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE ); throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE );
}
return (*itr)->target; return (*itr)->target;
} }
} // Namespace D3MF } // Namespace D3MF
} // Namespace Assimp } // Namespace Assimp
#endif //ASSIMP_BUILD_NO_3MF_IMPORTER #endif //ASSIMP_BUILD_NO_3MF_IMPORTER

View File

@ -51,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
typedef irr::io::IrrXMLReader XmlReader; using XmlReader = irr::io::IrrXMLReader ;
typedef std::shared_ptr<XmlReader> XmlReaderPtr; using XmlReaderPtr = std::shared_ptr<XmlReader> ;
struct OpcPackageRelationship { struct OpcPackageRelationship {
std::string id; std::string id;
@ -67,6 +67,8 @@ public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate();
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
@ -76,7 +78,7 @@ private:
std::unique_ptr<D3MFZipArchive> mZipArchive; std::unique_ptr<D3MFZipArchive> mZipArchive;
}; };
} } // Namespace D3MF
} } // Namespace Assimp
#endif // D3MFOPCPACKAGE_H #endif // D3MFOPCPACKAGE_H

View File

@ -169,7 +169,6 @@ public:
} }
private: private:
LineSplitter splitter; LineSplitter splitter;
int groupcode; int groupcode;
std::string value; std::string value;

View File

@ -76,7 +76,7 @@ bool DefaultIOSystem::Exists( const char* pFile) const
#ifdef _WIN32 #ifdef _WIN32
wchar_t fileName16[PATHLIMIT]; wchar_t fileName16[PATHLIMIT];
bool isUnicode = IsTextUnicode(pFile, strlen(pFile), NULL); bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL);
if (isUnicode) { if (isUnicode) {
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT); MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
@ -110,7 +110,7 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
FILE* file; FILE* file;
#ifdef _WIN32 #ifdef _WIN32
wchar_t fileName16[PATHLIMIT]; wchar_t fileName16[PATHLIMIT];
bool isUnicode = IsTextUnicode(strFile, strlen(strFile), NULL ); bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL );
if (isUnicode) { if (isUnicode) {
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT); MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
std::string mode8(strMode); std::string mode8(strMode);
@ -158,7 +158,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
{ {
ai_assert(in && _out); ai_assert(in && _out);
#if defined( _MSC_VER ) || defined( __MINGW32__ ) #if defined( _MSC_VER ) || defined( __MINGW32__ )
bool isUnicode = IsTextUnicode(in, strlen(in), NULL); bool isUnicode = IsTextUnicode(in, static_cast<int>(strlen(in)), NULL);
if (isUnicode) { if (isUnicode) {
wchar_t out16[PATHLIMIT]; wchar_t out16[PATHLIMIT];
wchar_t in16[PATHLIMIT]; wchar_t in16[PATHLIMIT];

View File

@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of DefaultLogger (and Logger) * @brief Implementation of DefaultLogger (and Logger)
*/ */
// Default log streams // Default log streams
#include "Win32DebugLogStream.h" #include "Win32DebugLogStream.h"
#include "StdOStreamLogStream.h" #include "StdOStreamLogStream.h"
@ -62,7 +61,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_SINGLETHREADED #ifndef ASSIMP_BUILD_SINGLETHREADED
# include <thread> # include <thread>
# include <mutex> # include <mutex>
std::mutex loggerMutex; std::mutex loggerMutex;
#endif #endif
@ -76,22 +74,19 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Represents a log-stream + its error severity // Represents a log-stream + its error severity
struct LogStreamInfo struct LogStreamInfo {
{
unsigned int m_uiErrorSeverity; unsigned int m_uiErrorSeverity;
LogStream *m_pStream; LogStream *m_pStream;
// Constructor // Constructor
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) : LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
m_uiErrorSeverity( uiErrorSev ), m_uiErrorSeverity( uiErrorSev ),
m_pStream( pStream ) m_pStream( pStream ) {
{
// empty // empty
} }
// Destructor // Destructor
~LogStreamInfo() ~LogStreamInfo() {
{
delete m_pStream; delete m_pStream;
} }
}; };
@ -109,7 +104,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
#ifdef WIN32 #ifdef WIN32
return new Win32DebugLogStream(); return new Win32DebugLogStream();
#else #else
return NULL; return nullptr;
#endif #endif
// Platform-independent default streams // Platform-independent default streams
@ -118,7 +113,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
case aiDefaultLogStream_STDOUT: case aiDefaultLogStream_STDOUT:
return new StdOStreamLogStream(std::cout); return new StdOStreamLogStream(std::cout);
case aiDefaultLogStream_FILE: case aiDefaultLogStream_FILE:
return (name && *name ? new FileLogStream(name,io) : NULL); return (name && *name ? new FileLogStream(name,io) : nullptr );
default: default:
// We don't know this default log stream, so raise an assertion // We don't know this default log stream, so raise an assertion
ai_assert(false); ai_assert(false);
@ -134,34 +129,38 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/, Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
LogSeverity severity /*= NORMAL*/, LogSeverity severity /*= NORMAL*/,
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/, unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
IOSystem* io /*= NULL*/) IOSystem* io /*= NULL*/) {
{
// enter the mutex here to avoid concurrency problems // enter the mutex here to avoid concurrency problems
#ifndef ASSIMP_BUILD_SINGLETHREADED #ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(loggerMutex); std::lock_guard<std::mutex> lock(loggerMutex);
#endif #endif
if (m_pLogger && !isNullLogger() ) if ( m_pLogger && !isNullLogger() ) {
delete m_pLogger; delete m_pLogger;
}
m_pLogger = new DefaultLogger( severity ); m_pLogger = new DefaultLogger( severity );
// Attach default log streams // Attach default log streams
// Stream the log to the MSVC debugger? // Stream the log to the MSVC debugger?
if (defStreams & aiDefaultLogStream_DEBUGGER) if ( defStreams & aiDefaultLogStream_DEBUGGER ) {
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) ); m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) );
}
// Stream the log to COUT? // Stream the log to COUT?
if (defStreams & aiDefaultLogStream_STDOUT) if ( defStreams & aiDefaultLogStream_STDOUT ) {
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) ); m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) );
}
// Stream the log to CERR? // Stream the log to CERR?
if (defStreams & aiDefaultLogStream_STDERR) if ( defStreams & aiDefaultLogStream_STDERR ) {
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) ); m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) );
}
// Stream the log to a file // Stream the log to a file
if (defStreams & aiDefaultLogStream_FILE && name && *name) if ( defStreams & aiDefaultLogStream_FILE && name && *name ) {
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) ); m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) );
}
return m_pLogger; return m_pLogger;
} }
@ -200,7 +199,6 @@ void Logger::warn(const char* message) {
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
void Logger::error(const char* message) { void Logger::error(const char* message) {
// SECURITY FIX: see above // SECURITY FIX: see above
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
return; return;
@ -209,23 +207,24 @@ void Logger::error(const char* message) {
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
void DefaultLogger::set( Logger *logger ) void DefaultLogger::set( Logger *logger ) {
{
// enter the mutex here to avoid concurrency problems // enter the mutex here to avoid concurrency problems
#ifndef ASSIMP_BUILD_SINGLETHREADED #ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(loggerMutex); std::lock_guard<std::mutex> lock(loggerMutex);
#endif #endif
if (!logger)logger = &s_pNullLogger; if ( nullptr == logger ) {
if (m_pLogger && !isNullLogger() ) logger = &s_pNullLogger;
}
if ( nullptr != m_pLogger && !isNullLogger() ) {
delete m_pLogger; delete m_pLogger;
}
DefaultLogger::m_pLogger = logger; DefaultLogger::m_pLogger = logger;
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
bool DefaultLogger::isNullLogger() bool DefaultLogger::isNullLogger() {
{
return m_pLogger == &s_pNullLogger; return m_pLogger == &s_pNullLogger;
} }
@ -236,8 +235,7 @@ Logger *DefaultLogger::get() {
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Kills the only instance // Kills the only instance
void DefaultLogger::kill() void DefaultLogger::kill() {
{
// enter the mutex here to avoid concurrency problems // enter the mutex here to avoid concurrency problems
#ifndef ASSIMP_BUILD_SINGLETHREADED #ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(loggerMutex); std::lock_guard<std::mutex> lock(loggerMutex);
@ -252,10 +250,10 @@ void DefaultLogger::kill()
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Debug message // Debug message
void DefaultLogger::OnDebug( const char* message ) void DefaultLogger::OnDebug( const char* message ) {
{ if ( m_Severity == Logger::NORMAL ) {
if ( m_Severity == Logger::NORMAL )
return; return;
}
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
char msg[Size]; char msg[Size];
@ -266,8 +264,7 @@ void DefaultLogger::OnDebug( const char* message )
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Logs an info // Logs an info
void DefaultLogger::OnInfo( const char* message ) void DefaultLogger::OnInfo( const char* message ){
{
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
char msg[Size]; char msg[Size];
ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message ); ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message );
@ -277,8 +274,7 @@ void DefaultLogger::OnInfo( const char* message )
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Logs a warning // Logs a warning
void DefaultLogger::OnWarn( const char* message ) void DefaultLogger::OnWarn( const char* message ) {
{
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
char msg[Size]; char msg[Size];
ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message ); ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message );
@ -288,8 +284,7 @@ void DefaultLogger::OnWarn( const char* message )
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Logs an error // Logs an error
void DefaultLogger::OnError( const char* message ) void DefaultLogger::OnError( const char* message ) {
{
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
char msg[ Size ]; char msg[ Size ];
ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message ); ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
@ -299,10 +294,10 @@ void DefaultLogger::OnError( const char* message )
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Will attach a new stream // Will attach a new stream
bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) {
{ if ( nullptr == pStream ) {
if (!pStream)
return false; return false;
}
if (0 == severity) { if (0 == severity) {
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
@ -312,8 +307,7 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
it != m_StreamArray.end(); it != m_StreamArray.end();
++it ) ++it )
{ {
if ( (*it)->m_pStream == pStream ) if ( (*it)->m_pStream == pStream ) {
{
(*it)->m_uiErrorSeverity |= severity; (*it)->m_uiErrorSeverity |= severity;
return true; return true;
} }
@ -326,34 +320,31 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Detach a stream // Detach a stream
bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) {
{ if ( nullptr == pStream ) {
if (!pStream)
return false; return false;
}
if (0 == severity) { if (0 == severity) {
severity = SeverityAll; severity = SeverityAll;
} }
for ( StreamIt it = m_StreamArray.begin(); bool res( false );
it != m_StreamArray.end(); for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
++it ) if ( (*it)->m_pStream == pStream ) {
{
if ( (*it)->m_pStream == pStream )
{
(*it)->m_uiErrorSeverity &= ~severity; (*it)->m_uiErrorSeverity &= ~severity;
if ( (*it)->m_uiErrorSeverity == 0 ) if ( (*it)->m_uiErrorSeverity == 0 ) {
{
// don't delete the underlying stream 'cause the caller gains ownership again // don't delete the underlying stream 'cause the caller gains ownership again
(**it).m_pStream = NULL; (**it).m_pStream = nullptr;
delete *it; delete *it;
m_StreamArray.erase( it ); m_StreamArray.erase( it );
res = true;
break; break;
} }
return true; return true;
} }
} }
return false; return res;
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@ -361,15 +352,13 @@ bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
DefaultLogger::DefaultLogger(LogSeverity severity) DefaultLogger::DefaultLogger(LogSeverity severity)
: Logger ( severity ) : Logger ( severity )
, noRepeatMsg (false) , noRepeatMsg (false)
, lastLen( 0 ) , lastLen( 0 ) {
{
lastMsg[0] = '\0'; lastMsg[0] = '\0';
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Destructor // Destructor
DefaultLogger::~DefaultLogger() DefaultLogger::~DefaultLogger() {
{
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) { for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
// also frees the underlying stream, we are its owner. // also frees the underlying stream, we are its owner.
delete *it; delete *it;
@ -378,9 +367,8 @@ DefaultLogger::~DefaultLogger()
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Writes message to stream // Writes message to stream
void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) {
{ ai_assert(nullptr != message);
ai_assert(NULL != message);
// Check whether this is a repeated message // Check whether this is a repeated message
if (! ::strncmp( message,lastMsg, lastLen-1)) if (! ::strncmp( message,lastMsg, lastLen-1))

View File

@ -99,22 +99,22 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
} }
bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
uint32_t imageSize = 0; std::streampos imageSize = 0;
std::string imagePath = path; std::string imagePath = path;
// Test path directly // Test path directly
std::ifstream file(imagePath, std::ios::binary | std::ios::ate); std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
if ((imageSize = file.tellg()) == -1u) { if ((imageSize = file.tellg()) == std::streampos(-1)) {
DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder."); DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
// Test path in root path // Test path in root path
imagePath = mRootPath + path; imagePath = mRootPath + path;
file.open(imagePath, std::ios::binary | std::ios::ate); file.open(imagePath, std::ios::binary | std::ios::ate);
if ((imageSize = file.tellg()) == -1u) { if ((imageSize = file.tellg()) == std::streampos(-1)) {
// Test path basename in root path // Test path basename in root path
imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
file.open(imagePath, std::ios::binary | std::ios::ate); file.open(imagePath, std::ios::binary | std::ios::ate);
if ((imageSize = file.tellg()) == -1u) { if ((imageSize = file.tellg()) == std::streampos(-1)) {
DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + "."); DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
return false; return false;
} }
@ -134,7 +134,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
// Add the new texture // Add the new texture
auto pTexture = new aiTexture(); auto pTexture = new aiTexture();
pTexture->mHeight = 0; // Means that this is still compressed pTexture->mHeight = 0; // Means that this is still compressed
pTexture->mWidth = imageSize; pTexture->mWidth = static_cast<uint32_t>(imageSize);
pTexture->pcData = imageContent; pTexture->pcData = imageContent;
auto extension = path.substr(path.find_last_of('.') + 1u); auto extension = path.substr(path.find_last_of('.') + 1u);

View File

@ -97,6 +97,8 @@ void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportPropert
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -169,6 +171,11 @@ Exporter::ExportFormatEntry gExporters[] =
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ), Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
#endif #endif
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
#endif
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ) Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
#endif #endif
@ -301,7 +308,8 @@ bool IsVerboseFormat(const aiScene* pScene) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) { aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
unsigned int pPreprocessing, const ExportProperties* pProperties) {
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// when they create scenes from scratch, users will likely create them not in verbose // when they create scenes from scratch, users will likely create them not in verbose

86
code/FBXCommon.h 100644
View File

@ -0,0 +1,86 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file FBXCommon.h
* Some useful constants and enums for dealing with FBX files.
*/
#ifndef AI_FBXCOMMON_H_INC
#define AI_FBXCOMMON_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
namespace FBX
{
const std::string NULL_RECORD = { // 13 null bytes
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
}; // who knows why
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit
// rotation order. We'll probably use EulerXYZ for everything
enum RotOrder {
RotOrder_EulerXYZ = 0,
RotOrder_EulerXZY,
RotOrder_EulerYZX,
RotOrder_EulerYXZ,
RotOrder_EulerZXY,
RotOrder_EulerZYX,
RotOrder_SphericXYZ,
RotOrder_MAX // end-of-enum sentinel
};
// transformation inheritance method. Most of the time RSrs
enum TransformInheritance {
TransformInheritance_RrSs = 0,
TransformInheritance_RSrs,
TransformInheritance_Rrs,
TransformInheritance_MAX // end-of-enum sentinel
};
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXCOMMON_H_INC

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,15 +135,14 @@ void Converter::ConvertRootNode() {
ConvertNodes( 0L, *out->mRootNode ); ConvertNodes( 0L, *out->mRootNode );
} }
void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) {
void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform )
{
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" ); const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" );
std::vector<aiNode*> nodes; std::vector<aiNode*> nodes;
nodes.reserve( conns.size() ); nodes.reserve( conns.size() );
std::vector<aiNode*> nodes_chain; std::vector<aiNode*> nodes_chain;
std::vector<aiNode*> post_nodes_chain;
try { try {
for( const Connection* con : conns ) { for( const Connection* con : conns ) {
@ -152,15 +153,16 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
} }
const Object* const object = con->SourceObject(); const Object* const object = con->SourceObject();
if ( !object ) { if ( nullptr == object ) {
FBXImporter::LogWarn( "failed to convert source object for Model link" ); FBXImporter::LogWarn( "failed to convert source object for Model link" );
continue; continue;
} }
const Model* const model = dynamic_cast<const Model*>( object ); const Model* const model = dynamic_cast<const Model*>( object );
if ( model ) { if ( nullptr != model ) {
nodes_chain.clear(); nodes_chain.clear();
post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent_transform; aiMatrix4x4 new_abs_transform = parent_transform;
@ -168,11 +170,11 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
// assimp (or rather: the complicated transformation chain that // assimp (or rather: the complicated transformation chain that
// is employed by fbx) means that we may need multiple aiNode's // is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation. // to represent a fbx node's transformation.
GenerateTransformationNodeChain( *model, nodes_chain ); GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
ai_assert( nodes_chain.size() ); ai_assert( nodes_chain.size() );
const std::string& original_name = FixNodeName( model->Name() ); std::string original_name = FixNodeName( model->Name() );
// check if any of the nodes in the chain has the name the fbx node // check if any of the nodes in the chain has the name the fbx node
// is supposed to have. If there is none, add another node to // is supposed to have. If there is none, add another node to
@ -187,7 +189,15 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
} }
if ( !name_carrier ) { if ( !name_carrier ) {
NodeNameCache::const_iterator it( std::find( mNodeNames.begin(), mNodeNames.end(), original_name ) );
if ( it != mNodeNames.end() ) {
original_name = original_name + std::string( "001" );
}
mNodeNames.push_back( original_name );
nodes_chain.push_back( new aiNode( original_name ) ); nodes_chain.push_back( new aiNode( original_name ) );
} else {
original_name = nodes_chain.back()->mName.C_Str();
} }
//setup metadata on newest node //setup metadata on newest node
@ -213,15 +223,46 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
// attach geometry // attach geometry
ConvertModel( *model, *nodes_chain.back(), new_abs_transform ); ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
// attach sub-nodes // check if there will be any child nodes
ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform ); const std::vector<const Connection*>& child_conns
= doc.GetConnectionsByDestinationSequenced( model->ID(), "Model" );
// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for( aiNode* postnode : post_nodes_chain ) {
ai_assert( postnode );
if ( last_parent != &parent ) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode*[ 1 ];
last_parent->mChildren[ 0 ] = postnode;
}
postnode->mParent = last_parent;
last_parent = postnode;
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
Util::delete_fun<aiNode> deleter;
std::for_each(
post_nodes_chain.begin(),
post_nodes_chain.end(),
deleter
);
}
// attach sub-nodes (if any)
ConvertNodes( model->ID(), *last_parent, new_abs_transform );
if ( doc.Settings().readLights ) { if ( doc.Settings().readLights ) {
ConvertLights( *model ); ConvertLights( *model, original_name );
} }
if ( doc.Settings().readCameras ) { if ( doc.Settings().readCameras ) {
ConvertCameras( *model ); ConvertCameras( *model, original_name );
} }
nodes.push_back( nodes_chain.front() ); nodes.push_back( nodes_chain.front() );
@ -240,38 +281,36 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
Util::delete_fun<aiNode> deleter; Util::delete_fun<aiNode> deleter;
std::for_each( nodes.begin(), nodes.end(), deleter ); std::for_each( nodes.begin(), nodes.end(), deleter );
std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter ); std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter );
std::for_each( post_nodes_chain.begin(), post_nodes_chain.end(), deleter );
} }
} }
void Converter::ConvertLights( const Model& model ) void Converter::ConvertLights( const Model& model, const std::string &orig_name ) {
{
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes(); const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
for( const NodeAttribute* attr : node_attrs ) { for( const NodeAttribute* attr : node_attrs ) {
const Light* const light = dynamic_cast<const Light*>( attr ); const Light* const light = dynamic_cast<const Light*>( attr );
if ( light ) { if ( light ) {
ConvertLight( model, *light ); ConvertLight( *light, orig_name );
} }
} }
} }
void Converter::ConvertCameras( const Model& model ) void Converter::ConvertCameras( const Model& model, const std::string &orig_name ) {
{
const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes(); const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
for( const NodeAttribute* attr : node_attrs ) { for( const NodeAttribute* attr : node_attrs ) {
const Camera* const cam = dynamic_cast<const Camera*>( attr ); const Camera* const cam = dynamic_cast<const Camera*>( attr );
if ( cam ) { if ( cam ) {
ConvertCamera( model, *cam ); ConvertCamera( *cam, orig_name );
} }
} }
} }
void Converter::ConvertLight( const Model& model, const Light& light ) void Converter::ConvertLight( const Light& light, const std::string &orig_name ) {
{
lights.push_back( new aiLight() ); lights.push_back( new aiLight() );
aiLight* const out_light = lights.back(); aiLight* const out_light = lights.back();
out_light->mName.Set( FixNodeName( model.Name() ) ); out_light->mName.Set( orig_name );
const float intensity = light.Intensity() / 100.0f; const float intensity = light.Intensity() / 100.0f;
const aiVector3D& col = light.Color(); const aiVector3D& col = light.Color();
@ -344,12 +383,12 @@ void Converter::ConvertLight( const Model& model, const Light& light )
} }
} }
void Converter::ConvertCamera( const Model& model, const Camera& cam ) void Converter::ConvertCamera( const Camera& cam, const std::string &orig_name )
{ {
cameras.push_back( new aiCamera() ); cameras.push_back( new aiCamera() );
aiCamera* const out_camera = cameras.back(); aiCamera* const out_camera = cameras.back();
out_camera->mName.Set( FixNodeName( model.Name() ) ); out_camera->mName.Set( orig_name );
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
@ -363,6 +402,31 @@ void Converter::ConvertCamera( const Model& model, const Camera& cam )
out_camera->mClipPlaneFar = cam.FarPlane(); out_camera->mClipPlaneFar = cam.FarPlane();
} }
static bool HasName( NodeNameCache &cache, const std::string &name ) {
NodeNameCache::const_iterator it( std::find( cache.begin(), cache.end(), name ) );
return it != cache.end();
}
void Converter::GetUniqueName( const std::string &name, std::string uniqueName ) {
if ( !HasName( mNodeNames, name ) ) {
uniqueName = name;
return;
}
int i( 0 );
std::string newName;
while ( HasName( mNodeNames, newName ) ) {
++i;
newName.clear();
newName += name;
std::stringstream ext;
ext << std::setfill( '0' ) << std::setw( 3 ) << i;
newName += ext.str();
}
uniqueName = newName;
mNodeNames.push_back( uniqueName );
}
const char* Converter::NameTransformationComp( TransformationComp comp ) const char* Converter::NameTransformationComp( TransformationComp comp )
{ {
@ -396,6 +460,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
return "GeometricRotation"; return "GeometricRotation";
case TransformationComp_GeometricTranslation: case TransformationComp_GeometricTranslation:
return "GeometricTranslation"; return "GeometricTranslation";
case TransformationComp_GeometricScalingInverse:
return "GeometricScalingInverse";
case TransformationComp_GeometricRotationInverse:
return "GeometricRotationInverse";
case TransformationComp_GeometricTranslationInverse:
return "GeometricTranslationInverse";
case TransformationComp_MAXIMUM: // this is to silence compiler warnings case TransformationComp_MAXIMUM: // this is to silence compiler warnings
default: default:
break; break;
@ -437,6 +507,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
return "GeometricRotation"; return "GeometricRotation";
case TransformationComp_GeometricTranslation: case TransformationComp_GeometricTranslation:
return "GeometricTranslation"; return "GeometricTranslation";
case TransformationComp_GeometricScalingInverse:
return "GeometricScalingInverse";
case TransformationComp_GeometricRotationInverse:
return "GeometricRotationInverse";
case TransformationComp_GeometricTranslationInverse:
return "GeometricTranslationInverse";
case TransformationComp_MAXIMUM: // this is to silence compiler warnings case TransformationComp_MAXIMUM: // this is to silence compiler warnings
break; break;
} }
@ -548,18 +624,26 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
bool ok; bool ok;
const float zero_epsilon = 1e-6f; const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) { for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
const TransformationComp comp = static_cast< TransformationComp >( i ); const TransformationComp comp = static_cast< TransformationComp >( i );
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation || if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
continue; continue;
} }
bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok ); const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
if ( ok && v.SquareLength() > zero_epsilon ) { if ( ok && scale_compare ) {
if ( (v - all_ones).SquareLength() > zero_epsilon ) {
return true; return true;
} }
} else if ( ok ) {
if ( v.SquareLength() > zero_epsilon ) {
return true;
}
}
} }
return false; return false;
@ -570,7 +654,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp ); return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
} }
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes ) void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
{ {
const PropertyTable& props = model.Props(); const PropertyTable& props = model.Props();
const Model::RotOrder rot = model.RotationOrder(); const Model::RotOrder rot = model.RotationOrder();
@ -582,20 +666,21 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// generate transformation matrices for all the different transformation components // generate transformation matrices for all the different transformation components
const float zero_epsilon = 1e-6f; const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
bool is_complex = false; bool is_complex = false;
const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok ); const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
if ( ok && PreRotation.SquareLength() > zero_epsilon ) { if ( ok && PreRotation.SquareLength() > zero_epsilon ) {
is_complex = true; is_complex = true;
GetRotationMatrix( rot, PreRotation, chain[ TransformationComp_PreRotation ] ); GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[ TransformationComp_PreRotation ] );
} }
const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok ); const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok );
if ( ok && PostRotation.SquareLength() > zero_epsilon ) { if ( ok && PostRotation.SquareLength() > zero_epsilon ) {
is_complex = true; is_complex = true;
GetRotationMatrix( rot, PostRotation, chain[ TransformationComp_PostRotation ] ); GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[ TransformationComp_PostRotation ] );
} }
const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok ); const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok );
@ -634,7 +719,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok ); const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) { if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] ); aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
} }
@ -644,18 +729,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok ); const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) { if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] ); aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
aiVector3D GeometricScalingInverse = GeometricScaling;
bool canscale = true;
for (unsigned int i = 0; i < 3; ++i) {
if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
} else {
FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
canscale = false;
break;
}
}
if (canscale) {
aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
}
} }
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok ); const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) { if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
is_complex = true;
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] ); GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
chain[ TransformationComp_GeometricRotationInverse ].Inverse();
} }
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok ); const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) { if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] ); aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
} }
// is_complex needs to be consistent with NeedsComplexTransformationChain() // is_complex needs to be consistent with NeedsComplexTransformationChain()
@ -663,7 +768,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// not be guaranteed. // not be guaranteed.
ai_assert( NeedsComplexTransformationChain( model ) == is_complex ); ai_assert( NeedsComplexTransformationChain( model ) == is_complex );
const std::string& name = FixNodeName( model.Name() ); std::string name = FixNodeName( model.Name() );
// now, if we have more than just Translation, Scaling and Rotation, // now, if we have more than just Translation, Scaling and Rotation,
// we need to generate a full node chain to accommodate for assimp's // we need to generate a full node chain to accommodate for assimp's
@ -690,10 +795,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
aiNode* nd = new aiNode(); aiNode* nd = new aiNode();
output_nodes.push_back( nd );
nd->mName.Set( NameTransformationChainNode( name, comp ) ); nd->mName.Set( NameTransformationChainNode( name, comp ) );
nd->mTransformation = chain[ i ]; nd->mTransformation = chain[ i ];
// geometric inverses go in a post-node chain
if ( comp == TransformationComp_GeometricScalingInverse ||
comp == TransformationComp_GeometricRotationInverse ||
comp == TransformationComp_GeometricTranslationInverse
) {
post_output_nodes.push_back( nd );
} else {
output_nodes.push_back( nd );
}
} }
ai_assert( output_nodes.size() ); ai_assert( output_nodes.size() );
@ -703,8 +816,10 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// else, we can just multiply the matrices together // else, we can just multiply the matrices together
aiNode* nd = new aiNode(); aiNode* nd = new aiNode();
output_nodes.push_back( nd ); output_nodes.push_back( nd );
std::string uniqueName;
GetUniqueName( name, uniqueName );
nd->mName.Set( name ); nd->mName.Set( uniqueName );
for (const auto &transform : chain) { for (const auto &transform : chain) {
nd->mTransformation = nd->mTransformation * transform; nd->mTransformation = nd->mTransformation * transform;
@ -1560,8 +1675,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
const std::string& propName, const std::string& propName,
aiTextureType target, const MeshGeometry* const mesh ) aiTextureType target, const MeshGeometry* const mesh ) {
{
LayeredTextureMap::const_iterator it = layeredTextures.find( propName ); LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
if ( it == layeredTextures.end() ) { if ( it == layeredTextures.end() ) {
return; return;
@ -1805,11 +1919,11 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
// TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok ); const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
float CalculatedOpacity = 1.0; float CalculatedOpacity = 1.0f;
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT ); out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
// as calculated by FBX SDK 2017: // as calculated by FBX SDK 2017:
CalculatedOpacity = 1.0 - ((Transparent.r + Transparent.g + Transparent.b) / 3.0); CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
} }
// use of TransparencyFactor is inconsistent. // use of TransparencyFactor is inconsistent.
@ -1923,81 +2037,17 @@ void Converter::ConvertAnimations()
} }
} }
void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name ) { std::string Converter::FixNodeName( const std::string& name ) {
if ( node_names.find( fixed_name ) == node_names.end() ) {
FBXImporter::LogError( "Cannot rename node " + fixed_name + ", not existing.");
return;
}
if ( node_names.find( new_name ) != node_names.end() ) {
FBXImporter::LogError( "Cannot rename node " + fixed_name + " to " + new_name +", name already existing." );
return;
}
ai_assert( node_names.find( fixed_name ) != node_names.end() );
ai_assert( node_names.find( new_name ) == node_names.end() );
renamed_nodes[ fixed_name ] = new_name;
const aiString fn( fixed_name );
for( aiCamera* cam : cameras ) {
if ( cam->mName == fn ) {
cam->mName.Set( new_name );
break;
}
}
for( aiLight* light : lights ) {
if ( light->mName == fn ) {
light->mName.Set( new_name );
break;
}
}
for( aiAnimation* anim : animations ) {
for ( unsigned int i = 0; i < anim->mNumChannels; ++i ) {
aiNodeAnim* const na = anim->mChannels[ i ];
if ( na->mNodeName == fn ) {
na->mNodeName.Set( new_name );
break;
}
}
}
}
std::string Converter::FixNodeName( const std::string& name )
{
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
// this causes ambiguities, well possible between empty identifiers, // this causes ambiguities, well possible between empty identifiers,
// such as "Model::" and ""). Make sure the behaviour is consistent // such as "Model::" and ""). Make sure the behaviour is consistent
// across multiple calls to FixNodeName(). // across multiple calls to FixNodeName().
if ( name.substr( 0, 7 ) == "Model::" ) { if ( name.substr( 0, 7 ) == "Model::" ) {
std::string temp = name.substr( 7 ); std::string temp = name.substr( 7 );
return temp;
const NodeNameMap::const_iterator it = node_names.find( temp );
if ( it != node_names.end() ) {
if ( !( *it ).second ) {
return FixNodeName( name + "_" );
}
}
node_names[ temp ] = true;
const NameNameMap::const_iterator rit = renamed_nodes.find( temp );
return rit == renamed_nodes.end() ? temp : ( *rit ).second;
} }
const NodeNameMap::const_iterator it = node_names.find( name ); return name;
if ( it != node_names.end() ) {
if ( ( *it ).second ) {
return FixNodeName( name + "_" );
}
}
node_names[ name ] = false;
const NameNameMap::const_iterator rit = renamed_nodes.find( name );
return rit == renamed_nodes.end() ? name : ( *rit ).second;
} }
void Converter::ConvertAnimationStack( const AnimationStack& st ) void Converter::ConvertAnimationStack( const AnimationStack& st )
@ -2209,8 +2259,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
has_any = true; has_any = true;
if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation && if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation )
comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
{ {
has_complex = true; has_complex = true;
} }

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
@ -82,7 +84,10 @@ public:
* The different parts that make up the final local transformation of a fbx-node * The different parts that make up the final local transformation of a fbx-node
*/ */
enum TransformationComp { enum TransformationComp {
TransformationComp_Translation = 0, TransformationComp_GeometricScalingInverse = 0,
TransformationComp_GeometricRotationInverse,
TransformationComp_GeometricTranslationInverse,
TransformationComp_Translation,
TransformationComp_RotationOffset, TransformationComp_RotationOffset,
TransformationComp_RotationPivot, TransformationComp_RotationPivot,
TransformationComp_PreRotation, TransformationComp_PreRotation,
@ -114,16 +119,19 @@ private:
void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4()); void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4());
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertLights(const Model& model); void ConvertLights(const Model& model, const std::string &orig_name );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCameras(const Model& model); void ConvertCameras(const Model& model, const std::string &orig_name );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertLight(const Model& model, const Light& light); void ConvertLight( const Light& light, const std::string &orig_name );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCamera(const Model& model, const Camera& cam); void ConvertCamera( const Camera& cam, const std::string &orig_name );
// ------------------------------------------------------------------------------------------------
void GetUniqueName( const std::string &name, std::string uniqueName );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// this returns unified names usable within assimp identifiers (i.e. no space characters - // this returns unified names usable within assimp identifiers (i.e. no space characters -
@ -153,7 +161,7 @@ private:
/** /**
* note: memory for output_nodes will be managed by the caller * note: memory for output_nodes will be managed by the caller
*/ */
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes); void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SetupNodeMetadata(const Model& model, aiNode& nd); void SetupNodeMetadata(const Model& model, aiNode& nd);
@ -255,18 +263,6 @@ private:
// convert animation data to aiAnimation et al // convert animation data to aiAnimation et al
void ConvertAnimations(); void ConvertAnimations();
// ------------------------------------------------------------------------------------------------
// rename a node already partially converted. fixed_name is a string previously returned by
// FixNodeName, new_name specifies the string FixNodeName should return on all further invocations
// which would previously have returned the old value.
//
// this also updates names in node animations, cameras and light sources and is thus slow.
//
// NOTE: the caller is responsible for ensuring that the new name is unique and does
// not collide with any other identifiers. The best way to ensure this is to only
// append to the old name, which is guaranteed to match these requirements.
void RenameNode(const std::string& fixed_name, const std::string& new_name);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// takes a fbx node name and returns the identifier to be used in the assimp output scene. // takes a fbx node name and returns the identifier to be used in the assimp output scene.
// the function is guaranteed to provide consistent results over multiple invocations // the function is guaranteed to provide consistent results over multiple invocations
@ -278,7 +274,6 @@ private:
// XXX: better use multi_map .. // XXX: better use multi_map ..
typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap; typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAnimationStack(const AnimationStack& st); void ConvertAnimationStack(const AnimationStack& st);
@ -429,13 +424,7 @@ private:
typedef std::map<std::string, unsigned int> NodeAnimBitMap; typedef std::map<std::string, unsigned int> NodeAnimBitMap;
NodeAnimBitMap node_anim_chain_bits; NodeAnimBitMap node_anim_chain_bits;
// name -> has had its prefix_stripped? NodeNameCache mNodeNames;
typedef std::map<std::string, bool> NodeNameMap;
NodeNameMap node_names;
typedef std::map<std::string, std::string> NameNameMap;
NameNameMap renamed_nodes;
double anim_fps; double anim_fps;
aiScene* const out; aiScene* const out;

View File

@ -353,6 +353,8 @@ void Document::ReadGlobalSettings()
std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true ); std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
//double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 );
if(!props) { if(!props) {
DOMError("GlobalSettings dictionary contains no property table"); DOMError("GlobalSettings dictionary contains no property table");
} }

View File

@ -1022,8 +1022,8 @@ public:
fbx_simple_property(CoordAxisSign, int, 1) fbx_simple_property(CoordAxisSign, int, 1)
fbx_simple_property(OriginalUpAxis, int, 0) fbx_simple_property(OriginalUpAxis, int, 0)
fbx_simple_property(OriginalUpAxisSign, int, 1) fbx_simple_property(OriginalUpAxisSign, int, 1)
fbx_simple_property(UnitScaleFactor, double, 1) fbx_simple_property(UnitScaleFactor, float, 1)
fbx_simple_property(OriginalUnitScaleFactor, double, 1) fbx_simple_property(OriginalUnitScaleFactor, float, 1)
fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0)) fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(DefaultCamera, std::string, "") fbx_simple_property(DefaultCamera, std::string, "")

View File

@ -0,0 +1,568 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportNode.h"
#include "FBXCommon.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <assimp/ai_assert.h>
#include <assimp/StringUtils.h> // ai_snprintf
#include <string>
#include <ostream>
#include <sstream> // ostringstream
#include <memory> // shared_ptr
// AddP70<type> helpers... there's no usable pattern here,
// so all are defined as separate functions.
// Even "animatable" properties are often completely different
// from the standard (nonanimated) property definition,
// so they are specified with an 'A' suffix.
void FBX::Node::AddP70int(
const std::string& name, int32_t value
) {
FBX::Node n("P");
n.AddProperties(name, "int", "Integer", "", value);
AddChild(n);
}
void FBX::Node::AddP70bool(
const std::string& name, bool value
) {
FBX::Node n("P");
n.AddProperties(name, "bool", "", "", int32_t(value));
AddChild(n);
}
void FBX::Node::AddP70double(
const std::string& name, double value
) {
FBX::Node n("P");
n.AddProperties(name, "double", "Number", "", value);
AddChild(n);
}
void FBX::Node::AddP70numberA(
const std::string& name, double value
) {
FBX::Node n("P");
n.AddProperties(name, "Number", "", "A", value);
AddChild(n);
}
void FBX::Node::AddP70color(
const std::string& name, double r, double g, double b
) {
FBX::Node n("P");
n.AddProperties(name, "ColorRGB", "Color", "", r, g, b);
AddChild(n);
}
void FBX::Node::AddP70colorA(
const std::string& name, double r, double g, double b
) {
FBX::Node n("P");
n.AddProperties(name, "Color", "", "A", r, g, b);
AddChild(n);
}
void FBX::Node::AddP70vector(
const std::string& name, double x, double y, double z
) {
FBX::Node n("P");
n.AddProperties(name, "Vector3D", "Vector", "", x, y, z);
AddChild(n);
}
void FBX::Node::AddP70vectorA(
const std::string& name, double x, double y, double z
) {
FBX::Node n("P");
n.AddProperties(name, "Vector", "", "A", x, y, z);
AddChild(n);
}
void FBX::Node::AddP70string(
const std::string& name, const std::string& value
) {
FBX::Node n("P");
n.AddProperties(name, "KString", "", "", value);
AddChild(n);
}
void FBX::Node::AddP70enum(
const std::string& name, int32_t value
) {
FBX::Node n("P");
n.AddProperties(name, "enum", "", "", value);
AddChild(n);
}
void FBX::Node::AddP70time(
const std::string& name, int64_t value
) {
FBX::Node n("P");
n.AddProperties(name, "KTime", "Time", "", value);
AddChild(n);
}
// public member functions for writing nodes to stream
void FBX::Node::Dump(
std::shared_ptr<Assimp::IOStream> outfile,
bool binary, int indent
) {
if (binary) {
Assimp::StreamWriterLE outstream(outfile);
DumpBinary(outstream);
} else {
std::ostringstream ss;
DumpAscii(ss, indent);
std::string s = ss.str();
outfile->Write(s.c_str(), s.size(), 1);
}
}
void FBX::Node::Dump(
Assimp::StreamWriterLE &outstream,
bool binary, int indent
) {
if (binary) {
DumpBinary(outstream);
} else {
std::ostringstream ss;
DumpAscii(ss, indent);
outstream.PutString(ss.str());
}
}
// public member functions for low-level writing
void FBX::Node::Begin(
Assimp::StreamWriterLE &s,
bool binary, int indent
) {
if (binary) {
BeginBinary(s);
} else {
// assume we're at the correct place to start already
(void)indent;
std::ostringstream ss;
BeginAscii(ss, indent);
s.PutString(ss.str());
}
}
void FBX::Node::DumpProperties(
Assimp::StreamWriterLE& s,
bool binary, int indent
) {
if (binary) {
DumpPropertiesBinary(s);
} else {
std::ostringstream ss;
DumpPropertiesAscii(ss, indent);
s.PutString(ss.str());
}
}
void FBX::Node::EndProperties(
Assimp::StreamWriterLE &s,
bool binary, int indent
) {
EndProperties(s, binary, indent, properties.size());
}
void FBX::Node::EndProperties(
Assimp::StreamWriterLE &s,
bool binary, int indent,
size_t num_properties
) {
if (binary) {
EndPropertiesBinary(s, num_properties);
} else {
// nothing to do
(void)indent;
}
}
void FBX::Node::BeginChildren(
Assimp::StreamWriterLE &s,
bool binary, int indent
) {
if (binary) {
// nothing to do
} else {
std::ostringstream ss;
BeginChildrenAscii(ss, indent);
s.PutString(ss.str());
}
}
void FBX::Node::DumpChildren(
Assimp::StreamWriterLE& s,
bool binary, int indent
) {
if (binary) {
DumpChildrenBinary(s);
} else {
std::ostringstream ss;
DumpChildrenAscii(ss, indent);
s.PutString(ss.str());
}
}
void FBX::Node::End(
Assimp::StreamWriterLE &s,
bool binary, int indent,
bool has_children
) {
if (binary) {
EndBinary(s, has_children);
} else {
std::ostringstream ss;
EndAscii(ss, indent, has_children);
s.PutString(ss.str());
}
}
// public member functions for writing to binary fbx
void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s)
{
// write header section (with placeholders for some things)
BeginBinary(s);
// write properties
DumpPropertiesBinary(s);
// go back and fill in property related placeholders
EndPropertiesBinary(s, properties.size());
// write children
DumpChildrenBinary(s);
// finish, filling in end offset placeholder
EndBinary(s, force_has_children || !children.empty());
}
// public member functions for writing to ascii fbx
void FBX::Node::DumpAscii(std::ostream &s, int indent)
{
// write name
BeginAscii(s, indent);
// write properties
DumpPropertiesAscii(s, indent);
if (force_has_children || !children.empty()) {
// begin children (with a '{')
BeginChildrenAscii(s, indent + 1);
// write children
DumpChildrenAscii(s, indent + 1);
}
// finish (also closing the children bracket '}')
EndAscii(s, indent, force_has_children || !children.empty());
}
// private member functions for low-level writing to fbx
void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
{
// remember start pos so we can come back and write the end pos
this->start_pos = s.Tell();
// placeholders for end pos and property section info
s.PutU4(0); // end pos
s.PutU4(0); // number of properties
s.PutU4(0); // total property section length
// node name
s.PutU1(uint8_t(name.size())); // length of node name
s.PutString(name); // node name as raw bytes
// property data comes after here
this->property_start = s.Tell();
}
void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s)
{
for (auto &p : properties) {
p.DumpBinary(s);
}
}
void FBX::Node::EndPropertiesBinary(
Assimp::StreamWriterLE &s,
size_t num_properties
) {
if (num_properties == 0) { return; }
size_t pos = s.Tell();
ai_assert(pos > property_start);
size_t property_section_size = pos - property_start;
s.Seek(start_pos + 4);
s.PutU4(uint32_t(num_properties));
s.PutU4(uint32_t(property_section_size));
s.Seek(pos);
}
void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s)
{
for (FBX::Node& child : children) {
child.DumpBinary(s);
}
}
void FBX::Node::EndBinary(
Assimp::StreamWriterLE &s,
bool has_children
) {
// if there were children, add a null record
if (has_children) { s.PutString(FBX::NULL_RECORD); }
// now go back and write initial pos
this->end_pos = s.Tell();
s.Seek(start_pos);
s.PutU4(uint32_t(end_pos));
s.Seek(end_pos);
}
void FBX::Node::BeginAscii(std::ostream& s, int indent)
{
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << name << ": ";
}
void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent)
{
for (size_t i = 0; i < properties.size(); ++i) {
if (i > 0) { s << ", "; }
properties[i].DumpAscii(s, indent);
}
}
void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent)
{
// only call this if there are actually children
s << " {";
(void)indent;
}
void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent)
{
// children will need a lot of padding and corralling
if (children.size() || force_has_children) {
for (size_t i = 0; i < children.size(); ++i) {
// no compression in ascii files, so skip this node if it exists
if (children[i].name == "EncryptionType") { continue; }
// the child can dump itself
children[i].DumpAscii(s, indent);
}
}
}
void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
{
if (!has_children) { return; } // nothing to do
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << "}";
}
// private helpers for static member functions
// ascii property node from vector of doubles
void FBX::Node::WritePropertyNodeAscii(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s,
int indent
){
char buffer[32];
FBX::Node node(name);
node.Begin(s, false, indent);
std::string vsize = std::to_string(v.size());
// *<size> {
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
// indent + 1
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
// a: value,value,value,...
s.PutString("a: ");
int count = 0;
for (size_t i = 0; i < v.size(); ++i) {
if (i > 0) { s.PutChar(','); }
int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]);
count += len;
if (count > 2048) { s.PutChar('\n'); count = 0; }
if (len < 0 || len > 31) {
// this should never happen
throw DeadlyExportError("failed to convert double to string");
}
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
}
// }
s.PutChar('\n');
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
s.PutChar('}'); s.PutChar(' ');
node.End(s, false, indent, false);
}
// ascii property node from vector of int32_t
void FBX::Node::WritePropertyNodeAscii(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s,
int indent
){
char buffer[32];
FBX::Node node(name);
node.Begin(s, false, indent);
std::string vsize = std::to_string(v.size());
// *<size> {
s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
// indent + 1
for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
// a: value,value,value,...
s.PutString("a: ");
int count = 0;
for (size_t i = 0; i < v.size(); ++i) {
if (i > 0) { s.PutChar(','); }
int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]);
count += len;
if (count > 2048) { s.PutChar('\n'); count = 0; }
if (len < 0 || len > 31) {
// this should never happen
throw DeadlyExportError("failed to convert double to string");
}
for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
}
// }
s.PutChar('\n');
for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
s.PutChar('}'); s.PutChar(' ');
node.End(s, false, indent, false);
}
// binary property node from vector of doubles
// TODO: optional zip compression!
void FBX::Node::WritePropertyNodeBinary(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s
){
FBX::Node node(name);
node.BeginBinary(s);
s.PutU1('d');
s.PutU4(uint32_t(v.size())); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(uint32_t(v.size()) * 8); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
node.EndPropertiesBinary(s, 1);
node.EndBinary(s, false);
}
// binary property node from vector of int32_t
// TODO: optional zip compression!
void FBX::Node::WritePropertyNodeBinary(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
){
FBX::Node node(name);
node.BeginBinary(s);
s.PutU1('i');
s.PutU4(uint32_t(v.size())); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(uint32_t(v.size()) * 4); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
node.EndPropertiesBinary(s, 1);
node.EndBinary(s, false);
}
// public static member functions
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
void FBX::Node::WritePropertyNode(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s,
bool binary, int indent
){
if (binary) {
FBX::Node::WritePropertyNodeBinary(name, v, s);
} else {
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
}
}
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
void FBX::Node::WritePropertyNode(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s,
bool binary, int indent
){
if (binary) {
FBX::Node::WritePropertyNodeBinary(name, v, s);
} else {
FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
}
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -0,0 +1,258 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file FBXExportNode.h
* Declares the FBX::Node helper class for fbx export.
*/
#ifndef AI_FBXEXPORTNODE_H_INC
#define AI_FBXEXPORTNODE_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportProperty.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
namespace FBX {
class Node;
}
class FBX::Node
{
public: // public data members
// TODO: accessors
std::string name; // node name
std::vector<FBX::Property> properties; // node properties
std::vector<FBX::Node> children; // child nodes
// some nodes always pretend they have children...
bool force_has_children = false;
public: // constructors
Node() = default;
Node(const std::string& n) : name(n) {}
// convenience template to construct with properties directly
template <typename... More>
Node(const std::string& n, const More... more)
: name(n)
{ AddProperties(more...); }
public: // functions to add properties or children
// add a single property to the node
template <typename T>
void AddProperty(T value) {
properties.emplace_back(value);
}
// convenience function to add multiple properties at once
template <typename T, typename... More>
void AddProperties(T value, More... more) {
properties.emplace_back(value);
AddProperties(more...);
}
void AddProperties() {}
// add a child node directly
void AddChild(const Node& node) { children.push_back(node); }
// convenience function to add a child node with a single property
template <typename... More>
void AddChild(
const std::string& name,
More... more
) {
FBX::Node c(name);
c.AddProperties(more...);
children.push_back(c);
}
public: // support specifically for dealing with Properties70 nodes
// it really is simpler to make these all separate functions.
// the versions with 'A' suffixes are for animatable properties.
// those often follow a completely different format internally in FBX.
void AddP70int(const std::string& name, int32_t value);
void AddP70bool(const std::string& name, bool value);
void AddP70double(const std::string& name, double value);
void AddP70numberA(const std::string& name, double value);
void AddP70color(const std::string& name, double r, double g, double b);
void AddP70colorA(const std::string& name, double r, double g, double b);
void AddP70vector(const std::string& name, double x, double y, double z);
void AddP70vectorA(const std::string& name, double x, double y, double z);
void AddP70string(const std::string& name, const std::string& value);
void AddP70enum(const std::string& name, int32_t value);
void AddP70time(const std::string& name, int64_t value);
// template for custom P70 nodes.
// anything that doesn't fit in the above can be created manually.
template <typename... More>
void AddP70(
const std::string& name,
const std::string& type,
const std::string& type2,
const std::string& flags,
More... more
) {
Node n("P");
n.AddProperties(name, type, type2, flags, more...);
AddChild(n);
}
public: // member functions for writing data to a file or stream
// write the full node to the given file or stream
void Dump(
std::shared_ptr<Assimp::IOStream> outfile,
bool binary, int indent
);
void Dump(Assimp::StreamWriterLE &s, bool binary, int indent);
// these other functions are for writing data piece by piece.
// they must be used carefully.
// for usage examples see FBXExporter.cpp.
void Begin(Assimp::StreamWriterLE &s, bool binary, int indent);
void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent);
void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent);
void EndProperties(
Assimp::StreamWriterLE &s, bool binary, int indent,
size_t num_properties
);
void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent);
void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent);
void End(
Assimp::StreamWriterLE &s, bool binary, int indent,
bool has_children
);
private: // internal functions used for writing
void DumpBinary(Assimp::StreamWriterLE &s);
void DumpAscii(Assimp::StreamWriterLE &s, int indent);
void DumpAscii(std::ostream &s, int indent);
void BeginBinary(Assimp::StreamWriterLE &s);
void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
void EndPropertiesBinary(Assimp::StreamWriterLE &s);
void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
void DumpChildrenBinary(Assimp::StreamWriterLE& s);
void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
void BeginAscii(std::ostream &s, int indent);
void DumpPropertiesAscii(std::ostream &s, int indent);
void BeginChildrenAscii(std::ostream &s, int indent);
void DumpChildrenAscii(std::ostream &s, int indent);
void EndAscii(std::ostream &s, int indent, bool has_children);
private: // data used for binary dumps
size_t start_pos; // starting position in stream
size_t end_pos; // ending position in stream
size_t property_start; // starting position of property section
public: // static member functions
// convenience function to create a node with a single property,
// and write it to the stream.
template <typename T>
static void WritePropertyNode(
const std::string& name,
const T value,
Assimp::StreamWriterLE& s,
bool binary, int indent
) {
FBX::Property p(value);
FBX::Node node(name, p);
node.Dump(s, binary, indent);
}
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
static void WritePropertyNode(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s,
bool binary, int indent
);
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
static void WritePropertyNode(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s,
bool binary, int indent
);
private: // static helper functions
static void WritePropertyNodeAscii(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s,
int indent
);
static void WritePropertyNodeAscii(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s,
int indent
);
static void WritePropertyNodeBinary(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s
);
static void WritePropertyNodeBinary(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
);
};
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTNODE_H_INC

View File

@ -0,0 +1,364 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportProperty.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <string>
#include <vector>
#include <ostream>
#include <locale>
#include <sstream> // ostringstream
// constructors for single element properties
FBX::Property::Property(bool v)
: type('C'), data(1)
{
data = {uint8_t(v)};
}
FBX::Property::Property(int16_t v) : type('Y'), data(2)
{
uint8_t* d = data.data();
(reinterpret_cast<int16_t*>(d))[0] = v;
}
FBX::Property::Property(int32_t v) : type('I'), data(4)
{
uint8_t* d = data.data();
(reinterpret_cast<int32_t*>(d))[0] = v;
}
FBX::Property::Property(float v) : type('F'), data(4)
{
uint8_t* d = data.data();
(reinterpret_cast<float*>(d))[0] = v;
}
FBX::Property::Property(double v) : type('D'), data(8)
{
uint8_t* d = data.data();
(reinterpret_cast<double*>(d))[0] = v;
}
FBX::Property::Property(int64_t v) : type('L'), data(8)
{
uint8_t* d = data.data();
(reinterpret_cast<int64_t*>(d))[0] = v;
}
// constructors for array-type properties
FBX::Property::Property(const char* c, bool raw)
: Property(std::string(c), raw)
{}
// strings can either be saved as "raw" (R) data, or "string" (S) data
FBX::Property::Property(const std::string& s, bool raw)
: type(raw ? 'R' : 'S'), data(s.size())
{
for (size_t i = 0; i < s.size(); ++i) {
data[i] = uint8_t(s[i]);
}
}
FBX::Property::Property(const std::vector<uint8_t>& r)
: type('R'), data(r)
{}
FBX::Property::Property(const std::vector<int32_t>& va)
: type('i'), data(4*va.size())
{
int32_t* d = reinterpret_cast<int32_t*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const std::vector<int64_t>& va)
: type('l'), data(8*va.size())
{
int64_t* d = reinterpret_cast<int64_t*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const std::vector<float>& va)
: type('f'), data(4*va.size())
{
float* d = reinterpret_cast<float*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const std::vector<double>& va)
: type('d'), data(8*va.size())
{
double* d = reinterpret_cast<double*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const aiMatrix4x4& vm)
: type('d'), data(8*16)
{
double* d = reinterpret_cast<double*>(data.data());
for (unsigned int c = 0; c < 4; ++c) {
for (unsigned int r = 0; r < 4; ++r) {
d[4*c+r] = vm[r][c];
}
}
}
// public member functions
size_t FBX::Property::size()
{
switch (type) {
case 'C': case 'Y': case 'I': case 'F': case 'D': case 'L':
return data.size() + 1;
case 'S': case 'R':
return data.size() + 5;
case 'i': case 'd':
return data.size() + 13;
default:
throw DeadlyExportError("Requested size on property of unknown type");
}
}
void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s)
{
s.PutU1(type);
uint8_t* d = data.data();
size_t N;
switch (type) {
case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
case 'S':
case 'R':
s.PutU4(uint32_t(data.size()));
for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
return;
case 'i':
N = data.size() / 4;
s.PutU4(uint32_t(N)); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size
for (size_t i = 0; i < N; ++i) {
s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
}
return;
case 'l':
N = data.size() / 8;
s.PutU4(uint32_t(N)); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size
for (size_t i = 0; i < N; ++i) {
s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
}
return;
case 'f':
N = data.size() / 4;
s.PutU4(uint32_t(N)); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size
for (size_t i = 0; i < N; ++i) {
s.PutF4((reinterpret_cast<float*>(d))[i]);
}
return;
case 'd':
N = data.size() / 8;
s.PutU4(uint32_t(N)); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(uint32_t(data.size())); // data size
for (size_t i = 0; i < N; ++i) {
s.PutF8((reinterpret_cast<double*>(d))[i]);
}
return;
default:
std::ostringstream err;
err << "Tried to dump property with invalid type '";
err << type << "'!";
throw DeadlyExportError(err.str());
}
}
void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent)
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss.precision(15); // this seems to match official FBX SDK exports
DumpAscii(ss, indent);
outstream.PutString(ss.str());
}
void FBX::Property::DumpAscii(std::ostream& s, int indent)
{
// no writing type... or anything. just shove it into the stream.
uint8_t* d = data.data();
size_t N;
size_t swap = data.size();
size_t count = 0;
switch (type) {
case 'C':
if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; }
else { s << 'F'; }
return;
case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return;
case 'I': s << *(reinterpret_cast<int32_t*>(d)); return;
case 'F': s << *(reinterpret_cast<float*>(d)); return;
case 'D': s << *(reinterpret_cast<double*>(d)); return;
case 'L': s << *(reinterpret_cast<int64_t*>(d)); return;
case 'S':
// first search to see if it has "\x00\x01" in it -
// which separates fields which are reversed in the ascii version.
// yeah.
// FBX, yeah.
for (size_t i = 0; i < data.size(); ++i) {
if (data[i] == '\0') {
swap = i;
break;
}
}
case 'R':
s << '"';
// we might as well check this now,
// probably it will never happen
for (size_t i = 0; i < data.size(); ++i) {
char c = data[i];
if (c == '"') {
throw runtime_error("can't handle quotes in property string");
}
}
// first write the SWAPPED member (if any)
for (size_t i = swap + 2; i < data.size(); ++i) {
char c = data[i];
s << c;
}
// then a separator
if (swap != data.size()) {
s << "::";
}
// then the initial member
for (size_t i = 0; i < swap; ++i) {
char c = data[i];
s << c;
}
s << '"';
return;
case 'i':
N = data.size() / 4; // number of elements
s << '*' << N << " {\n";
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
s << "a: ";
for (size_t i = 0; i < N; ++i) {
if (i > 0) { s << ','; }
if (count++ > 120) { s << '\n'; count = 0; }
s << (reinterpret_cast<int32_t*>(d))[i];
}
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << "} ";
return;
case 'l':
N = data.size() / 8;
s << '*' << N << " {\n";
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
s << "a: ";
for (size_t i = 0; i < N; ++i) {
if (i > 0) { s << ','; }
if (count++ > 120) { s << '\n'; count = 0; }
s << (reinterpret_cast<int64_t*>(d))[i];
}
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << "} ";
return;
case 'f':
N = data.size() / 4;
s << '*' << N << " {\n";
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
s << "a: ";
for (size_t i = 0; i < N; ++i) {
if (i > 0) { s << ','; }
if (count++ > 120) { s << '\n'; count = 0; }
s << (reinterpret_cast<float*>(d))[i];
}
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << "} ";
return;
case 'd':
N = data.size() / 8;
s << '*' << N << " {\n";
for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
s << "a: ";
// set precision to something that can handle doubles
s.precision(15);
for (size_t i = 0; i < N; ++i) {
if (i > 0) { s << ','; }
if (count++ > 120) { s << '\n'; count = 0; }
s << (reinterpret_cast<double*>(d))[i];
}
s << '\n';
for (int i = 0; i < indent; ++i) { s << '\t'; }
s << "} ";
return;
default:
std::ostringstream err;
err << "Tried to dump property with invalid type '";
err << type << "'!";
throw runtime_error(err.str());
}
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -0,0 +1,129 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file FBXExportProperty.h
* Declares the FBX::Property helper class for fbx export.
*/
#ifndef AI_FBXEXPORTPROPERTY_H_INC
#define AI_FBXEXPORTPROPERTY_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include <assimp/types.h> // aiMatrix4x4
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
#include <ostream>
#include <type_traits> // is_void
namespace FBX {
class Property;
}
/** FBX::Property
*
* Holds a value of any of FBX's recognized types,
* each represented by a particular one-character code.
* C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true
* Y : 2-byte int16
* I : 4-byte int32
* F : 4-byte float
* D : 8-byte double
* L : 8-byte int64
* i : array of int32
* f : array of float
* d : array of double
* l : array of int64
* b : array of 1-byte booleans (0x00 or 0x01)
* S : string (array of 1-byte char)
* R : raw data (array of bytes)
*/
class FBX::Property
{
public:
// constructors for basic types.
// all explicit to avoid accidental typecasting
explicit Property(bool v);
// TODO: determine if there is actually a byte type,
// or if this always means <bool>. 'C' seems to imply <char>,
// so possibly the above was intended to represent both.
explicit Property(int16_t v);
explicit Property(int32_t v);
explicit Property(float v);
explicit Property(double v);
explicit Property(int64_t v);
// strings can either be stored as 'R' (raw) or 'S' (string) type
explicit Property(const char* c, bool raw=false);
explicit Property(const std::string& s, bool raw=false);
explicit Property(const std::vector<uint8_t>& r);
explicit Property(const std::vector<int32_t>& va);
explicit Property(const std::vector<int64_t>& va);
explicit Property(const std::vector<double>& va);
explicit Property(const std::vector<float>& va);
explicit Property(const aiMatrix4x4& vm);
// this will catch any type not defined above,
// so that we don't accidentally convert something we don't want.
// for example (const char*) --> (bool)... seriously wtf C++
template <class T>
explicit Property(T v) : type('X') {
static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
} // note: no line wrap so it appears verbatim on the compiler error
// the size of this property node in a binary file, in bytes
size_t size();
// write this property node as binary data to the given stream
void DumpBinary(Assimp::StreamWriterLE &s);
void DumpAscii(Assimp::StreamWriterLE &s, int indent=0);
void DumpAscii(std::ostream &s, int indent=0);
// note: make sure the ostream is in classic "C" locale
private:
char type;
std::vector<uint8_t> data;
};
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTPROPERTY_H_INC

2475
code/FBXExporter.cpp 100644

File diff suppressed because it is too large Load Diff

178
code/FBXExporter.h 100644
View File

@ -0,0 +1,178 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file FBXExporter.h
* Declares the exporter class to write a scene to an fbx file
*/
#ifndef AI_FBXEXPORTER_H_INC
#define AI_FBXEXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportNode.h" // FBX::Node
#include "FBXCommon.h" // FBX::TransformInheritance
#include <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <vector>
#include <map>
#include <unordered_set>
#include <memory> // shared_ptr
#include <sstream> // stringstream
struct aiScene;
struct aiNode;
//struct aiMaterial;
namespace Assimp
{
class IOSystem;
class IOStream;
class ExportProperties;
// ---------------------------------------------------------------------
/** Helper class to export a given scene to an FBX file. */
// ---------------------------------------------------------------------
class FBXExporter
{
public:
/// Constructor for a specific scene to export
FBXExporter(const aiScene* pScene, const ExportProperties* pProperties);
// call one of these methods to export
void ExportBinary(const char* pFile, IOSystem* pIOSystem);
void ExportAscii(const char* pFile, IOSystem* pIOSystem);
private:
bool binary; // whether current export is in binary or ascii format
const aiScene* mScene; // the scene to export
const ExportProperties* mProperties; // currently unused
std::shared_ptr<IOStream> outfile; // file to write to
std::vector<FBX::Node> connections; // conection storage
std::vector<int64_t> mesh_uids;
std::vector<int64_t> material_uids;
std::map<const aiNode*,int64_t> node_uids;
// this crude unique-ID system is actually fine
int64_t last_uid = 999999;
int64_t generate_uid() { return ++last_uid; }
// binary files have a specific header and footer,
// in addition to the actual data
void WriteBinaryHeader();
void WriteBinaryFooter();
// ascii files have a comment at the top
void WriteAsciiHeader();
// WriteAllNodes does the actual export.
// It just calls all the Write<Section> methods below in order.
void WriteAllNodes();
// Methods to write individual sections.
// The order here matches the order inside an FBX file.
// Each method corresponds to a top-level FBX section,
// except WriteHeader which also includes some binary-only sections
// and WriteFooter which is binary data only.
void WriteHeaderExtension();
// WriteFileId(); // binary-only, included in WriteHeader
// WriteCreationTime(); // binary-only, included in WriteHeader
// WriteCreator(); // binary-only, included in WriteHeader
void WriteGlobalSettings();
void WriteDocuments();
void WriteReferences();
void WriteDefinitions();
void WriteObjects();
void WriteConnections();
// WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
// helpers
void WriteAsciiSectionHeader(const std::string& title);
void WriteModelNodes(
Assimp::StreamWriterLE& s,
const aiNode* node,
int64_t parent_uid,
const std::unordered_set<const aiNode*>& limbnodes
);
void WriteModelNodes( // usually don't call this directly
StreamWriterLE& s,
const aiNode* node,
int64_t parent_uid,
const std::unordered_set<const aiNode*>& limbnodes,
std::vector<std::pair<std::string,aiVector3D>>& transform_chain
);
void WriteModelNode( // nor this
StreamWriterLE& s,
bool binary,
const aiNode* node,
int64_t node_uid,
const std::string& type,
const std::vector<std::pair<std::string,aiVector3D>>& xfm_chain,
FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs
);
void WriteAnimationCurveNode(
StreamWriterLE& outstream,
int64_t uid,
std::string name, // "T", "R", or "S"
aiVector3D default_value,
std::string property_name, // "Lcl Translation" etc
int64_t animation_layer_uid,
int64_t node_uid
);
void WriteAnimationCurve(
StreamWriterLE& outstream,
double default_value,
const std::vector<int64_t>& times,
const std::vector<float>& values,
int64_t curvenode_id,
const std::string& property_link // "d|X", "d|Y", etc
);
};
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTER_H_INC

View File

@ -54,6 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXProperties.h" #include "FBXProperties.h"
#include <assimp/ByteSwapper.h> #include <assimp/ByteSwapper.h>
#include <algorithm> // std::transform
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -82,11 +84,12 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
std::string templateName; std::string templateName;
const char* const sh = shading.c_str(); // lower-case shading because Blender (for example) writes "Phong"
if(!strcmp(sh,"phong")) { std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower);
if(shading == "phong") {
templateName = "Material.FbxSurfacePhong"; templateName = "Material.FbxSurfacePhong";
} }
else if(!strcmp(sh,"lambert")) { else if(shading == "lambert") {
templateName = "Material.FbxSurfaceLambert"; templateName = "Material.FbxSurfaceLambert";
} }
else { else {

View File

@ -79,14 +79,13 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Geometry::~Geometry() Geometry::~Geometry()
{ {
// empty
} }
const Skin* Geometry::DeformerSkin() const { const Skin* Geometry::DeformerSkin() const {
return skin; return skin;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Geometry(id, element,name, doc) : Geometry(id, element,name, doc)
@ -186,9 +185,8 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
MeshGeometry::~MeshGeometry() MeshGeometry::~MeshGeometry() {
{ // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -308,7 +306,6 @@ void MeshGeometry::ReadLayerElement(const Scope& layerElement)
<< type << ", index: " << typedIndex); << type << ", index: " << typedIndex);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
{ {
@ -412,7 +409,6 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Lengthy utility function to read and resolve a FBX vertex data array - that is, the // Lengthy utility function to read and resolve a FBX vertex data array - that is, the
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors, // output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
@ -428,16 +424,19 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const std::vector<unsigned int>& mapping_offsets, const std::vector<unsigned int>& mapping_offsets,
const std::vector<unsigned int>& mappings) const std::vector<unsigned int>& mappings)
{ {
bool isDirect = ReferenceInformationType == "Direct";
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
// fall-back to direct data if there is no index data element
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
isDirect = true;
isIndexToDirect = false;
}
// handle permutations of Mapping and Reference type - it would be nice to // handle permutations of Mapping and Reference type - it would be nice to
// deal with this more elegantly and with less redundancy, but right // deal with this more elegantly and with less redundancy, but right
// now it seems unavoidable. // now it seems unavoidable.
if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") { if (MappingInformationType == "ByVertice" && isDirect) {
if ( !HasElement( source, indexDataElementName ) ) {
return;
}
std::vector<T> tempData; std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@ -450,14 +449,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
} }
} }
} }
else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") { else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
std::vector<T> tempData; std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
data_out.resize(vertex_count); data_out.resize(vertex_count);
if ( !HasElement( source, indexDataElementName ) ) {
return;
}
std::vector<int> uvIndices; std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
@ -472,7 +468,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
} }
} }
} }
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") { else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
std::vector<T> tempData; std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@ -485,7 +481,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
data_out.swap(tempData); data_out.swap(tempData);
} }
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") { else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
std::vector<T> tempData; std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@ -499,8 +495,13 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
return; return;
} }
const T empty;
unsigned int next = 0; unsigned int next = 0;
for(int i : uvIndices) { for(int i : uvIndices) {
if ( -1 == i ) {
data_out[ next++ ] = empty;
continue;
}
if (static_cast<size_t>(i) >= tempData.size()) { if (static_cast<size_t>(i) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
} }
@ -528,7 +529,6 @@ void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, c
m_mappings); m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
const std::string& MappingInformationType, const std::string& MappingInformationType,
@ -543,7 +543,6 @@ void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope
m_mappings); m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source, void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
const std::string& MappingInformationType, const std::string& MappingInformationType,

View File

@ -68,7 +68,6 @@ private:
const Skin* skin; const Skin* skin;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;
@ -95,8 +94,8 @@ public:
* if no tangents are specified */ * if no tangents are specified */
const std::vector<aiVector3D>& GetTangents() const; const std::vector<aiVector3D>& GetTangents() const;
/** Get a list of all vertex binormals or an empty array /** Get a list of all vertex bi-normals or an empty array
* if no binormals are specified */ * if no bi-normals are specified */
const std::vector<aiVector3D>& GetBinormals() const; const std::vector<aiVector3D>& GetBinormals() const;
/** Return list of faces - each entry denotes a face and specifies /** Return list of faces - each entry denotes a face and specifies

View File

@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Implements a filter system to filter calls to Exists() and Open() * Implements a filter system to filter calls to Exists() and Open()
* in order to improve the success rate of file opening ... * in order to improve the success rate of file opening ...
*/ */
#pragma once
#ifndef AI_FILESYSTEMFILTER_H_INC #ifndef AI_FILESYSTEMFILTER_H_INC
#define AI_FILESYSTEMFILTER_H_INC #define AI_FILESYSTEMFILTER_H_INC
#include "../include/assimp/IOSystem.hpp" #include <assimp/IOSystem.hpp>
#include "../include/assimp/DefaultLogger.hpp" #include <assimp/DefaultLogger.hpp>
#include "../include/assimp/fast_atof.h" #include <assimp/fast_atof.h>
#include "../include/assimp/ParsingUtils.h" #include <assimp/ParsingUtils.h>
namespace Assimp { namespace Assimp {
@ -64,90 +65,89 @@ class FileSystemFilter : public IOSystem
public: public:
/** Constructor. */ /** Constructor. */
FileSystemFilter(const std::string& file, IOSystem* old) FileSystemFilter(const std::string& file, IOSystem* old)
: wrapped (old) : mWrapped (old)
, src_file (file) , mSrc_file(file)
, sep(wrapped->getOsSeparator()) , sep(mWrapped->getOsSeparator()) {
{ ai_assert(nullptr != mWrapped);
ai_assert(NULL != wrapped);
// Determine base directory // Determine base directory
base = src_file; mBase = mSrc_file;
std::string::size_type ss2; std::string::size_type ss2;
if (std::string::npos != (ss2 = base.find_last_of("\\/"))) { if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) {
base.erase(ss2,base.length()-ss2); mBase.erase(ss2,mBase.length()-ss2);
} } else {
else { mBase = "";
base = "";
// return;
} }
// make sure the directory is terminated properly // make sure the directory is terminated properly
char s; char s;
if (base.length() == 0) { if ( mBase.empty() ) {
base = "."; mBase = ".";
base += getOsSeparator(); mBase += getOsSeparator();
} } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
else if ((s = *(base.end()-1)) != '\\' && s != '/') { mBase += getOsSeparator();
base += getOsSeparator();
} }
DefaultLogger::get()->info("Import root directory is \'" + base + "\'"); DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'");
} }
/** Destructor. */ /** Destructor. */
~FileSystemFilter() ~FileSystemFilter() {
{ // empty
// haha
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Tests for the existence of a file at the given path. */ /** Tests for the existence of a file at the given path. */
bool Exists( const char* pFile) const bool Exists( const char* pFile) const {
{ ai_assert( nullptr != mWrapped );
std::string tmp = pFile; std::string tmp = pFile;
// Currently this IOSystem is also used to open THE ONE FILE. // Currently this IOSystem is also used to open THE ONE FILE.
if (tmp != src_file) { if (tmp != mSrc_file) {
BuildPath(tmp); BuildPath(tmp);
Cleanup(tmp); Cleanup(tmp);
} }
return wrapped->Exists(tmp); return mWrapped->Exists(tmp);
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns the directory separator. */ /** Returns the directory separator. */
char getOsSeparator() const char getOsSeparator() const {
{
return sep; return sep;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Open a new file with a given path. */ /** Open a new file with a given path. */
IOStream* Open( const char* pFile, const char* pMode = "rb") IOStream* Open( const char* pFile, const char* pMode = "rb") {
{ ai_assert( nullptr != mWrapped );
ai_assert(pFile); if ( nullptr == pFile || nullptr == pMode ) {
ai_assert(pMode); return nullptr;
}
ai_assert( nullptr != pFile );
ai_assert( nullptr != pMode );
// First try the unchanged path // First try the unchanged path
IOStream* s = wrapped->Open(pFile,pMode); IOStream* s = mWrapped->Open(pFile,pMode);
if (!s) { if (nullptr == s) {
std::string tmp = pFile; std::string tmp = pFile;
// Try to convert between absolute and relative paths // Try to convert between absolute and relative paths
BuildPath(tmp); BuildPath(tmp);
s = wrapped->Open(tmp,pMode); s = mWrapped->Open(tmp,pMode);
if (!s) { if (nullptr == s) {
// Finally, look for typical issues with paths // Finally, look for typical issues with paths
// and try to correct them. This is our last // and try to correct them. This is our last
// resort. // resort.
tmp = pFile; tmp = pFile;
Cleanup(tmp); Cleanup(tmp);
BuildPath(tmp); BuildPath(tmp);
s = wrapped->Open(tmp,pMode); s = mWrapped->Open(tmp,pMode);
} }
} }
@ -156,27 +156,75 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Closes the given file and releases all resources associated with it. */ /** Closes the given file and releases all resources associated with it. */
void Close( IOStream* pFile) void Close( IOStream* pFile) {
{ ai_assert( nullptr != mWrapped );
return wrapped->Close(pFile); return mWrapped->Close(pFile);
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Compare two paths */ /** Compare two paths */
bool ComparePaths (const char* one, const char* second) const bool ComparePaths (const char* one, const char* second) const {
{ ai_assert( nullptr != mWrapped );
return wrapped->ComparePaths (one,second); return mWrapped->ComparePaths (one,second);
}
// -------------------------------------------------------------------
/** Pushes a new directory onto the directory stack. */
bool PushDirectory(const std::string &path ) {
ai_assert( nullptr != mWrapped );
return mWrapped->PushDirectory(path);
}
// -------------------------------------------------------------------
/** Returns the top directory from the stack. */
const std::string &CurrentDirectory() const {
ai_assert( nullptr != mWrapped );
return mWrapped->CurrentDirectory();
}
// -------------------------------------------------------------------
/** Returns the number of directories stored on the stack. */
size_t StackSize() const {
ai_assert( nullptr != mWrapped );
return mWrapped->StackSize();
}
// -------------------------------------------------------------------
/** Pops the top directory from the stack. */
bool PopDirectory() {
ai_assert( nullptr != mWrapped );
return mWrapped->PopDirectory();
}
// -------------------------------------------------------------------
/** Creates an new directory at the given path. */
bool CreateDirectory(const std::string &path) {
ai_assert( nullptr != mWrapped );
return mWrapped->CreateDirectory(path);
}
// -------------------------------------------------------------------
/** Will change the current directory to the given path. */
bool ChangeDirectory(const std::string &path) {
ai_assert( nullptr != mWrapped );
return mWrapped->ChangeDirectory(path);
}
// -------------------------------------------------------------------
/** Delete file. */
bool DeleteFile(const std::string &file) {
ai_assert( nullptr != mWrapped );
return mWrapped->DeleteFile(file);
} }
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build a valid path from a given relative or absolute path. /** Build a valid path from a given relative or absolute path.
*/ */
void BuildPath (std::string& in) const void BuildPath (std::string& in) const {
{ ai_assert( nullptr != mWrapped );
// if we can already access the file, great. // if we can already access the file, great.
if (in.length() < 3 || wrapped->Exists(in)) { if (in.length() < 3 || mWrapped->Exists(in)) {
return; return;
} }
@ -184,8 +232,8 @@ private:
if (in[1] != ':') { if (in[1] != ':') {
// append base path and try // append base path and try
const std::string tmp = base + in; const std::string tmp = mBase + in;
if (wrapped->Exists(tmp)) { if (mWrapped->Exists(tmp)) {
in = tmp; in = tmp;
return; return;
} }
@ -207,7 +255,7 @@ private:
std::string::size_type last_dirsep = std::string::npos; std::string::size_type last_dirsep = std::string::npos;
while(true) { while(true) {
tmp = base; tmp = mBase;
tmp += sep; tmp += sep;
std::string::size_type dirsep = in.rfind('/', last_dirsep); std::string::size_type dirsep = in.rfind('/', last_dirsep);
@ -223,7 +271,7 @@ private:
last_dirsep = dirsep-1; last_dirsep = dirsep-1;
tmp += in.substr(dirsep+1, in.length()-pos); tmp += in.substr(dirsep+1, in.length()-pos);
if (wrapped->Exists(tmp)) { if (mWrapped->Exists(tmp)) {
in = tmp; in = tmp;
return; return;
} }
@ -236,15 +284,14 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Cleanup the given path /** Cleanup the given path
*/ */
void Cleanup (std::string& in) const void Cleanup (std::string& in) const {
{
char last = 0;
if(in.empty()) { if(in.empty()) {
return; return;
} }
// Remove a very common issue when we're parsing file names: spaces at the // Remove a very common issue when we're parsing file names: spaces at the
// beginning of the path. // beginning of the path.
char last = 0;
std::string::iterator it = in.begin(); std::string::iterator it = in.begin();
while (IsSpaceOrNewLine( *it ))++it; while (IsSpaceOrNewLine( *it ))++it;
if (it != in.begin()) { if (it != in.begin()) {
@ -274,9 +321,7 @@ private:
it = in.erase(it); it = in.erase(it);
--it; --it;
} }
} } else if (*it == '%' && in.end() - it > 2) {
else if (*it == '%' && in.end() - it > 2) {
// Hex sequence in URIs // Hex sequence in URIs
if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) { if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
*it = HexOctetToDecimal(&*it); *it = HexOctetToDecimal(&*it);
@ -290,8 +335,8 @@ private:
} }
private: private:
IOSystem* wrapped; IOSystem *mWrapped;
std::string src_file, base; std::string mSrc_file, mBase;
char sep; char sep;
}; };

View File

@ -60,9 +60,9 @@ namespace Assimp {
* @param in Input mesh * @param in Input mesh
* @return Hash. * @return Hash.
*/ */
inline uint64_t GetMeshHash(aiMesh* in) inline
{ uint64_t GetMeshHash(aiMesh* in) {
ai_assert(NULL != in); ai_assert(nullptr != in);
// ... get an unique value representing the vertex format of the mesh // ... get an unique value representing the vertex format of the mesh
const unsigned int fhash = GetMeshVFormatUnique(in); const unsigned int fhash = GetMeshVFormatUnique(in);
@ -78,14 +78,14 @@ inline uint64_t GetMeshHash(aiMesh* in)
/** @brief Perform a component-wise comparison of two arrays /** @brief Perform a component-wise comparison of two arrays
* *
* @param first First array * @param first First array
* @param second Second aray * @param second Second array
* @param size Size of both arrays * @param size Size of both arrays
* @param e Epsilon * @param e Epsilon
* @return true if the arrays are identical * @return true if the arrays are identical
*/ */
inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second, inline
unsigned int size, float e) bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
{ unsigned int size, float e) {
for (const aiVector3D* end = first+size; first != end; ++first,++second) { for (const aiVector3D* end = first+size; first != end; ++first,++second) {
if ( (*first - *second).SquareLength() >= e) if ( (*first - *second).SquareLength() >= e)
return false; return false;

View File

@ -100,26 +100,22 @@ IRRImporter::~IRRImporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
/* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and
* search for typical tokens.
*/
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
if ( extension == "irr" ) {
if (extension == "irr")return true; return true;
else if (extension == "xml" || checkSig) } else if (extension == "xml" || checkSig) {
{
/* If CanRead() is called in order to check whether we /* If CanRead() is called in order to check whether we
* support a specific file extension in general pIOHandler * support a specific file extension in general pIOHandler
* might be NULL and it's our duty to return true here. * might be NULL and it's our duty to return true here.
*/ */
if (!pIOHandler)return true; if ( nullptr == pIOHandler ) {
return true;
}
const char* tokens[] = {"irr_scene"}; const char* tokens[] = {"irr_scene"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
} }
return false; return false;
} }

View File

@ -190,7 +190,7 @@ Importer::~Importer()
delete pimpl->mIOHandler; delete pimpl->mIOHandler;
delete pimpl->mProgressHandler; delete pimpl->mProgressHandler;
// Kill imported scene. Destructors should do that recursivly // Kill imported scene. Destructor's should do that recursively
delete pimpl->mScene; delete pimpl->mScene;
// Delete shared post-processing data // Delete shared post-processing data
@ -200,18 +200,6 @@ Importer::~Importer()
delete pimpl; delete pimpl;
} }
// ------------------------------------------------------------------------------------------------
// Copy constructor - copies the config of another Importer, not the scene
Importer::Importer(const Importer &other)
: pimpl(NULL) {
new(this) Importer();
pimpl->mIntProperties = other.pimpl->mIntProperties;
pimpl->mFloatProperties = other.pimpl->mFloatProperties;
pimpl->mStringProperties = other.pimpl->mStringProperties;
pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Register a custom post-processing step // Register a custom post-processing step
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
@ -634,7 +622,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
if (s != std::string::npos) { if (s != std::string::npos) {
DefaultLogger::get()->info("File extension not known, trying signature-based detection"); DefaultLogger::get()->info("File extension not known, trying signature-based detection");
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
imp = pimpl->mImporter[a]; imp = pimpl->mImporter[a];
break; break;
@ -959,6 +946,7 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const
size_t Importer::GetImporterIndex (const char* szExtension) const size_t Importer::GetImporterIndex (const char* szExtension) const
{ {
ai_assert(szExtension); ai_assert(szExtension);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// skip over wildcard and dot characters at string head -- // skip over wildcard and dot characters at string head --

View File

@ -141,7 +141,8 @@ bool IFCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
// it is only unambiguous as long as we don't support any further // it is only unambiguous as long as we don't support any further
// file formats with STEP as their encoding. // file formats with STEP as their encoding.
const char* tokens[] = {"ISO-10303-21"}; const char* tokens[] = {"ISO-10303-21"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); const bool found( SearchFileHeaderForToken( pIOHandler, pFile, tokens, 1 ) );
return found;
} }
return false; return false;
} }
@ -583,8 +584,7 @@ typedef std::map<std::string, std::string> Metadata;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties, void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
const std::string& prefix = "", const std::string& prefix = "",
unsigned int nest = 0) unsigned int nest = 0) {
{
for(const Schema_2x3::IfcProperty& property : set) { for(const Schema_2x3::IfcProperty& property : set) {
const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name; const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) { if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {

View File

@ -40,13 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */ /** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include "IFCReaderGen.h" #include "AssimpPCH.h"
#include "IFCReaderGen4.h"
namespace Assimp { namespace Assimp {
using namespace IFC; using namespace IFC;
using namespace ::Assimp::IFC::Schema_4;
namespace { namespace {

View File

@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
namespace Schema_4 {
using namespace STEP; using namespace STEP;
using namespace STEP::EXPRESS; using namespace STEP::EXPRESS;
@ -5443,6 +5445,7 @@ namespace STEP {
#undef DECL_CONV_STUB #undef DECL_CONV_STUB
} //! Schema_4
} //! STEP } //! STEP
} //! Assimp } //! Assimp

View File

@ -432,7 +432,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart); unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
if (layer.mName != "<LWODefault>" || num > 0) { if (layer.mName != "<LWODefault>" || num > 0) {
aiNode* pcNode = new aiNode(); aiNode* pcNode = new aiNode();
apcNodes[layer.mIndex] = pcNode;
pcNode->mName.Set(layer.mName); pcNode->mName.Set(layer.mName);
pcNode->mParent = (aiNode*)&layer; pcNode->mParent = (aiNode*)&layer;
pcNode->mNumMeshes = num; pcNode->mNumMeshes = num;
@ -442,6 +441,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p) for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
pcNode->mMeshes[p] = p + meshStart; pcNode->mMeshes[p] = p + meshStart;
} }
apcNodes[layer.mIndex] = pcNode;
} }
} }
@ -584,7 +584,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
//Set parent of all children, inserting pivots //Set parent of all children, inserting pivots
//std::cout << "Set parent of all children" << std::endl; //std::cout << "Set parent of all children" << std::endl;
std::map<uint16_t, aiNode*> mapPivot; std::map<uint16_t, aiNode*> mapPivot;
for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
//Get the parent index //Get the parent index
LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent); LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
@ -593,7 +593,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
//Create pivot node, store it into the pivot map, and set the parent as the pivot //Create pivot node, store it into the pivot map, and set the parent as the pivot
aiNode* pivotNode = new aiNode(); aiNode* pivotNode = new aiNode();
pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data)); pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
mapPivot[-(itapcNodes->first+2)] = pivotNode;
itapcNodes->second->mParent = pivotNode; itapcNodes->second->mParent = pivotNode;
//Look for the parent node to attach the pivot to //Look for the parent node to attach the pivot to
@ -611,18 +610,19 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
mapPivot[-(itapcNodes->first+2)] = pivotNode;
} }
//Merge pivot map into node map //Merge pivot map into node map
//std::cout << "Merge pivot map into node map" << std::endl; //std::cout << "Merge pivot map into node map" << std::endl;
for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
apcNodes[itMapPivot->first] = itMapPivot->second; apcNodes[itMapPivot->first] = itMapPivot->second;
} }
//Set children of all parents //Set children of all parents
apcNodes[-1] = root; apcNodes[-1] = root;
for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) { for (auto itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
++(itMapParentNodes->second->mNumChildren); ++(itMapParentNodes->second->mNumChildren);
} }
@ -630,7 +630,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
if (itMapParentNodes->second->mNumChildren) { if (itMapParentNodes->second->mNumChildren) {
itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ]; itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
uint16_t p = 0; uint16_t p = 0;
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second; itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
} }

View File

@ -120,7 +120,11 @@ public:
{ {
unsigned int mBone; ///< Index of the bone unsigned int mBone; ///< Index of the bone
float mWeight; ///< Weight of that bone on this vertex float mWeight; ///< Weight of that bone on this vertex
Weight() { } Weight()
: mBone(0)
, mWeight(0.0f)
{ }
Weight( unsigned int pBone, float pWeight) Weight( unsigned int pBone, float pWeight)
{ {
mBone = pBone; mBone = pBone;

View File

@ -844,11 +844,11 @@ struct IntGroupInfo_MDL7
struct IntGroupData_MDL7 struct IntGroupData_MDL7
{ {
IntGroupData_MDL7() IntGroupData_MDL7()
: pcFaces(NULL), bNeed2UV(false) : bNeed2UV(false)
{} {}
//! Array of faces that belong to the group //! Array of faces that belong to the group
MDL::IntFace_MDL7* pcFaces; std::vector<MDL::IntFace_MDL7> pcFaces;
//! Array of vertex positions //! Array of vertex positions
std::vector<aiVector3D> vPositions; std::vector<aiVector3D> vPositions;

View File

@ -1502,7 +1502,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
groupData.bNeed2UV = true; groupData.bNeed2UV = true;
} }
} }
groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris]; groupData.pcFaces.resize(groupInfo.pcGroup->numtris);
// read all faces into the preallocated arrays // read all faces into the preallocated arrays
ReadFaces_3DGS_MDL7(groupInfo, groupData); ReadFaces_3DGS_MDL7(groupInfo, groupData);

View File

@ -132,18 +132,18 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt
mOutputMat.precision(16); mOutputMat.precision(16);
WriteGeometryFile(noMtl); WriteGeometryFile(noMtl);
if (!noMtl) if ( !noMtl ) {
WriteMaterialFile(); WriteMaterialFile();
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ObjExporter::~ObjExporter() { ObjExporter::~ObjExporter() {
// empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string ObjExporter :: GetMaterialLibName() std::string ObjExporter::GetMaterialLibName() {
{
// within the Obj file, we use just the relative file name with the path stripped // within the Obj file, we use just the relative file name with the path stripped
const std::string& s = GetMaterialLibFileName(); const std::string& s = GetMaterialLibFileName();
std::string::size_type il = s.find_last_of("/\\"); std::string::size_type il = s.find_last_of("/\\");
@ -158,8 +158,9 @@ std::string ObjExporter :: GetMaterialLibName()
std::string ObjExporter::GetMaterialLibFileName() { std::string ObjExporter::GetMaterialLibFileName() {
// Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl // Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
size_t lastdot = filename.find_last_of('.'); size_t lastdot = filename.find_last_of('.');
if (lastdot != std::string::npos) if ( lastdot != std::string::npos ) {
return filename.substr( 0, lastdot ) + MaterialExt; return filename.substr( 0, lastdot ) + MaterialExt;
}
return filename + MaterialExt; return filename + MaterialExt;
} }
@ -172,8 +173,7 @@ void ObjExporter::WriteHeader(std::ostringstream& out) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string ObjExporter::GetMaterialName(unsigned int index) std::string ObjExporter::GetMaterialName(unsigned int index) {
{
const aiMaterial* const mat = pScene->mMaterials[index]; const aiMaterial* const mat = pScene->mMaterials[index];
if ( nullptr == mat ) { if ( nullptr == mat ) {
static const std::string EmptyStr; static const std::string EmptyStr;
@ -191,8 +191,7 @@ std::string ObjExporter::GetMaterialName(unsigned int index)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ObjExporter::WriteMaterialFile() void ObjExporter::WriteMaterialFile() {
{
WriteHeader(mOutputMat); WriteHeader(mOutputMat);
for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) { for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
@ -310,8 +309,9 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
if (!m.name.empty()) { if (!m.name.empty()) {
mOutput << "g " << m.name << endl; mOutput << "g " << m.name << endl;
} }
if (!noMtl) if ( !noMtl ) {
mOutput << "usemtl " << m.matname << endl; mOutput << "usemtl " << m.matname << endl;
}
for(const Face& f : m.faces) { for(const Face& f : m.faces) {
mOutput << f.kind << ' '; mOutput << f.kind << ' ';
@ -436,8 +436,7 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) {
{
const aiMatrix4x4& mAbs = mParent * nd->mTransformation; const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {

View File

@ -207,30 +207,24 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
// Create the root node of the scene // Create the root node of the scene
pScene->mRootNode = new aiNode; pScene->mRootNode = new aiNode;
if ( !pModel->m_ModelName.empty() ) if ( !pModel->m_ModelName.empty() ) {
{
// Set the name of the scene // Set the name of the scene
pScene->mRootNode->mName.Set(pModel->m_ModelName); pScene->mRootNode->mName.Set(pModel->m_ModelName);
} } else {
else
{
// This is a fatal error, so break down the application // This is a fatal error, so break down the application
ai_assert(false); ai_assert(false);
} }
// Create nodes for the whole scene // Create nodes for the whole scene
std::vector<aiMesh*> MeshArray; std::vector<aiMesh*> MeshArray;
for (size_t index = 0; index < pModel->m_Objects.size(); index++) for (size_t index = 0; index < pModel->m_Objects.size(); ++index ) {
{
createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray); createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
} }
// Create mesh pointer buffer for this scene // Create mesh pointer buffer for this scene
if (pScene->mNumMeshes > 0) if (pScene->mNumMeshes > 0) {
{
pScene->mMeshes = new aiMesh*[ MeshArray.size() ]; pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
for (size_t index =0; index < MeshArray.size(); index++) for (size_t index =0; index < MeshArray.size(); ++index ) {
{
pScene->mMeshes[ index ] = MeshArray[ index ]; pScene->mMeshes[ index ] = MeshArray[ index ];
} }
} }
@ -261,8 +255,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
appendChildToParentNode( pParent, pNode ); appendChildToParentNode( pParent, pNode );
} }
for ( size_t i=0; i< pObject->m_Meshes.size(); i++ ) for ( size_t i=0; i< pObject->m_Meshes.size(); ++i ) {
{
unsigned int meshId = pObject->m_Meshes[ i ]; unsigned int meshId = pObject->m_Meshes[ i ];
aiMesh *pMesh = createTopology( pModel, pObject, meshId ); aiMesh *pMesh = createTopology( pModel, pObject, meshId );
if( pMesh ) { if( pMesh ) {
@ -275,8 +268,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
} }
// Create all nodes from the sub-objects stored in the current object // Create all nodes from the sub-objects stored in the current object
if ( !pObject->m_SubObjects.empty() ) if ( !pObject->m_SubObjects.empty() ) {
{
size_t numChilds = pObject->m_SubObjects.size(); size_t numChilds = pObject->m_SubObjects.size();
pNode->mNumChildren = static_cast<unsigned int>( numChilds ); pNode->mNumChildren = static_cast<unsigned int>( numChilds );
pNode->mChildren = new aiNode*[ numChilds ]; pNode->mChildren = new aiNode*[ numChilds ];
@ -286,16 +278,14 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
// Set mesh instances into scene- and node-instances // Set mesh instances into scene- and node-instances
const size_t meshSizeDiff = MeshArray.size()- oldMeshSize; const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
if ( meshSizeDiff > 0 ) if ( meshSizeDiff > 0 ) {
{
pNode->mMeshes = new unsigned int[ meshSizeDiff ]; pNode->mMeshes = new unsigned int[ meshSizeDiff ];
pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff ); pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
size_t index = 0; size_t index = 0;
for (size_t i = oldMeshSize; i < MeshArray.size(); i++) for (size_t i = oldMeshSize; i < MeshArray.size(); ++i ) {
{
pNode->mMeshes[ index ] = pScene->mNumMeshes; pNode->mMeshes[ index ] = pScene->mNumMeshes;
pScene->mNumMeshes++; pScene->mNumMeshes++;
index++; ++index;
} }
} }

View File

@ -303,11 +303,12 @@ void ObjFileMtlImporter::createMaterial()
// New Material created // New Material created
m_pModel->m_pCurrentMaterial = new ObjFile::Material(); m_pModel->m_pCurrentMaterial = new ObjFile::Material();
m_pModel->m_pCurrentMaterial->MaterialName.Set( name ); m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
m_pModel->m_MaterialLib.push_back( name );
m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
if (m_pModel->m_pCurrentMesh) { if (m_pModel->m_pCurrentMesh) {
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
} }
m_pModel->m_MaterialLib.push_back( name );
m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
} else { } else {
// Use older material // Use older material
m_pModel->m_pCurrentMaterial = (*it).second; m_pModel->m_pCurrentMaterial = (*it).second;

View File

@ -612,13 +612,14 @@ void ObjFileParser::getMaterialLib() {
if ( '/' != *path.rbegin() ) { if ( '/' != *path.rbegin() ) {
path += '/'; path += '/';
} }
absName = path + strMatName; absName += path;
absName += strMatName;
} else { } else {
absName = strMatName; absName = strMatName;
} }
IOStream *pFile = m_pIO->Open( absName );
if (!pFile ) { IOStream *pFile = m_pIO->Open( absName );
if ( nullptr == pFile ) {
DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName); DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl"; std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName); DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName);

View File

@ -52,27 +52,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream> #include <sstream>
#include <cctype> #include <cctype>
namespace Assimp namespace Assimp {
{ namespace Ogre {
namespace Ogre
{
/// Returns a lower cased copy of @s. /// Returns a lower cased copy of @s.
static inline std::string ToLower(std::string s) static AI_FORCE_INLINE
std::string ToLower(std::string s)
{ {
std::transform(s.begin(), s.end(), s.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s; return s;
} }
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching. /// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) static AI_FORCE_INLINE
{ bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
if (s.empty() || suffix.empty()) if (s.empty() || suffix.empty()) {
{
return false; return false;
} } else if (s.length() < suffix.length()) {
else if (s.length() < suffix.length())
{
return false; return false;
} }
@ -82,48 +78,43 @@ static inline bool EndsWith(const std::string &s, const std::string &suffix, boo
size_t len = suffix.length(); size_t len = suffix.length();
std::string sSuffix = s.substr(s.length()-len, len); std::string sSuffix = s.substr(s.length()-len, len);
return (ASSIMP_stricmp(sSuffix, suffix) == 0); return (ASSIMP_stricmp(sSuffix, suffix) == 0);
} }
// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring // Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
/// Trim from start /// Trim from start
static inline std::string &TrimLeft(std::string &s, bool newlines = true) static AI_FORCE_INLINE
{ std::string &TrimLeft(std::string &s, bool newlines = true) {
if (!newlines) if (!newlines) {
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); })); s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
} } else {
else
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); })); s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
} }
return s; return s;
} }
/// Trim from end /// Trim from end
static inline std::string &TrimRight(std::string &s, bool newlines = true) static AI_FORCE_INLINE
{ std::string &TrimRight(std::string &s, bool newlines = true) {
if (!newlines) if (!newlines) {
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end()); s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
} } else {
else
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); })); s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
} }
return s; return s;
} }
/// Trim from both ends /// Trim from both ends
static inline std::string &Trim(std::string &s, bool newlines = true) static AI_FORCE_INLINE
{ std::string &Trim(std::string &s, bool newlines = true) {
return TrimLeft(TrimRight(s, newlines), newlines); return TrimLeft(TrimRight(s, newlines), newlines);
} }
/// Skips a line from current @ss position until a newline. Returns the skipped part. /// Skips a line from current @ss position until a newline. Returns the skipped part.
static inline std::string SkipLine(std::stringstream &ss) static AI_FORCE_INLINE
{ std::string SkipLine(std::stringstream &ss) {
std::string skipped; std::string skipped;
getline(ss, skipped); getline(ss, skipped);
return skipped; return skipped;
@ -131,8 +122,8 @@ static inline std::string SkipLine(std::stringstream &ss)
/// Skips a line and reads next element from @c ss to @c nextElement. /// Skips a line and reads next element from @c ss to @c nextElement.
/** @return Skipped line content until newline. */ /** @return Skipped line content until newline. */
static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) static AI_FORCE_INLINE
{ std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
std::string skipped = SkipLine(ss); std::string skipped = SkipLine(ss);
ss >> nextElement; ss >> nextElement;
return skipped; return skipped;

View File

@ -213,18 +213,18 @@ std::string &OgreXmlSerializer::SkipCurrentNode()
DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">"); DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
#endif #endif
for(;;) for(;;) {
{ if (!m_reader->read()) {
if (!m_reader->read())
{
m_currentNodeName = ""; m_currentNodeName = "";
return m_currentNodeName; return m_currentNodeName;
} }
if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END) if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
continue; continue;
else if (std::string(m_reader->getNodeName()) == m_currentNodeName) } else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
break; break;
} }
}
return NextNode(); return NextNode();
} }
@ -303,17 +303,16 @@ static const char *anZ = "z";
// Mesh // Mesh
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
{
OgreXmlSerializer serializer(reader); OgreXmlSerializer serializer(reader);
MeshXml *mesh = new MeshXml(); MeshXml *mesh = new MeshXml();
serializer.ReadMesh(mesh); serializer.ReadMesh(mesh);
return mesh; return mesh;
} }
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
{
if (NextNode() != nnMesh) { if (NextNode() != nnMesh) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>"); throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
} }
@ -835,7 +834,7 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
{ {
static const aiVector3D zeroVec(0.f, 0.f, 0.f); const aiVector3D zeroVec(0.f, 0.f, 0.f);
NextNode(); NextNode();
while(m_currentNodeName == nnKeyFrame) while(m_currentNodeName == nnKeyFrame)

View File

@ -221,12 +221,8 @@ static void propId2StdString( Property *prop, std::string &name, std::string &ke
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
OpenGEXImporter::VertexContainer::VertexContainer() OpenGEXImporter::VertexContainer::VertexContainer()
: m_numVerts( 0 ) : m_numColors( 0 )
, m_vertices( nullptr )
, m_numColors( 0 )
, m_colors( nullptr ) , m_colors( nullptr )
, m_numNormals( 0 )
, m_normals( nullptr )
, m_numUVComps() , m_numUVComps()
, m_textureCoords() { , m_textureCoords() {
// empty // empty
@ -234,9 +230,7 @@ OpenGEXImporter::VertexContainer::VertexContainer()
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
OpenGEXImporter::VertexContainer::~VertexContainer() { OpenGEXImporter::VertexContainer::~VertexContainer() {
delete[] m_vertices;
delete[] m_colors; delete[] m_colors;
delete[] m_normals;
for(auto &texcoords : m_textureCoords) { for(auto &texcoords : m_textureCoords) {
delete [] texcoords; delete [] texcoords;
@ -697,7 +691,8 @@ void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *
void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) { void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
m_currentMesh = new aiMesh; m_currentMesh = new aiMesh;
const size_t meshidx( m_meshCache.size() ); const size_t meshidx( m_meshCache.size() );
m_meshCache.push_back( m_currentMesh ); // ownership is transfered but a reference remains in m_currentMesh
m_meshCache.emplace_back( m_currentMesh );
Property *prop = node->getProperties(); Property *prop = node->getProperties();
if( nullptr != prop ) { if( nullptr != prop ) {
@ -736,17 +731,22 @@ enum MeshAttribute {
TexCoord TexCoord
}; };
static const std::string PosToken = "position";
static const std::string ColToken = "color";
static const std::string NormalToken = "normal";
static const std::string TexCoordToken = "texcoord";
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
static MeshAttribute getAttributeByName( const char *attribName ) { static MeshAttribute getAttributeByName( const char *attribName ) {
ai_assert( nullptr != attribName ); ai_assert( nullptr != attribName );
if ( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) { if ( 0 == strncmp( PosToken.c_str(), attribName, PosToken.size() ) ) {
return Position; return Position;
} else if ( 0 == strncmp( "color", attribName, strlen( "color" ) ) ) { } else if ( 0 == strncmp( ColToken.c_str(), attribName, ColToken.size() ) ) {
return Color; return Color;
} else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) { } else if( 0 == strncmp( NormalToken.c_str(), attribName, NormalToken.size() ) ) {
return Normal; return Normal;
} else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) { } else if( 0 == strncmp( TexCoordToken.c_str(), attribName, TexCoordToken.size() ) ) {
return TexCoord; return TexCoord;
} }
@ -857,17 +857,15 @@ void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene
const size_t numItems( countDataArrayListItems( vaList ) ); const size_t numItems( countDataArrayListItems( vaList ) );
if( Position == attribType ) { if( Position == attribType ) {
m_currentVertices.m_numVerts = numItems; m_currentVertices.m_vertices.resize( numItems );
m_currentVertices.m_vertices = new aiVector3D[ numItems ]; copyVectorArray( numItems, vaList, m_currentVertices.m_vertices.data() );
copyVectorArray( numItems, vaList, m_currentVertices.m_vertices );
} else if ( Color == attribType ) { } else if ( Color == attribType ) {
m_currentVertices.m_numColors = numItems; m_currentVertices.m_numColors = numItems;
m_currentVertices.m_colors = new aiColor4D[ numItems ]; m_currentVertices.m_colors = new aiColor4D[ numItems ];
copyColor4DArray( numItems, vaList, m_currentVertices.m_colors ); copyColor4DArray( numItems, vaList, m_currentVertices.m_colors );
} else if( Normal == attribType ) { } else if( Normal == attribType ) {
m_currentVertices.m_numNormals = numItems; m_currentVertices.m_normals.resize( numItems );
m_currentVertices.m_normals = new aiVector3D[ numItems ]; copyVectorArray( numItems, vaList, m_currentVertices.m_normals.data() );
copyVectorArray( numItems, vaList, m_currentVertices.m_normals );
} else if( TexCoord == attribType ) { } else if( TexCoord == attribType ) {
m_currentVertices.m_numUVComps[ 0 ] = numItems; m_currentVertices.m_numUVComps[ 0 ] = numItems;
m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ]; m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ];
@ -904,7 +902,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
hasColors = true; hasColors = true;
} }
bool hasNormalCoords( false ); bool hasNormalCoords( false );
if ( m_currentVertices.m_numNormals > 0 ) { if ( !m_currentVertices.m_normals.empty() ) {
m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ]; m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ];
hasNormalCoords = true; hasNormalCoords = true;
} }
@ -922,7 +920,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
Value *next( vaList->m_dataList ); Value *next( vaList->m_dataList );
for( size_t indices = 0; indices < current.mNumIndices; indices++ ) { for( size_t indices = 0; indices < current.mNumIndices; indices++ ) {
const int idx( next->getUnsignedInt32() ); const int idx( next->getUnsignedInt32() );
ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_numVerts ); ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_vertices.size() );
ai_assert( index < m_currentMesh->mNumVertices ); ai_assert( index < m_currentMesh->mNumVertices );
aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] ); aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] );
m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z ); m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z );
@ -1105,17 +1103,15 @@ void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene * /*pS
return; return;
} }
const float floatVal( val->getFloat() ); const float floatVal( val->getFloat() );
if ( prop->m_value != nullptr ) {
if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) { if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mHorizontalFOV = floatVal; m_currentCamera->mHorizontalFOV = floatVal;
} else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 3 ) ) { } else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 4 ) ) {
m_currentCamera->mClipPlaneNear = floatVal; m_currentCamera->mClipPlaneNear = floatVal;
} else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) { } else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mClipPlaneFar = floatVal; m_currentCamera->mClipPlaneFar = floatVal;
} }
} }
} }
}
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
void OpenGEXImporter::handleAttenNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) { void OpenGEXImporter::handleAttenNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
@ -1145,7 +1141,9 @@ void OpenGEXImporter::copyMeshes( aiScene *pScene ) {
pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size()); pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
std::copy( m_meshCache.begin(), m_meshCache.end(), pScene->mMeshes ); for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
pScene->mMeshes[i] = m_meshCache[i].release();
}
} }
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------

View File

@ -144,12 +144,10 @@ protected:
private: private:
struct VertexContainer { struct VertexContainer {
size_t m_numVerts; std::vector<aiVector3D> m_vertices;
aiVector3D *m_vertices;
size_t m_numColors; size_t m_numColors;
aiColor4D *m_colors; aiColor4D *m_colors;
size_t m_numNormals; std::vector<aiVector3D> m_normals;
aiVector3D *m_normals;
size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
@ -185,7 +183,7 @@ private:
typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap; typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap;
NodeChildMap m_nodeChildMap; NodeChildMap m_nodeChildMap;
std::vector<aiMesh*> m_meshCache; std::vector<std::unique_ptr<aiMesh> > m_meshCache;
typedef std::map<std::string, size_t> ReferenceMap; typedef std::map<std::string, size_t> ReferenceMap;
std::map<std::string, size_t> m_mesh2refMap; std::map<std::string, size_t> m_mesh2refMap;
std::map<std::string, size_t> m_material2refMap; std::map<std::string, size_t> m_material2refMap;
@ -194,7 +192,7 @@ private:
MetricInfo m_metrics[ MetricInfo::Max ]; MetricInfo m_metrics[ MetricInfo::Max ];
aiNode *m_currentNode; aiNode *m_currentNode;
VertexContainer m_currentVertices; VertexContainer m_currentVertices;
aiMesh *m_currentMesh; aiMesh *m_currentMesh; // not owned, target is owned by m_meshCache
aiMaterial *m_currentMaterial; aiMaterial *m_currentMaterial;
aiLight *m_currentLight; aiLight *m_currentLight;
aiCamera *m_currentCamera; aiCamera *m_currentCamera;

View File

@ -148,6 +148,17 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina
<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
<< aiGetVersionRevision() << ")" << endl; << aiGetVersionRevision() << ")" << endl;
// Look through materials for a diffuse texture, and add it if found
for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i )
{
const aiMaterial* const mat = pScene->mMaterials[i];
aiString s;
if ( AI_SUCCESS == mat->Get( AI_MATKEY_TEXTURE_DIFFUSE( 0 ), s ) )
{
mOutput << "comment TextureFile " << s.data << endl;
}
}
// TODO: probably want to check here rather than just assume something // TODO: probably want to check here rather than just assume something
// definitely not good to always write float even if we might have double precision // definitely not good to always write float even if we might have double precision

View File

@ -106,24 +106,24 @@ PLYImporter::~PLYImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
if (extension == "ply") if ( extension == "ply" ) {
return true; return true;
else if (!extension.length() || checkSig) } else if (!extension.length() || checkSig) {
{ if ( !pIOHandler ) {
if (!pIOHandler)return true; return true;
const char* tokens[] = { "ply" }; }
static const char* tokens[] = { "ply" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }
return false; return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiImporterDesc* PLYImporter::GetInfo() const const aiImporterDesc* PLYImporter::GetInfo() const {
{
return &desc; return &desc;
} }
@ -149,9 +149,7 @@ static bool isBigEndian(const char* szMe) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void PLYImporter::InternReadFile(const std::string& pFile, void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
aiScene* pScene, IOSystem* pIOHandler)
{
static const std::string mode = "rb"; static const std::string mode = "rb";
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode)); std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
if (!fileStream.get()) { if (!fileStream.get()) {
@ -159,7 +157,7 @@ void PLYImporter::InternReadFile(const std::string& pFile,
} }
// Get the file-size // Get the file-size
size_t fileSize = fileStream->FileSize(); const size_t fileSize( fileStream->FileSize() );
if ( 0 == fileSize ) { if ( 0 == fileSize ) {
throw DeadlyImportError("File " + pFile + " is empty."); throw DeadlyImportError("File " + pFile + " is empty.");
} }
@ -174,8 +172,7 @@ void PLYImporter::InternReadFile(const std::string& pFile,
if ((headerCheck.size() < 3) || if ((headerCheck.size() < 3) ||
(headerCheck[0] != 'P' && headerCheck[0] != 'p') || (headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
(headerCheck[1] != 'L' && headerCheck[1] != 'l') || (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) (headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) {
{
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there"); throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
} }
@ -194,10 +191,8 @@ void PLYImporter::InternReadFile(const std::string& pFile,
if (TokenMatch(szMe, "format", 6)) { if (TokenMatch(szMe, "format", 6)) {
if (TokenMatch(szMe, "ascii", 5)) { if (TokenMatch(szMe, "ascii", 5)) {
SkipLine(szMe, (const char**)&szMe); SkipLine(szMe, (const char**)&szMe);
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
{ if (mGeneratedMesh != NULL) {
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -205,17 +200,13 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)"); throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
} }
} } else if (!::strncmp(szMe, "binary_", 7)) {
else if (!::strncmp(szMe, "binary_", 7))
{
szMe += 7; szMe += 7;
const bool bIsBE(isBigEndian(szMe)); const bool bIsBE(isBigEndian(szMe));
// skip the line, parse the rest of the header and build the DOM // skip the line, parse the rest of the header and build the DOM
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
{ if (mGeneratedMesh != NULL) {
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -223,11 +214,8 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)"); throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
} }
} } else {
else if (mGeneratedMesh != NULL) {
{
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -235,12 +223,9 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unknown file format"); throw DeadlyImportError("Invalid .ply file: Unknown file format");
} }
} } else {
else
{
AI_DEBUG_INVALIDATE_PTR(this->mBuffer); AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
if (mGeneratedMesh != NULL) if (mGeneratedMesh != NULL) {
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -252,41 +237,15 @@ void PLYImporter::InternReadFile(const std::string& pFile,
//free the file buffer //free the file buffer
streamedBuffer.close(); streamedBuffer.close();
if (mGeneratedMesh == NULL) if (mGeneratedMesh == NULL) {
{
throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data "); throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
} }
// if no face list is existing we assume that the vertex // if no face list is existing we assume that the vertex
// list is containing a list of points // list is containing a list of points
bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false; bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
if (pointsOnly) if (pointsOnly) {
{ mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
if (mGeneratedMesh->mNumVertices < 3)
{
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh);
mGeneratedMesh = nullptr;
}
streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Not enough "
"vertices to build a proper face list. ");
}
const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
mGeneratedMesh->mNumFaces = iNum;
mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
for (unsigned int i = 0; i < iNum; ++i)
{
mGeneratedMesh->mFaces[i].mNumIndices = 3;
mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1;
mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2;
}
} }
// now load a list of all materials // now load a list of all materials
@ -521,9 +480,7 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a color component to [0...1] // Convert a color component to [0...1]
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
PLY::EDataType eType)
{
switch (eType) switch (eType)
{ {
case EDT_Float: case EDT_Float:

View File

@ -57,7 +57,6 @@ struct aiMesh;
namespace Assimp { namespace Assimp {
using namespace PLY; using namespace PLY;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1043,71 +1043,91 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
switch (eType) switch (eType)
{ {
case EDT_UInt: case EDT_UInt:
out->iUInt = (uint32_t)*((uint32_t*)pCur); {
pCur += 4; uint32_t t;
memcpy(&t, pCur, sizeof(uint32_t));
pCur += sizeof(uint32_t);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); if (p_bBE)ByteSwap::Swap(&t);
out->iUInt = t;
break; break;
}
case EDT_UShort: case EDT_UShort:
{ {
uint16_t i = *((uint16_t*)pCur); uint16_t t;
memcpy(&t, pCur, sizeof(uint16_t));
pCur += sizeof(uint16_t);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap(&i); if (p_bBE)ByteSwap::Swap(&t);
out->iUInt = (uint32_t)i; out->iUInt = t;
pCur += 2;
break; break;
} }
case EDT_UChar: case EDT_UChar:
{ {
out->iUInt = (uint32_t)(*((uint8_t*)pCur)); uint8_t t;
pCur++; memcpy(&t, pCur, sizeof(uint8_t));
pCur += sizeof(uint8_t);
out->iUInt = t;
break; break;
} }
case EDT_Int: case EDT_Int:
out->iInt = *((int32_t*)pCur); {
pCur += 4; int32_t t;
memcpy(&t, pCur, sizeof(int32_t));
pCur += sizeof(int32_t);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap(&out->iInt); if (p_bBE)ByteSwap::Swap(&t);
out->iInt = t;
break; break;
}
case EDT_Short: case EDT_Short:
{ {
int16_t i = *((int16_t*)pCur); int16_t t;
memcpy(&t, pCur, sizeof(int16_t));
pCur += sizeof(int16_t);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap(&i); if (p_bBE)ByteSwap::Swap(&t);
out->iInt = (int32_t)i; out->iInt = t;
pCur += 2;
break; break;
} }
case EDT_Char: case EDT_Char:
out->iInt = (int32_t)*((int8_t*)pCur); {
pCur++; int8_t t;
memcpy(&t, pCur, sizeof(int8_t));
pCur += sizeof(int8_t);
out->iInt = t;
break; break;
}
case EDT_Float: case EDT_Float:
{ {
out->fFloat = *((float*)pCur); float t;
memcpy(&t, pCur, sizeof(float));
pCur += sizeof(float);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); if (p_bBE)ByteSwap::Swap(&t);
pCur += 4; out->fFloat = t;
break; break;
} }
case EDT_Double: case EDT_Double:
{ {
out->fDouble = *((double*)pCur); double t;
memcpy(&t, pCur, sizeof(double));
pCur += sizeof(double);
// Swap endianness // Swap endianness
if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); if (p_bBE)ByteSwap::Swap(&t);
pCur += 8; out->fDouble = t;
break; break;
} }
default: default:

View File

@ -39,12 +39,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file Defines the helper data structures for importing PLY files */ /** @file Defines the helper data structures for importing PLY files */
#pragma once
#ifndef AI_PLYFILEHELPER_H_INC #ifndef AI_PLYFILEHELPER_H_INC
#define AI_PLYFILEHELPER_H_INC #define AI_PLYFILEHELPER_H_INC
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/IOStreamBuffer.h> #include <assimp/IOStreamBuffer.h>
#include <vector> #include <vector>
@ -58,8 +57,7 @@ class PLYImporter;
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
// http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
// http://www.okino.com/conv/exp_ply.htm // http://www.okino.com/conv/exp_ply.htm
namespace PLY namespace PLY {
{
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
/* /*
@ -78,8 +76,7 @@ int8
int16 int16
uint8 ... forms are also used uint8 ... forms are also used
*/ */
enum EDataType enum EDataType {
{
EDT_Char = 0x0u, EDT_Char = 0x0u,
EDT_UChar, EDT_UChar,
EDT_Short, EDT_Short,
@ -98,8 +95,7 @@ enum EDataType
* *
* Semantics define the usage of a property, e.g. x coordinate * Semantics define the usage of a property, e.g. x coordinate
*/ */
enum ESemantic enum ESemantic {
{
//! vertex position x coordinate //! vertex position x coordinate
EST_XCoord = 0x0u, EST_XCoord = 0x0u,
//! vertex position x coordinate //! vertex position x coordinate
@ -182,15 +178,14 @@ enum ESemantic
* *
* Semantics define the usage of an element, e.g. vertex or material * Semantics define the usage of an element, e.g. vertex or material
*/ */
enum EElementSemantic enum EElementSemantic {
{
//! The element is a vertex //! The element is a vertex
EEST_Vertex = 0x0u, EEST_Vertex = 0x0u,
//! The element is a face description (index table) //! The element is a face description (index table)
EEST_Face, EEST_Face,
//! The element is a tristrip description (index table) //! The element is a triangle-strip description (index table)
EEST_TriStrip, EEST_TriStrip,
//! The element is an edge description (ignored) //! The element is an edge description (ignored)
@ -211,17 +206,16 @@ enum EElementSemantic
* *
* This can e.g. be a part of the vertex declaration * This can e.g. be a part of the vertex declaration
*/ */
class Property class Property {
{
public: public:
//! Default constructor //! Default constructor
Property() Property()
: eType (EDT_Int), : eType (EDT_Int)
Semantic(), , Semantic()
bIsList(false), , bIsList(false)
eFirstType(EDT_UChar) , eFirstType(EDT_UChar) {
{} // empty
}
//! Data type of the property //! Data type of the property
EDataType eType; EDataType eType;
@ -260,15 +254,14 @@ public:
* This can e.g. be the vertex declaration. Elements contain a * This can e.g. be the vertex declaration. Elements contain a
* well-defined number of properties. * well-defined number of properties.
*/ */
class Element class Element {
{
public: public:
//! Default constructor //! Default constructor
Element() Element()
: eSemantic (EEST_INVALID) : eSemantic (EEST_INVALID)
, NumOccur(0) , NumOccur(0) {
{} // empty
}
//! List of properties assigned to the element //! List of properties assigned to the element
//! std::vector to support operator[] //! std::vector to support operator[]

View File

@ -125,6 +125,9 @@ corresponding preprocessor flag to selectively disable steps.
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
# include "DeboneProcess.h" # include "DeboneProcess.h"
#endif #endif
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
# include "ScaleProcess.h"
#endif
namespace Assimp { namespace Assimp {
@ -136,7 +139,7 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
// of sequence it is executed. Steps that are added here are not // of sequence it is executed. Steps that are added here are not
// validated - as RegisterPPStep() does - all dependencies must be given. // validated - as RegisterPPStep() does - all dependencies must be given.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
out.reserve(30); out.reserve(31);
#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS) #if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
out.push_back( new MakeLeftHandedProcess()); out.push_back( new MakeLeftHandedProcess());
#endif #endif
@ -197,7 +200,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) #if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
out.push_back( new GenFaceNormalsProcess()); out.push_back( new GenFaceNormalsProcess());
#endif #endif
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
out.push_back( new ScaleProcess());
#endif
// ......................................................................... // .........................................................................
// DON'T change the order of these five .. // DON'T change the order of these five ..
// XXX this is actually a design weakness that dates back to the time // XXX this is actually a design weakness that dates back to the time

View File

@ -651,7 +651,8 @@ void PretransformVertices::Execute( aiScene* pScene)
// generate mesh nodes // generate mesh nodes
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
{ {
aiNode* pcNode = *nodes = new aiNode(); aiNode* pcNode = new aiNode();
*nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
pcNode->mName = pScene->mMeshes[i]->mName; pcNode->mName = pScene->mMeshes[i]->mName;
@ -663,7 +664,8 @@ void PretransformVertices::Execute( aiScene* pScene)
// generate light nodes // generate light nodes
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
{ {
aiNode* pcNode = *nodes = new aiNode(); aiNode* pcNode = new aiNode();
*nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i); pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i);
pScene->mLights[i]->mName = pcNode->mName; pScene->mLights[i]->mName = pcNode->mName;
@ -671,7 +673,8 @@ void PretransformVertices::Execute( aiScene* pScene)
// generate camera nodes // generate camera nodes
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
{ {
aiNode* pcNode = *nodes = new aiNode(); aiNode* pcNode = new aiNode();
*nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i); pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i);
pScene->mCameras[i]->mName = pcNode->mName; pScene->mCameras[i]->mName = pcNode->mName;

View File

@ -172,12 +172,16 @@ void STLExporter :: WriteMeshBinary(const aiMesh* m)
} }
nor.Normalize(); nor.Normalize();
} }
ai_real nx = nor.x, ny = nor.y, nz = nor.z; // STL binary files use 4-byte floats. This may possibly cause loss of precision
// for clients using 8-byte doubles
float nx = (float) nor.x;
float ny = (float) nor.y;
float nz = (float) nor.z;
AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz); AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz);
mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4); mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4);
for(unsigned int a = 0; a < f.mNumIndices; ++a) { for(unsigned int a = 0; a < f.mNumIndices; ++a) {
const aiVector3D& v = m->mVertices[f.mIndices[a]]; const aiVector3D& v = m->mVertices[f.mIndices[a]];
ai_real vx = v.x, vy = v.y, vz = v.z; float vx = (float) v.x, vy = (float) v.y, vz = (float) v.z;
AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz); AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz);
mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4); mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4);
} }

View File

@ -449,26 +449,43 @@ bool STLImporter::LoadBinaryFile()
aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
typedef aiVector3t<float> aiVector3F;
aiVector3F* theVec;
aiVector3F theVec3F;
for ( unsigned int i = 0; i < pMesh->mNumFaces; ++i ) { for ( unsigned int i = 0; i < pMesh->mNumFaces; ++i ) {
// NOTE: Blender sometimes writes empty normals ... this is not // NOTE: Blender sometimes writes empty normals ... this is not
// our fault ... the RemoveInvalidData helper step should fix that // our fault ... the RemoveInvalidData helper step should fix that
::memcpy( vn, sz, sizeof( aiVector3D ) );
sz += sizeof(aiVector3D); // There's one normal for the face in the STL; use it three times
// for vertex normals
theVec = (aiVector3F*) sz;
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
vn->x = theVec3F.x; vn->y = theVec3F.y; vn->z = theVec3F.z;
*(vn+1) = *vn; *(vn+1) = *vn;
*(vn+2) = *vn; *(vn+2) = *vn;
++theVec;
vn += 3; vn += 3;
::memcpy( vp, sz, sizeof( aiVector3D ) ); // vertex 1
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
++theVec;
++vp; ++vp;
sz += sizeof(aiVector3D);
::memcpy( vp, sz, sizeof( aiVector3D ) ); // vertex 2
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
++theVec;
++vp; ++vp;
sz += sizeof(aiVector3D);
::memcpy( vp, sz, sizeof( aiVector3D ) ); // vertex 3
::memcpy( &theVec3F, theVec, sizeof(aiVector3F) );
vp->x = theVec3F.x; vp->y = theVec3F.y; vp->z = theVec3F.z;
++theVec;
++vp; ++vp;
sz += sizeof(aiVector3D);
sz = (const unsigned char*) theVec;
uint16_t color = *((uint16_t*)sz); uint16_t color = *((uint16_t*)sz);
sz += 2; sz += 2;

View File

@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
#include "ScaleProcess.h" #include "ScaleProcess.h"
#include <assimp/scene.h> #include <assimp/scene.h>
@ -86,13 +88,6 @@ void ScaleProcess::Execute( aiScene* pScene ) {
void ScaleProcess::traverseNodes( aiNode *node ) { void ScaleProcess::traverseNodes( aiNode *node ) {
applyScaling( node ); applyScaling( node );
/*for ( unsigned int i = 0; i < node->mNumChildren; ++i ) {
aiNode *currentNode = currentNode->mChildren[ i ];
if ( nullptr != currentNode ) {
traverseNodes( currentNode );
}
}*/
} }
void ScaleProcess::applyScaling( aiNode *currentNode ) { void ScaleProcess::applyScaling( aiNode *currentNode ) {
@ -104,3 +99,5 @@ void ScaleProcess::applyScaling( aiNode *currentNode ) {
} }
} // Namespace Assimp } // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS

View File

@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/SceneCombiner.h> #include <assimp/SceneCombiner.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/metadata.h>
#include <assimp/Hash.h> #include <assimp/Hash.h>
#include "time.h" #include "time.h"
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -806,8 +807,9 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mNormals) { if ((*it)->mNormals) {
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D)); ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
} else {
DefaultLogger::get()->warn( "JoinMeshes: Normals expected but input mesh contains no normals" );
} }
else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
pv2 += (*it)->mNumVertices; pv2 += (*it)->mNumVertices;
} }
} }
@ -821,8 +823,9 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
if ((*it)->mTangents) { if ((*it)->mTangents) {
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D)); ::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D)); ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
} else {
DefaultLogger::get()->warn( "JoinMeshes: Tangents expected but input mesh contains no tangents" );
} }
else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
pv2 += (*it)->mNumVertices; pv2 += (*it)->mNumVertices;
pv2b += (*it)->mNumVertices; pv2b += (*it)->mNumVertices;
} }
@ -834,11 +837,11 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices]; pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mTextureCoords[n]) { if ((*it)->mTextureCoords[n]) {
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D)); ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
} else {
DefaultLogger::get()->warn( "JoinMeshes: UVs expected but input mesh contains no UVs" );
} }
else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
pv2 += (*it)->mNumVertices; pv2 += (*it)->mNumVertices;
} }
++n; ++n;
@ -848,11 +851,11 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
while ((**begin).HasVertexColors(n)) { while ((**begin).HasVertexColors(n)) {
aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices]; aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mColors[n]) { if ((*it)->mColors[n]) {
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D)); ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
} else {
DefaultLogger::get()->warn( "JoinMeshes: VCs expected but input mesh contains no VCs" );
} }
else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
pv2 += (*it)->mNumVertices; pv2 += (*it)->mNumVertices;
} }
++n; ++n;
@ -1001,7 +1004,12 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
*_dest = new aiScene(); *_dest = new aiScene();
} }
aiScene* dest = *_dest; aiScene* dest = *_dest;
ai_assert(dest); ai_assert(nullptr != dest);
// copy metadata
if ( nullptr != src->mMetaData ) {
dest->mMetaData = new aiMetadata( *src->mMetaData );
}
// copy animations // copy animations
dest->mNumAnimations = src->mNumAnimations; dest->mNumAnimations = src->mNumAnimations;
@ -1279,6 +1287,7 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
break; break;
default: default:
ai_assert(false); ai_assert(false);
break;
} }
} }
} }

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

@ -294,7 +294,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition,
index++; index++;
// Now start iterating from there until the first position lays outside of the distance range. // Now start iterating from there until the first position lays outside of the distance range.
// Add all positions inside the distance range within the tolerance to the result aray // Add all positions inside the distance range within the tolerance to the result array
std::vector<Entry>::const_iterator it = mPositions.begin() + index; std::vector<Entry>::const_iterator it = mPositions.begin() + index;
while( ToBinary(it->mDistance) < maxDistBinary) while( ToBinary(it->mDistance) < maxDistBinary)
{ {

View File

@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "VertexTriangleAdjacency.h" #include "VertexTriangleAdjacency.h"
#include <assimp/mesh.h> #include <assimp/mesh.h>
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -60,8 +59,8 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
// compute the number of referenced vertices if it wasn't specified by the caller // compute the number of referenced vertices if it wasn't specified by the caller
const aiFace* const pcFaceEnd = pcFaces + iNumFaces; const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
if (!iNumVertices) { if (!iNumVertices) {
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
ai_assert( nullptr != pcFace );
ai_assert(3 == pcFace->mNumIndices); ai_assert(3 == pcFace->mNumIndices);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
@ -69,19 +68,18 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
} }
} }
this->iNumVertices = iNumVertices; mNumVertices = iNumVertices;
unsigned int* pi; unsigned int* pi;
// allocate storage // allocate storage
if (bComputeNumTriangles) { if (bComputeNumTriangles) {
pi = mLiveTriangles = new unsigned int[iNumVertices+1]; pi = mLiveTriangles = new unsigned int[iNumVertices+1];
memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1)); ::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
mOffsetTable = new unsigned int[iNumVertices+2]+1; mOffsetTable = new unsigned int[iNumVertices+2]+1;
} } else {
else {
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1; pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1)); ::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
mLiveTriangles = NULL; // important, otherwise the d'tor would crash mLiveTriangles = NULL; // important, otherwise the d'tor would crash
} }
@ -90,8 +88,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
*piEnd++ = 0u; *piEnd++ = 0u;
// first pass: compute the number of faces referencing each vertex // first pass: compute the number of faces referencing each vertex
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
{
pi[pcFace->mIndices[0]]++; pi[pcFace->mIndices[0]]++;
pi[pcFace->mIndices[1]]++; pi[pcFace->mIndices[1]]++;
pi[pcFace->mIndices[2]]++; pi[pcFace->mIndices[2]]++;

View File

@ -60,10 +60,8 @@ namespace Assimp {
* @note Although it is called #VertexTriangleAdjacency, the current version does also * @note Although it is called #VertexTriangleAdjacency, the current version does also
* support arbitrary polygons. */ * support arbitrary polygons. */
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
class ASSIMP_API VertexTriangleAdjacency class ASSIMP_API VertexTriangleAdjacency {
{
public: public:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** @brief Construction from an existing index buffer /** @brief Construction from an existing index buffer
* @param pcFaces Index buffer * @param pcFaces Index buffer
@ -77,39 +75,30 @@ public:
unsigned int iNumVertices = 0, unsigned int iNumVertices = 0,
bool bComputeNumTriangles = true); bool bComputeNumTriangles = true);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** @brief Destructor */ /** @brief Destructor */
~VertexTriangleAdjacency(); ~VertexTriangleAdjacency();
public:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** @brief Get all triangles adjacent to a vertex /** @brief Get all triangles adjacent to a vertex
* @param iVertIndex Index of the vertex * @param iVertIndex Index of the vertex
* @return A pointer to the adjacency list. */ * @return A pointer to the adjacency list. */
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
{ ai_assert(iVertIndex < mNumVertices);
ai_assert(iVertIndex < iNumVertices);
return &mAdjacencyTable[ mOffsetTable[iVertIndex]]; return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** @brief Get the number of triangles that are referenced by /** @brief Get the number of triangles that are referenced by
* a vertex. This function returns a reference that can be modified * a vertex. This function returns a reference that can be modified
* @param iVertIndex Index of the vertex * @param iVertIndex Index of the vertex
* @return Number of referenced triangles */ * @return Number of referenced triangles */
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) {
{ ai_assert( iVertIndex < mNumVertices );
ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles); ai_assert( nullptr != mLiveTriangles );
return mLiveTriangles[iVertIndex]; return mLiveTriangles[iVertIndex];
} }
public:
//! Offset table //! Offset table
unsigned int* mOffsetTable; unsigned int* mOffsetTable;
@ -120,9 +109,9 @@ public:
unsigned int* mLiveTriangles; unsigned int* mLiveTriangles;
//! Debug: Number of referenced vertices //! Debug: Number of referenced vertices
unsigned int iNumVertices; unsigned int mNumVertices;
}; };
}
} //! ns Assimp
#endif // !! AI_VTADJACENCY_H_INC #endif // !! AI_VTADJACENCY_H_INC

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,
@ -44,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the XFile importer class * @brief Implementation of the XFile importer class
*/ */
#ifndef ASSIMP_BUILD_NO_X_IMPORTER #ifndef ASSIMP_BUILD_NO_X_IMPORTER
#include "XFileImporter.h" #include "XFileImporter.h"
@ -79,17 +76,19 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
XFileImporter::XFileImporter() XFileImporter::XFileImporter()
{} : mBuffer() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
XFileImporter::~XFileImporter() XFileImporter::~XFileImporter() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if(extension == "x") { if(extension == "x") {
return true; return true;
@ -104,23 +103,24 @@ bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get file extension list // Get file extension list
const aiImporterDesc* XFileImporter::GetInfo () const const aiImporterDesc* XFileImporter::GetInfo () const {
{
return &desc; return &desc;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
{
// read file into memory // read file into memory
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile)); std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL) if ( file.get() == NULL ) {
throw DeadlyImportError( "Failed to open file " + pFile + "." ); throw DeadlyImportError( "Failed to open file " + pFile + "." );
}
static const size_t MinSize = 16;
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
if( fileSize < 16) if ( fileSize < MinSize ) {
throw DeadlyImportError( "XFile is too small." ); throw DeadlyImportError( "XFile is too small." );
}
// in the hope that binary files will never start with a BOM ... // in the hope that binary files will never start with a BOM ...
mBuffer.resize( fileSize + 1); mBuffer.resize( fileSize + 1);
@ -134,9 +134,10 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I
CreateDataRepresentationFromImport( pScene, parser.GetImportedData()); CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
// if nothing came from it, report it as error // if nothing came from it, report it as error
if( !pScene->mRootNode) if ( !pScene->mRootNode ) {
throw DeadlyImportError( "XFile is ill-formatted - no content imported." ); throw DeadlyImportError( "XFile is ill-formatted - no content imported." );
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs the return data structure out of the imported data. // Constructs the return data structure out of the imported data.
@ -146,17 +147,15 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
ConvertMaterials( pScene, pData->mGlobalMaterials); ConvertMaterials( pScene, pData->mGlobalMaterials);
// copy nodes, extracting meshes and materials on the way // copy nodes, extracting meshes and materials on the way
pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode); pScene->mRootNode = CreateNodes( pScene, nullptr, pData->mRootNode);
// extract animations // extract animations
CreateAnimations( pScene, pData); CreateAnimations( pScene, pData);
// read the global meshes that were stored outside of any node // read the global meshes that were stored outside of any node
if( pData->mGlobalMeshes.size() > 0) if( !pData->mGlobalMeshes.empty() ) {
{
// create a root node to hold them if there isn't any, yet // create a root node to hold them if there isn't any, yet
if( pScene->mRootNode == NULL) if( pScene->mRootNode == nullptr ) {
{
pScene->mRootNode = new aiNode; pScene->mRootNode = new aiNode;
pScene->mRootNode->mName.Set( "$dummy_node"); pScene->mRootNode->mName.Set( "$dummy_node");
} }
@ -180,8 +179,7 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
flipper.Execute(pScene); flipper.Execute(pScene);
// finally: create a dummy material if not material was imported // finally: create a dummy material if not material was imported
if( pScene->mNumMaterials == 0) if( pScene->mNumMaterials == 0) {
{
pScene->mNumMaterials = 1; pScene->mNumMaterials = 1;
// create the Material // create the Material
aiMaterial* mat = new aiMaterial; aiMaterial* mat = new aiMaterial;
@ -205,10 +203,10 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Recursively creates scene nodes from the imported hierarchy. // Recursively creates scene nodes from the imported hierarchy.
aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) {
{ if ( !pNode ) {
if( !pNode) return nullptr;
return NULL; }
// create node // create node
aiNode* node = new aiNode; aiNode* node = new aiNode;
@ -222,30 +220,28 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
CreateMeshes( pScene, node, pNode->mMeshes); CreateMeshes( pScene, node, pNode->mMeshes);
// handle childs // handle childs
if( pNode->mChildren.size() > 0) if( !pNode->mChildren.empty() ) {
{
node->mNumChildren = (unsigned int)pNode->mChildren.size(); node->mNumChildren = (unsigned int)pNode->mChildren.size();
node->mChildren = new aiNode* [node->mNumChildren]; node->mChildren = new aiNode* [node->mNumChildren];
for( unsigned int a = 0; a < pNode->mChildren.size(); a++) for ( unsigned int a = 0; a < pNode->mChildren.size(); ++a ) {
node->mChildren[ a ] = CreateNodes( pScene, node, pNode->mChildren[ a ] ); node->mChildren[ a ] = CreateNodes( pScene, node, pNode->mChildren[ a ] );
} }
}
return node; return node;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates the meshes for the given node. // Creates the meshes for the given node.
void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) {
{
if (pMeshes.empty()) { if (pMeshes.empty()) {
return; return;
} }
// create a mesh for each mesh-material combination in the source node // create a mesh for each mesh-material combination in the source node
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
for( unsigned int a = 0; a < pMeshes.size(); a++) for( unsigned int a = 0; a < pMeshes.size(); ++a ) {
{
XFile::Mesh* sourceMesh = pMeshes[a]; XFile::Mesh* sourceMesh = pMeshes[a];
if ( nullptr == sourceMesh ) { if ( nullptr == sourceMesh ) {
continue; continue;
@ -255,35 +251,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
ConvertMaterials( pScene, sourceMesh->mMaterials); ConvertMaterials( pScene, sourceMesh->mMaterials);
unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u); unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
for( unsigned int b = 0; b < numMaterials; b++) for( unsigned int b = 0; b < numMaterials; ++b ) {
{
// collect the faces belonging to this material // collect the faces belonging to this material
std::vector<unsigned int> faces; std::vector<unsigned int> faces;
unsigned int numVertices = 0; unsigned int numVertices = 0;
if( sourceMesh->mFaceMaterials.size() > 0) if( !sourceMesh->mFaceMaterials.empty() ) {
{
// if there is a per-face material defined, select the faces with the corresponding material // if there is a per-face material defined, select the faces with the corresponding material
for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++) for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c ) {
{ if( sourceMesh->mFaceMaterials[c] == b) {
if( sourceMesh->mFaceMaterials[c] == b)
{
faces.push_back( c); faces.push_back( c);
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
} }
} }
} else } else {
{
// if there is no per-face material, place everything into one mesh // if there is no per-face material, place everything into one mesh
for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++) for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c ) {
{
faces.push_back( c); faces.push_back( c);
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
} }
} }
// no faces/vertices using this material? strange... // no faces/vertices using this material? strange...
if( numVertices == 0) if ( numVertices == 0 ) {
continue; continue;
}
// create a submesh using this material // create a submesh using this material
aiMesh* mesh = new aiMesh; aiMesh* mesh = new aiMesh;
@ -291,11 +282,9 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// find the material in the scene's material list. Either own material // find the material in the scene's material list. Either own material
// or referenced material, it should already have a valid index // or referenced material, it should already have a valid index
if( sourceMesh->mFaceMaterials.size() > 0) if( !sourceMesh->mFaceMaterials.empty() ) {
{
mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex); mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
} else } else {
{
mesh->mMaterialIndex = 0; mesh->mMaterialIndex = 0;
} }
@ -310,28 +299,28 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
mesh->mName.Set(sourceMesh->mName); mesh->mName.Set(sourceMesh->mName);
// normals? // normals?
if( sourceMesh->mNormals.size() > 0) if ( sourceMesh->mNormals.size() > 0 ) {
mesh->mNormals = new aiVector3D[ numVertices ]; mesh->mNormals = new aiVector3D[ numVertices ];
}
// texture coords // texture coords
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
{ if ( !sourceMesh->mTexCoords[ c ].empty() ) {
if( sourceMesh->mTexCoords[c].size() > 0)
mesh->mTextureCoords[ c ] = new aiVector3D[ numVertices ]; mesh->mTextureCoords[ c ] = new aiVector3D[ numVertices ];
} }
}
// vertex colors // vertex colors
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
{ if ( !sourceMesh->mColors[ c ].empty() ) {
if( sourceMesh->mColors[c].size() > 0)
mesh->mColors[ c ] = new aiColor4D[ numVertices ]; mesh->mColors[ c ] = new aiColor4D[ numVertices ];
} }
}
// now collect the vertex data of all data streams present in the imported mesh // now collect the vertex data of all data streams present in the imported mesh
unsigned int newIndex = 0; unsigned int newIndex( 0 );
std::vector<unsigned int> orgPoints; // from which original point each new vertex stems std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
orgPoints.resize( numVertices, 0); orgPoints.resize( numVertices, 0);
for( unsigned int c = 0; c < faces.size(); c++) for( unsigned int c = 0; c < faces.size(); ++c ) {
{
unsigned int f = faces[c]; // index of the source face unsigned int f = faces[c]; // index of the source face
const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
@ -341,30 +330,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
df.mIndices = new unsigned int[ df.mNumIndices]; df.mIndices = new unsigned int[ df.mNumIndices];
// collect vertex data for indices of this face // collect vertex data for indices of this face
for( unsigned int d = 0; d < df.mNumIndices; d++) for( unsigned int d = 0; d < df.mNumIndices; ++d ) {
{
df.mIndices[d] = newIndex; df.mIndices[d] = newIndex;
orgPoints[newIndex] = pf.mIndices[d]; orgPoints[newIndex] = pf.mIndices[d];
// Position // Position
mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]]; mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
// Normal, if present // Normal, if present
if( mesh->HasNormals()) if ( mesh->HasNormals() ) {
mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ sourceMesh->mNormFaces[ f ].mIndices[ d ] ]; mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ sourceMesh->mNormFaces[ f ].mIndices[ d ] ];
}
// texture coord sets // texture coord sets
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e ) {
{ if( mesh->HasTextureCoords( e)) {
if( mesh->HasTextureCoords( e))
{
aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]]; aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f); mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
} }
} }
// vertex color sets // vertex color sets
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++) for ( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e ) {
if( mesh->HasVertexColors( e)) if ( mesh->HasVertexColors( e ) ) {
mesh->mColors[ e ][ newIndex ] = sourceMesh->mColors[ e ][ pf.mIndices[ d ] ]; mesh->mColors[ e ][ newIndex ] = sourceMesh->mColors[ e ][ pf.mIndices[ d ] ];
}
}
newIndex++; newIndex++;
} }
@ -376,28 +365,29 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// convert all bones of the source mesh which influence vertices in this newly created mesh // convert all bones of the source mesh which influence vertices in this newly created mesh
const std::vector<XFile::Bone>& bones = sourceMesh->mBones; const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
std::vector<aiBone*> newBones; std::vector<aiBone*> newBones;
for( unsigned int c = 0; c < bones.size(); c++) for( unsigned int c = 0; c < bones.size(); ++c ) {
{
const XFile::Bone& obone = bones[c]; const XFile::Bone& obone = bones[c];
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0); std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0);
for( unsigned int d = 0; d < obone.mWeights.size(); d++) for ( unsigned int d = 0; d < obone.mWeights.size(); ++d ) {
oldWeights[ obone.mWeights[ d ].mVertex ] = obone.mWeights[ d ].mWeight; oldWeights[ obone.mWeights[ d ].mVertex ] = obone.mWeights[ d ].mWeight;
}
// collect all vertex weights that influence a vertex in the new mesh // collect all vertex weights that influence a vertex in the new mesh
std::vector<aiVertexWeight> newWeights; std::vector<aiVertexWeight> newWeights;
newWeights.reserve( numVertices); newWeights.reserve( numVertices);
for( unsigned int d = 0; d < orgPoints.size(); d++) for( unsigned int d = 0; d < orgPoints.size(); ++d ) {
{
// does the new vertex stem from an old vertex which was influenced by this bone? // does the new vertex stem from an old vertex which was influenced by this bone?
ai_real w = oldWeights[orgPoints[d]]; ai_real w = oldWeights[orgPoints[d]];
if( w > 0.0) if ( w > 0.0 ) {
newWeights.push_back( aiVertexWeight( d, w ) ); newWeights.push_back( aiVertexWeight( d, w ) );
} }
}
// if the bone has no weights in the newly created mesh, ignore it // if the bone has no weights in the newly created mesh, ignore it
if( newWeights.size() == 0) if ( newWeights.empty() ) {
continue; continue;
}
// create // create
aiBone* nbone = new aiBone; aiBone* nbone = new aiBone;
@ -407,14 +397,14 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
nbone->mOffsetMatrix = obone.mOffsetMatrix; nbone->mOffsetMatrix = obone.mOffsetMatrix;
nbone->mNumWeights = (unsigned int)newWeights.size(); nbone->mNumWeights = (unsigned int)newWeights.size();
nbone->mWeights = new aiVertexWeight[nbone->mNumWeights]; nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
for( unsigned int d = 0; d < newWeights.size(); d++) for ( unsigned int d = 0; d < newWeights.size(); ++d ) {
nbone->mWeights[ d ] = newWeights[ d ]; nbone->mWeights[ d ] = newWeights[ d ];
} }
}
// store the bones in the mesh // store the bones in the mesh
mesh->mNumBones = (unsigned int)newBones.size(); mesh->mNumBones = (unsigned int)newBones.size();
if( newBones.size() > 0) if( !newBones.empty()) {
{
mesh->mBones = new aiBone*[mesh->mNumBones]; mesh->mBones = new aiBone*[mesh->mNumBones];
std::copy( newBones.begin(), newBones.end(), mesh->mBones); std::copy( newBones.begin(), newBones.end(), mesh->mBones);
} }
@ -424,8 +414,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// reallocate scene mesh array to be large enough // reallocate scene mesh array to be large enough
aiMesh** prevArray = pScene->mMeshes; aiMesh** prevArray = pScene->mMeshes;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
if( prevArray) if( prevArray) {
{
memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*)); memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
delete [] prevArray; delete [] prevArray;
} }
@ -435,8 +424,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
// store all meshes in the mesh library of the scene and store their indices in the node // store all meshes in the mesh library of the scene and store their indices in the node
for( unsigned int a = 0; a < meshes.size(); a++) for( unsigned int a = 0; a < meshes.size(); a++) {
{
pScene->mMeshes[pScene->mNumMeshes] = meshes[a]; pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
pNode->mMeshes[a] = pScene->mNumMeshes; pNode->mMeshes[a] = pScene->mNumMeshes;
pScene->mNumMeshes++; pScene->mNumMeshes++;
@ -445,16 +433,15 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts the animations from the given imported data and creates them in the scene. // Converts the animations from the given imported data and creates them in the scene.
void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) {
{
std::vector<aiAnimation*> newAnims; std::vector<aiAnimation*> newAnims;
for( unsigned int a = 0; a < pData->mAnims.size(); a++) for( unsigned int a = 0; a < pData->mAnims.size(); ++a ) {
{
const XFile::Animation* anim = pData->mAnims[a]; const XFile::Animation* anim = pData->mAnims[a];
// some exporters mock me with empty animation tags. // some exporters mock me with empty animation tags.
if( anim->mAnims.size() == 0) if ( anim->mAnims.empty() ) {
continue; continue;
}
// create a new animation to hold the data // create a new animation to hold the data
aiAnimation* nanim = new aiAnimation; aiAnimation* nanim = new aiAnimation;
@ -466,15 +453,14 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
nanim->mNumChannels = (unsigned int)anim->mAnims.size(); nanim->mNumChannels = (unsigned int)anim->mAnims.size();
nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels]; nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
for( unsigned int b = 0; b < anim->mAnims.size(); b++) for( unsigned int b = 0; b < anim->mAnims.size(); ++b ) {
{
const XFile::AnimBone* bone = anim->mAnims[b]; const XFile::AnimBone* bone = anim->mAnims[b];
aiNodeAnim* nbone = new aiNodeAnim; aiNodeAnim* nbone = new aiNodeAnim;
nbone->mNodeName.Set( bone->mBoneName); nbone->mNodeName.Set( bone->mBoneName);
nanim->mChannels[b] = nbone; nanim->mChannels[b] = nbone;
// keyframes are given as combined transformation matrix keys // keyframes are given as combined transformation matrix keys
if( bone->mTrafoKeys.size() > 0) if( !bone->mTrafoKeys.empty() )
{ {
nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size(); nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
@ -483,8 +469,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size(); nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys]; nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++) for( unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
{
// deconstruct each matrix into separate position, rotation and scaling // deconstruct each matrix into separate position, rotation and scaling
double time = bone->mTrafoKeys[c].mTime; double time = bone->mTrafoKeys[c].mTime;
aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix; aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
@ -516,13 +501,11 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
// longest lasting key sequence determines duration // longest lasting key sequence determines duration
nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime); nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
} else } else {
{
// separate key sequences for position, rotation, scaling // separate key sequences for position, rotation, scaling
nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size(); nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++) for( unsigned int c = 0; c < nbone->mNumPositionKeys; ++c ) {
{
aiVector3D pos = bone->mPosKeys[c].mValue; aiVector3D pos = bone->mPosKeys[c].mValue;
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime; nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
@ -532,8 +515,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
// rotation // rotation
nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size(); nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys]; nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++) for( unsigned int c = 0; c < nbone->mNumRotationKeys; ++c ) {
{
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix(); aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime; nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
@ -573,43 +555,38 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials) void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
{ {
// count the non-referrer materials in the array // count the non-referrer materials in the array
unsigned int numNewMaterials = 0; unsigned int numNewMaterials( 0 );
for( unsigned int a = 0; a < pMaterials.size(); a++) for ( unsigned int a = 0; a < pMaterials.size(); ++a ) {
if( !pMaterials[a].mIsReference) if ( !pMaterials[ a ].mIsReference ) {
numNewMaterials++; ++numNewMaterials;
}
}
// resize the scene's material list to offer enough space for the new materials // resize the scene's material list to offer enough space for the new materials
if( numNewMaterials > 0 ) if( numNewMaterials > 0 ) {
{
aiMaterial** prevMats = pScene->mMaterials; aiMaterial** prevMats = pScene->mMaterials;
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials]; pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
if( prevMats) if( nullptr != prevMats) {
{ ::memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
delete [] prevMats; delete [] prevMats;
} }
} }
// convert all the materials given in the array // convert all the materials given in the array
for( unsigned int a = 0; a < pMaterials.size(); a++) for( unsigned int a = 0; a < pMaterials.size(); ++a ) {
{
XFile::Material& oldMat = pMaterials[a]; XFile::Material& oldMat = pMaterials[a];
if( oldMat.mIsReference) if( oldMat.mIsReference) {
{
// find the material it refers to by name, and store its index // find the material it refers to by name, and store its index
for( size_t a = 0; a < pScene->mNumMaterials; ++a ) for( size_t a = 0; a < pScene->mNumMaterials; ++a ) {
{
aiString name; aiString name;
pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name); pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
{
oldMat.sceneIndex = a; oldMat.sceneIndex = a;
break; break;
} }
} }
if( oldMat.sceneIndex == SIZE_MAX ) if( oldMat.sceneIndex == SIZE_MAX ) {
{
DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" ); DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" );
oldMat.sceneIndex = 0; oldMat.sceneIndex = 0;
} }
@ -622,7 +599,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
name.Set( oldMat.mName); name.Set( oldMat.mName);
mat->AddProperty( &name, AI_MATKEY_NAME); mat->AddProperty( &name, AI_MATKEY_NAME);
// Shading model: hardcoded to PHONG, there is no such information in an XFile // Shading model: hard-coded to PHONG, there is no such information in an XFile
// FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
// for some models in the SDK (e.g. good old tiny.x) // for some models in the SDK (e.g. good old tiny.x)
int shadeMode = (int)oldMat.mSpecularExponent == 0.0f int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
@ -639,36 +616,33 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
// texture, if there is one // texture, if there is one
if (1 == oldMat.mTextures.size()) if (1 == oldMat.mTextures.size() ) {
{
const XFile::TexEntry& otex = oldMat.mTextures.back(); const XFile::TexEntry& otex = oldMat.mTextures.back();
if (otex.mName.length()) if (otex.mName.length()) {
{
// if there is only one texture assume it contains the diffuse color // if there is only one texture assume it contains the diffuse color
aiString tex( otex.mName); aiString tex( otex.mName);
if( otex.mIsNormalMap) if ( otex.mIsNormalMap ) {
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) ); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) );
else } else {
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) ); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
} }
} }
else } else {
{
// Otherwise ... try to search for typical strings in the // Otherwise ... try to search for typical strings in the
// texture's file name like 'bump' or 'diffuse' // texture's file name like 'bump' or 'diffuse'
unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0; unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
for( unsigned int b = 0; b < oldMat.mTextures.size(); b++) for( unsigned int b = 0; b < oldMat.mTextures.size(); ++b ) {
{
const XFile::TexEntry& otex = oldMat.mTextures[b]; const XFile::TexEntry& otex = oldMat.mTextures[b];
std::string sz = otex.mName; std::string sz = otex.mName;
if (!sz.length())continue; if ( !sz.length() ) {
continue;
}
// find the file name // find the file name
//const size_t iLen = sz.length();
std::string::size_type s = sz.find_last_of("\\/"); std::string::size_type s = sz.find_last_of("\\/");
if (std::string::npos == s) if ( std::string::npos == s ) {
s = 0; s = 0;
}
// cut off the file extension // cut off the file extension
std::string::size_type sExt = sz.find_last_of('.'); std::string::size_type sExt = sz.find_last_of('.');
@ -677,36 +651,27 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
} }
// convert to lower case for easier comparison // convert to lower case for easier comparison
for( unsigned int c = 0; c < sz.length(); c++) for ( unsigned int c = 0; c < sz.length(); ++c ) {
if( isalpha( sz[c])) if ( isalpha( sz[ c ] ) ) {
sz[ c ] = tolower( sz[ c ] ); sz[ c ] = tolower( sz[ c ] );
}
}
// Place texture filename property under the corresponding name // Place texture filename property under the corresponding name
aiString tex( oldMat.mTextures[b].mName); aiString tex( oldMat.mTextures[b].mName);
// bump map // bump map
if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
} else } else if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) {
if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
} else } else if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) {
if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
} else } else if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) {
if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
} else } else if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) {
if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
} else } else {
{
// Assume it is a diffuse texture // Assume it is a diffuse texture
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
} }

View File

@ -87,59 +87,60 @@ static void dummy_free (void* /*opaque*/, void* address) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. Creates a data structure out of the XFile given in the memory block. // Constructor. Creates a data structure out of the XFile given in the memory block.
XFileParser::XFileParser( const std::vector<char>& pBuffer) XFileParser::XFileParser( const std::vector<char>& pBuffer)
{ : mMajorVersion( 0 )
mMajorVersion = mMinorVersion = 0; , mMinorVersion( 0 )
mIsBinaryFormat = false; , mIsBinaryFormat( false )
mBinaryNumCount = 0; , mBinaryNumCount( 0 )
P = End = NULL; , mP( nullptr )
mLineNumber = 0; , mEnd( nullptr )
mScene = NULL; , mLineNumber( 0 )
, mScene( nullptr ) {
// vector to store uncompressed file for INFLATE'd X files // vector to store uncompressed file for INFLATE'd X files
std::vector<char> uncompressed; std::vector<char> uncompressed;
// set up memory pointers // set up memory pointers
P = &pBuffer.front(); mP = &pBuffer.front();
End = P + pBuffer.size() - 1; mEnd = mP + pBuffer.size() - 1;
// check header // check header
if( strncmp( P, "xof ", 4) != 0) if ( 0 != strncmp( mP, "xof ", 4 ) ) {
throw DeadlyImportError( "Header mismatch, file is not an XFile." ); throw DeadlyImportError( "Header mismatch, file is not an XFile." );
}
// read version. It comes in a four byte format such as "0302" // read version. It comes in a four byte format such as "0302"
mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48); mMajorVersion = (unsigned int)(mP[4] - 48) * 10 + (unsigned int)(mP[5] - 48);
mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48); mMinorVersion = (unsigned int)(mP[6] - 48) * 10 + (unsigned int)(mP[7] - 48);
bool compressed = false; bool compressed = false;
// txt - pure ASCII text format // txt - pure ASCII text format
if( strncmp( P + 8, "txt ", 4) == 0) if( strncmp( mP + 8, "txt ", 4) == 0)
mIsBinaryFormat = false; mIsBinaryFormat = false;
// bin - Binary format // bin - Binary format
else if( strncmp( P + 8, "bin ", 4) == 0) else if( strncmp( mP + 8, "bin ", 4) == 0)
mIsBinaryFormat = true; mIsBinaryFormat = true;
// tzip - Inflate compressed text format // tzip - Inflate compressed text format
else if( strncmp( P + 8, "tzip", 4) == 0) else if( strncmp( mP + 8, "tzip", 4) == 0)
{ {
mIsBinaryFormat = false; mIsBinaryFormat = false;
compressed = true; compressed = true;
} }
// bzip - Inflate compressed binary format // bzip - Inflate compressed binary format
else if( strncmp( P + 8, "bzip", 4) == 0) else if( strncmp( mP + 8, "bzip", 4) == 0)
{ {
mIsBinaryFormat = true; mIsBinaryFormat = true;
compressed = true; compressed = true;
} }
else ThrowException( format() << "Unsupported xfile format '" << else ThrowException( format() << "Unsupported xfile format '" <<
P[8] << P[9] << P[10] << P[11] << "'"); mP[8] << mP[9] << mP[10] << mP[11] << "'");
// float size // float size
mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000 mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000
+ (unsigned int)(P[13] - 48) * 100 + (unsigned int)(mP[13] - 48) * 100
+ (unsigned int)(P[14] - 48) * 10 + (unsigned int)(mP[14] - 48) * 10
+ (unsigned int)(P[15] - 48); + (unsigned int)(mP[15] - 48);
if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64) if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." ); ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." );
@ -147,7 +148,7 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// The x format specifies size in bits, but we work in bytes // The x format specifies size in bits, but we work in bytes
mBinaryFloatSize /= 8; mBinaryFloatSize /= 8;
P += 16; mP += 16;
// If this is a compressed X file, apply the inflate algorithm to it // If this is a compressed X file, apply the inflate algorithm to it
if (compressed) if (compressed)
@ -186,13 +187,13 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
::inflateInit2(&stream, -MAX_WBITS); ::inflateInit2(&stream, -MAX_WBITS);
// skip unknown data (checksum, flags?) // skip unknown data (checksum, flags?)
P += 6; mP += 6;
// First find out how much storage we'll need. Count sections. // First find out how much storage we'll need. Count sections.
const char* P1 = P; const char* P1 = mP;
unsigned int est_out = 0; unsigned int est_out = 0;
while (P1 + 3 < End) while (P1 + 3 < mEnd)
{ {
// read next offset // read next offset
uint16_t ofs = *((uint16_t*)P1); uint16_t ofs = *((uint16_t*)P1);
@ -216,18 +217,18 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// Allocate storage and terminating zero and do the actual uncompressing // Allocate storage and terminating zero and do the actual uncompressing
uncompressed.resize(est_out + 1); uncompressed.resize(est_out + 1);
char* out = &uncompressed.front(); char* out = &uncompressed.front();
while (P + 3 < End) while (mP + 3 < mEnd)
{ {
uint16_t ofs = *((uint16_t*)P); uint16_t ofs = *((uint16_t*)mP);
AI_SWAP2(ofs); AI_SWAP2(ofs);
P += 4; mP += 4;
if (P + ofs > End + 2) { if (mP + ofs > mEnd + 2) {
throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
} }
// push data to the stream // push data to the stream
stream.next_in = (Bytef*)P; stream.next_in = (Bytef*)mP;
stream.avail_in = ofs; stream.avail_in = ofs;
stream.next_out = (Bytef*)out; stream.next_out = (Bytef*)out;
stream.avail_out = MSZIP_BLOCK; stream.avail_out = MSZIP_BLOCK;
@ -242,15 +243,15 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// and advance to the next offset // and advance to the next offset
out += MSZIP_BLOCK - stream.avail_out; out += MSZIP_BLOCK - stream.avail_out;
P += ofs; mP += ofs;
} }
// terminate zlib // terminate zlib
::inflateEnd(&stream); ::inflateEnd(&stream);
// ok, update pointers to point to the uncompressed file data // ok, update pointers to point to the uncompressed file data
P = &uncompressed[0]; mP = &uncompressed[0];
End = out; mEnd = out;
// FIXME: we don't need the compressed data anymore, could release // FIXME: we don't need the compressed data anymore, could release
// it already for better memory usage. Consider breaking const-co. // it already for better memory usage. Consider breaking const-co.
@ -465,12 +466,11 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
// read position faces // read position faces
unsigned int numPosFaces = ReadInt(); unsigned int numPosFaces = ReadInt();
pMesh->mPosFaces.resize( numPosFaces); pMesh->mPosFaces.resize( numPosFaces);
for( unsigned int a = 0; a < numPosFaces; a++) for( unsigned int a = 0; a < numPosFaces; ++a) {
{
// read indices // read indices
unsigned int numIndices = ReadInt(); unsigned int numIndices = ReadInt();
Face& face = pMesh->mPosFaces[a]; Face& face = pMesh->mPosFaces[a];
for (unsigned int b = 0; b < numIndices; b++) { for (unsigned int b = 0; b < numIndices; ++b) {
face.mIndices.push_back( ReadInt() ); face.mIndices.push_back( ReadInt() );
} }
TestForSeparator(); TestForSeparator();
@ -478,11 +478,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
// here, other data objects may follow // here, other data objects may follow
bool running = true; bool running = true;
while ( running ) while ( running ) {
{
std::string objectName = GetNextToken(); std::string objectName = GetNextToken();
if( objectName.size() == 0) if( objectName.empty() )
ThrowException( "Unexpected end of file while parsing mesh structure"); ThrowException( "Unexpected end of file while parsing mesh structure");
else else
if( objectName == "}") if( objectName == "}")
@ -517,8 +516,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) {
{ if ( nullptr == pMesh ) {
return;
}
readHeadOfDataObject(); readHeadOfDataObject();
std::string transformNodeName; std::string transformNodeName;
@ -647,8 +648,8 @@ void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
if( !mIsBinaryFormat) if( !mIsBinaryFormat)
{ {
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( *P == ';' || *P == ',') if( *mP == ';' || *mP == ',')
P++; mP++;
} }
} }
@ -678,8 +679,8 @@ void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
// commented out version check, as version 03.03 exported from blender also has 2 semicolons // commented out version check, as version 03.03 exported from blender also has 2 semicolons
if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2) if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
{ {
if(P < End && *P == ';') if(mP < mEnd && *mP == ';')
++P; ++mP;
} }
// if there was only a single material index, replicate it on all faces // if there was only a single material index, replicate it on all faces
@ -1029,12 +1030,12 @@ void XFileParser::TestForSeparator()
return; return;
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if( mP >= mEnd)
return; return;
// test and skip // test and skip
if( *P == ';' || *P == ',') if( *mP == ';' || *mP == ',')
P++; mP++;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1046,62 +1047,73 @@ void XFileParser::readHeadOfDataObject( std::string* poName)
if( poName) if( poName)
*poName = nameOrBrace; *poName = nameOrBrace;
if( GetNextToken() != "{") if ( GetNextToken() != "{" ) {
delete mScene;
ThrowException( "Opening brace expected." ); ThrowException( "Opening brace expected." );
} }
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string XFileParser::GetNextToken() std::string XFileParser::GetNextToken() {
{
std::string s; std::string s;
// process binary-formatted file // process binary-formatted file
if( mIsBinaryFormat) if( mIsBinaryFormat) {
{
// in binary mode it will only return NAME and STRING token // in binary mode it will only return NAME and STRING token
// and (correctly) skip over other tokens. // and (correctly) skip over other tokens.
if ( mEnd - mP < 2 ) {
if( End - P < 2) return s; return s;
}
unsigned int tok = ReadBinWord(); unsigned int tok = ReadBinWord();
unsigned int len; unsigned int len;
// standalone tokens // standalone tokens
switch( tok) switch( tok ) {
{ case 1: {
case 1:
// name token // name token
if( End - P < 4) return s; if ( mEnd - mP < 4 ) {
len = ReadBinDWord();
if( End - P < int(len)) return s;
s = std::string(P, len);
P += len;
return s; return s;
}
len = ReadBinDWord();
const int bounds = int( mEnd - mP );
const int iLen = int( len );
if ( iLen < 0 ) {
return s;
}
if ( bounds < iLen ) {
return s;
}
s = std::string( mP, len );
mP += len;
}
return s;
case 2: case 2:
// string token // string token
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
if( End - P < int(len)) return s; if( mEnd - mP < int(len)) return s;
s = std::string(P, len); s = std::string(mP, len);
P += (len + 2); mP += (len + 2);
return s; return s;
case 3: case 3:
// integer token // integer token
P += 4; mP += 4;
return "<integer>"; return "<integer>";
case 5: case 5:
// GUID token // GUID token
P += 16; mP += 16;
return "<guid>"; return "<guid>";
case 6: case 6:
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
P += (len * 4); mP += (len * 4);
return "<int_list>"; return "<int_list>";
case 7: case 7:
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
P += (len * mBinaryFloatSize); mP += (len * mBinaryFloatSize);
return "<flt_list>"; return "<flt_list>";
case 0x0a: case 0x0a:
return "{"; return "{";
@ -1159,19 +1171,19 @@ std::string XFileParser::GetNextToken()
else else
{ {
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if( mP >= mEnd)
return s; return s;
while( (P < End) && !isspace( (unsigned char) *P)) while( (mP < mEnd) && !isspace( (unsigned char) *mP))
{ {
// either keep token delimiters when already holding a token, or return if first valid char // either keep token delimiters when already holding a token, or return if first valid char
if( *P == ';' || *P == '}' || *P == '{' || *P == ',') if( *mP == ';' || *mP == '}' || *mP == '{' || *mP == ',')
{ {
if( !s.size()) if( !s.size())
s.append( P++, 1); s.append( mP++, 1);
break; // stop for delimiter break; // stop for delimiter
} }
s.append( P++, 1); s.append( mP++, 1);
} }
} }
return s; return s;
@ -1186,18 +1198,18 @@ void XFileParser::FindNextNoneWhiteSpace()
bool running = true; bool running = true;
while( running ) while( running )
{ {
while( P < End && isspace( (unsigned char) *P)) while( mP < mEnd && isspace( (unsigned char) *mP))
{ {
if( *P == '\n') if( *mP == '\n')
mLineNumber++; mLineNumber++;
++P; ++mP;
} }
if( P >= End) if( mP >= mEnd)
return; return;
// check if this is a comment // check if this is a comment
if( (P[0] == '/' && P[1] == '/') || P[0] == '#') if( (mP[0] == '/' && mP[1] == '/') || mP[0] == '#')
ReadUntilEndOfLine(); ReadUntilEndOfLine();
else else
break; break;
@ -1214,22 +1226,30 @@ void XFileParser::GetNextTokenAsString( std::string& poString)
} }
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if ( mP >= mEnd ) {
delete mScene;
ThrowException( "Unexpected end of file while parsing string" ); ThrowException( "Unexpected end of file while parsing string" );
}
if( *P != '"') if ( *mP != '"' ) {
delete mScene;
ThrowException( "Expected quotation mark." ); ThrowException( "Expected quotation mark." );
++P; }
++mP;
while( P < End && *P != '"') while( mP < mEnd && *mP != '"')
poString.append( P++, 1); poString.append( mP++, 1);
if( P >= End-1) if ( mP >= mEnd - 1 ) {
delete mScene;
ThrowException( "Unexpected end of file while parsing string" ); ThrowException( "Unexpected end of file while parsing string" );
}
if( P[1] != ';' || P[0] != '"') if ( mP[ 1 ] != ';' || mP[ 0 ] != '"' ) {
delete mScene;
ThrowException( "Expected quotation mark and semicolon at the end of a string." ); ThrowException( "Expected quotation mark and semicolon at the end of a string." );
P+=2; }
mP+=2;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1238,35 +1258,35 @@ void XFileParser::ReadUntilEndOfLine()
if( mIsBinaryFormat) if( mIsBinaryFormat)
return; return;
while( P < End) while( mP < mEnd)
{ {
if( *P == '\n' || *P == '\r') if( *mP == '\n' || *mP == '\r')
{ {
++P; mLineNumber++; ++mP; mLineNumber++;
return; return;
} }
++P; ++mP;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned short XFileParser::ReadBinWord() unsigned short XFileParser::ReadBinWord()
{ {
ai_assert(End - P >= 2); ai_assert(mEnd - mP >= 2);
const unsigned char* q = (const unsigned char*) P; const unsigned char* q = (const unsigned char*) mP;
unsigned short tmp = q[0] | (q[1] << 8); unsigned short tmp = q[0] | (q[1] << 8);
P += 2; mP += 2;
return tmp; return tmp;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int XFileParser::ReadBinDWord() unsigned int XFileParser::ReadBinDWord() {
{ ai_assert(mEnd - mP >= 4);
ai_assert(End - P >= 4);
const unsigned char* q = (const unsigned char*) P; const unsigned char* q = (const unsigned char*) mP;
unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24); unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
P += 4; mP += 4;
return tmp; return tmp;
} }
@ -1275,20 +1295,20 @@ unsigned int XFileParser::ReadInt()
{ {
if( mIsBinaryFormat) if( mIsBinaryFormat)
{ {
if( mBinaryNumCount == 0 && End - P >= 2) if( mBinaryNumCount == 0 && mEnd - mP >= 2)
{ {
unsigned short tmp = ReadBinWord(); // 0x06 or 0x03 unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
if( tmp == 0x06 && End - P >= 4) // array of ints follows if( tmp == 0x06 && mEnd - mP >= 4) // array of ints follows
mBinaryNumCount = ReadBinDWord(); mBinaryNumCount = ReadBinDWord();
else // single int follows else // single int follows
mBinaryNumCount = 1; mBinaryNumCount = 1;
} }
--mBinaryNumCount; --mBinaryNumCount;
if ( End - P >= 4) { if ( mEnd - mP >= 4) {
return ReadBinDWord(); return ReadBinDWord();
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} else } else
@ -1299,24 +1319,24 @@ unsigned int XFileParser::ReadInt()
// check preceding minus sign // check preceding minus sign
bool isNegative = false; bool isNegative = false;
if( *P == '-') if( *mP == '-')
{ {
isNegative = true; isNegative = true;
P++; mP++;
} }
// at least one digit expected // at least one digit expected
if( !isdigit( *P)) if( !isdigit( *mP))
ThrowException( "Number expected."); ThrowException( "Number expected.");
// read digits // read digits
unsigned int number = 0; unsigned int number = 0;
while( P < End) while( mP < mEnd)
{ {
if( !isdigit( *P)) if( !isdigit( *mP))
break; break;
number = number * 10 + (*P - 48); number = number * 10 + (*mP - 48);
P++; mP++;
} }
CheckForSeparator(); CheckForSeparator();
@ -1329,34 +1349,35 @@ ai_real XFileParser::ReadFloat()
{ {
if( mIsBinaryFormat) if( mIsBinaryFormat)
{ {
if( mBinaryNumCount == 0 && End - P >= 2) if( mBinaryNumCount == 0 && mEnd - mP >= 2)
{ {
unsigned short tmp = ReadBinWord(); // 0x07 or 0x42 unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
if( tmp == 0x07 && End - P >= 4) // array of floats following if( tmp == 0x07 && mEnd - mP >= 4) // array of floats following
mBinaryNumCount = ReadBinDWord(); mBinaryNumCount = ReadBinDWord();
else // single float following else // single float following
mBinaryNumCount = 1; mBinaryNumCount = 1;
} }
--mBinaryNumCount; --mBinaryNumCount;
if( mBinaryFloatSize == 8) if( mBinaryFloatSize == 8) {
{ if( mEnd - mP >= 8) {
if( End - P >= 8) { double res;
ai_real result = (ai_real) (*(double*) P); ::memcpy( &res, mP, 8 );
P += 8; mP += 8;
const ai_real result( static_cast<ai_real>( res ) );
return result; return result;
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} else } else {
{ if( mEnd - mP >= 4) {
if( End - P >= 4) { ai_real result;
ai_real result = *(ai_real*) P; ::memcpy( &result, mP, 4 );
P += 4; mP += 4;
return result; return result;
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} }
@ -1367,21 +1388,21 @@ ai_real XFileParser::ReadFloat()
// check for various special strings to allow reading files from faulty exporters // check for various special strings to allow reading files from faulty exporters
// I mean you, Blender! // I mean you, Blender!
// Reading is safe because of the terminating zero // Reading is safe because of the terminating zero
if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0) if( strncmp( mP, "-1.#IND00", 9) == 0 || strncmp( mP, "1.#IND00", 8) == 0)
{ {
P += 9; mP += 9;
CheckForSeparator(); CheckForSeparator();
return 0.0; return 0.0;
} else } else
if( strncmp( P, "1.#QNAN0", 8) == 0) if( strncmp( mP, "1.#QNAN0", 8) == 0)
{ {
P += 8; mP += 8;
CheckForSeparator(); CheckForSeparator();
return 0.0; return 0.0;
} }
ai_real result = 0.0; ai_real result = 0.0;
P = fast_atoreal_move<ai_real>( P, result); mP = fast_atoreal_move<ai_real>( mP, result);
CheckForSeparator(); CheckForSeparator();
@ -1438,14 +1459,13 @@ aiColor3D XFileParser::ReadRGB()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text. // Throws an exception with a line number and the given text.
AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) {
{ if ( mIsBinaryFormat ) {
if( mIsBinaryFormat)
throw DeadlyImportError( pText ); throw DeadlyImportError( pText );
else } else {
throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText ); throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText );
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Filters the imported hierarchy for some degenerated cases that some exporters produce. // Filters the imported hierarchy for some degenerated cases that some exporters produce.

View File

@ -49,10 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h> #include <assimp/types.h>
namespace Assimp namespace Assimp {
{ namespace XFile {
namespace XFile
{
struct Node; struct Node;
struct Mesh; struct Mesh;
struct Scene; struct Scene;
@ -61,21 +59,20 @@ namespace Assimp
struct AnimBone; struct AnimBone;
} }
/** The XFileParser reads a XFile either in text or binary form and builds a temporary /**
* @brief The XFileParser reads a XFile either in text or binary form and builds a temporary
* data structure out of it. * data structure out of it.
*/ */
class XFileParser class XFileParser {
{
public: public:
/** Constructor. Creates a data structure out of the XFile given in the memory block. /// Constructor. Creates a data structure out of the XFile given in the memory block.
* @param pBuffer Null-terminated memory buffer containing the XFile /// @param pBuffer Null-terminated memory buffer containing the XFile
*/
explicit XFileParser( const std::vector<char>& pBuffer); explicit XFileParser( const std::vector<char>& pBuffer);
/** Destructor. Destroys all imported data along with it */ /// Destructor. Destroys all imported data along with it
~XFileParser(); ~XFileParser();
/** Returns the temporary representation of the imported data */ /// Returns the temporary representation of the imported data.
XFile::Scene* GetImportedData() const { return mScene; } XFile::Scene* GetImportedData() const { return mScene; }
protected: protected:
@ -101,7 +98,7 @@ protected:
//! places pointer to next begin of a token, and ignores comments //! places pointer to next begin of a token, and ignores comments
void FindNextNoneWhiteSpace(); void FindNextNoneWhiteSpace();
//! returns next parseable token. Returns empty string if no token there //! returns next valid token. Returns empty string if no token there
std::string GetNextToken(); std::string GetNextToken();
//! reads header of data object including the opening brace. //! reads header of data object including the opening brace.
@ -138,7 +135,8 @@ protected:
/** Throws an exception with a line number and the given text. */ /** Throws an exception with a line number and the given text. */
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
/** Filters the imported hierarchy for some degenerated cases that some exporters produce. /**
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.
* @param pData The sub-hierarchy to filter * @param pData The sub-hierarchy to filter
*/ */
void FilterHierarchy( XFile::Node* pNode); void FilterHierarchy( XFile::Node* pNode);
@ -147,18 +145,13 @@ protected:
unsigned int mMajorVersion, mMinorVersion; ///< version numbers unsigned int mMajorVersion, mMinorVersion; ///< version numbers
bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8 unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
// counter for number arrays in binary format unsigned int mBinaryNumCount; /// < counter for number arrays in binary format
unsigned int mBinaryNumCount; const char* mP;
const char* mEnd;
const char* P; unsigned int mLineNumber; ///< Line number when reading in text format
const char* End; XFile::Scene* mScene; ///< Imported data
/// Line number when reading in text format
unsigned int mLineNumber;
/// Imported data
XFile::Scene* mScene;
}; };
} } //! ns Assimp
#endif // AI_XFILEPARSER_H_INC #endif // AI_XFILEPARSER_H_INC

View File

@ -72,17 +72,6 @@ using namespace irr::io;
#endif #endif
// scopeguard for a malloc'ed buffer
struct free_it
{
free_it(void* free) : free(free) {}
~free_it() {
::free(this->free);
}
void* free;
};
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
template<> const char* LogFunctions<XGLImporter>::Prefix() template<> const char* LogFunctions<XGLImporter>::Prefix()
{ {
@ -155,8 +144,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
Bytef* dest = NULL; std::vector<Bytef> uncompressed;
free_it free_it_really(dest);
#endif #endif
m_scene = pScene; m_scene = pScene;
@ -192,6 +180,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
size_t total = 0l; size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024 #define MYBLOCK 1024
Bytef block[MYBLOCK]; Bytef block[MYBLOCK];
@ -206,8 +195,8 @@ void XGLImporter::InternReadFile( const std::string& pFile,
} }
const size_t have = MYBLOCK - zstream.avail_out; const size_t have = MYBLOCK - zstream.avail_out;
total += have; total += have;
dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); uncompressed.resize(total);
memcpy(dest + total - have,block,have); memcpy(uncompressed.data() + total - have,block,have);
} }
while (ret != Z_STREAM_END); while (ret != Z_STREAM_END);
@ -215,7 +204,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
inflateEnd(&zstream); inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
#endif #endif
} }

View File

@ -166,32 +166,7 @@ namespace glTF2
//! Magic number for GLB files //! Magic number for GLB files
#define AI_GLB_MAGIC_NUMBER "glTF" #define AI_GLB_MAGIC_NUMBER "glTF"
#include <assimp/pbrmaterial.h>
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
#ifdef ASSIMP_API #ifdef ASSIMP_API
#include "./../include/assimp/Compiler/pushpack1.h" #include "./../include/assimp/Compiler/pushpack1.h"

View File

@ -669,7 +669,7 @@ inline Image::Image()
} }
inline void Image::Read(Value& obj, Asset& /*r*/) inline void Image::Read(Value& obj, Asset& r)
{ {
if (!mDataLength) { if (!mDataLength) {
if (Value* uri = FindString(obj, "uri")) { if (Value* uri = FindString(obj, "uri")) {
@ -686,6 +686,19 @@ inline void Image::Read(Value& obj, Asset& /*r*/)
this->uri = uristr; this->uri = uristr;
} }
} }
else if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
Ref<Buffer> buffer = this->bufferView->buffer;
this->mDataLength = this->bufferView->byteLength;
// maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
this->mData = new uint8_t [this->mDataLength];
memcpy(this->mData, buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
if (Value* mtype = FindString(obj, "mimeType")) {
this->mimeType = mtype->GetString();
}
}
} }
} }

View File

@ -316,12 +316,10 @@ 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) {
std::string texId = mAsset->FindUniqueID("", "texture"); std::string texId = mAsset->FindUniqueID("", "texture");

View File

@ -948,24 +948,24 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note. size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
if(primitives[0].indices->count != size_coordindex) if(primitives[0].indices->count != size_coordindex)
throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) + throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + to_string(size_coordindex) +
") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ")."); ") not equal to uncompressed (" + to_string(primitives[0].indices->count) + ").");
size_coordindex *= sizeof(IndicesType); size_coordindex *= sizeof(IndicesType);
// Coordinates // Coordinates
size_t size_coord = ifs.GetNCoord();// See float attributes note. size_t size_coord = ifs.GetNCoord();// See float attributes note.
if(primitives[0].attributes.position[0]->count != size_coord) if(primitives[0].attributes.position[0]->count != size_coord)
throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) + throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + to_string(size_coord) +
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ")."); ") not equal to uncompressed (" + to_string(primitives[0].attributes.position[0]->count) + ").");
size_coord *= 3 * sizeof(float); size_coord *= 3 * sizeof(float);
// Normals // Normals
size_t size_normal = ifs.GetNNormal();// See float attributes note. size_t size_normal = ifs.GetNNormal();// See float attributes note.
if(primitives[0].attributes.normal[0]->count != size_normal) if(primitives[0].attributes.normal[0]->count != size_normal)
throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) + throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + to_string(size_normal) +
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ")."); ") not equal to uncompressed (" + to_string(primitives[0].attributes.normal[0]->count) + ").");
size_normal *= 3 * sizeof(float); size_normal *= 3 * sizeof(float);
// Additional attributes. // Additional attributes.
@ -989,8 +989,8 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
if(idx_texcoord < primitives[0].attributes.texcoord.size()) if(idx_texcoord < primitives[0].attributes.texcoord.size())
{ {
if(primitives[0].attributes.texcoord[idx]->count != tval) if(primitives[0].attributes.texcoord[idx]->count != tval)
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + std::to_string(tval) + throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + to_string(tval) +
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.texcoord[idx]->count) + ")."); ") not equal to uncompressed (" + to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
idx_texcoord++; idx_texcoord++;
} }

View File

@ -194,9 +194,16 @@ void glTFImporter::ImportMaterials(glTF::Asset& r)
aimat->AddProperty(&str, AI_MATKEY_NAME); aimat->AddProperty(&str, AI_MATKEY_NAME);
} }
SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT );
SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE ); SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE );
SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); SetMaterialColorProperty(embeddedTexIdxs, r, mat.emission, aimat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
if (mat.transparent && (mat.transparency != 1.0f)) {
aimat->AddProperty(&mat.transparency, 1, AI_MATKEY_OPACITY);
}
if (mat.shininess > 0.f) { if (mat.shininess > 0.f) {
aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS); aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);

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

Some files were not shown because too many files have changed in this diff Show More